A game about forced loneliness, made by TACStudios
1using System.Linq;
2using UnityEngine;
3using UnityEditor.Graphing;
4using UnityEditor.ShaderGraph.Drawing.Controls;
5using UnityEditor.ShaderGraph.Internal;
6
7namespace UnityEditor.ShaderGraph
8{
9 enum TextureType
10 {
11 Default,
12 Normal
13 };
14
15 [FormerName("UnityEditor.ShaderGraph.Texture2DNode")]
16 [Title("Input", "Texture", "Sample Texture 2D")]
17 class SampleTexture2DNode : AbstractMaterialNode, IGeneratesBodyCode, IMayRequireMeshUV
18 {
19 public const int OutputSlotRGBAId = 0;
20 public const int OutputSlotRId = 4;
21 public const int OutputSlotGId = 5;
22 public const int OutputSlotBId = 6;
23 public const int OutputSlotAId = 7;
24 public const int TextureInputId = 1;
25 public const int UVInput = 2;
26 public const int SamplerInput = 3;
27 public const int MipBiasInput = 8;
28 public const int LodInput = 9;
29 public const int DdxInput = 10;
30 public const int DdyInput = 11;
31
32 const string kTextureInputName = "Texture";
33 const string kUVInputName = "UV";
34 const string kSamplerInputName = "Sampler";
35
36 RGBANodeOutput m_RGBAPins = RGBANodeOutput.NewDefault();
37 Mip2DSamplingInputs m_Mip2DSamplingInputs = Mip2DSamplingInputs.NewDefault();
38
39 public override bool hasPreview { get { return true; } }
40
41 public SampleTexture2DNode()
42 {
43 name = "Sample Texture 2D";
44 synonyms = new string[] { "tex2d" };
45 UpdateNodeAfterDeserialization();
46 }
47
48 [SerializeField]
49 private TextureType m_TextureType = TextureType.Default;
50
51 [EnumControl("Type")]
52 public TextureType textureType
53 {
54 get { return m_TextureType; }
55 set
56 {
57 if (m_TextureType == value)
58 return;
59
60 m_TextureType = value;
61 Dirty(ModificationScope.Graph);
62
63 ValidateNode();
64 }
65 }
66
67 [SerializeField]
68 private NormalMapSpace m_NormalMapSpace = NormalMapSpace.Tangent;
69
70 [EnumControl("Space")]
71 public NormalMapSpace normalMapSpace
72 {
73 get { return m_NormalMapSpace; }
74 set
75 {
76 if (m_NormalMapSpace == value)
77 return;
78
79 m_NormalMapSpace = value;
80 Dirty(ModificationScope.Graph);
81 }
82 }
83
84 [SerializeField]
85 private bool m_EnableGlobalMipBias = true;
86 internal bool enableGlobalMipBias
87 {
88 set { m_EnableGlobalMipBias = value; }
89 get { return m_EnableGlobalMipBias; }
90 }
91
92 [SerializeField]
93 private Texture2DMipSamplingMode m_MipSamplingMode = Texture2DMipSamplingMode.Standard;
94 internal Texture2DMipSamplingMode mipSamplingMode
95 {
96 set { m_MipSamplingMode = value; UpdateMipSamplingModeInputs(); }
97 get { return m_MipSamplingMode; }
98 }
99
100 private void UpdateMipSamplingModeInputs()
101 {
102 var capabilities = ShaderStageCapability.Fragment;
103 if (m_MipSamplingMode == Texture2DMipSamplingMode.LOD || m_MipSamplingMode == Texture2DMipSamplingMode.Gradient)
104 capabilities |= ShaderStageCapability.Vertex;
105
106 m_RGBAPins.SetCapabilities(capabilities);
107
108 m_Mip2DSamplingInputs = MipSamplingModesUtils.CreateMip2DSamplingInputs(
109 this, m_MipSamplingMode, m_Mip2DSamplingInputs, MipBiasInput, LodInput, DdxInput, DdyInput);
110
111 }
112
113 public sealed override void UpdateNodeAfterDeserialization()
114 {
115 m_RGBAPins.CreateNodes(this, ShaderStageCapability.None, OutputSlotRGBAId, OutputSlotRId, OutputSlotGId, OutputSlotBId, OutputSlotAId);
116 AddSlot(new Texture2DInputMaterialSlot(TextureInputId, kTextureInputName, kTextureInputName));
117 AddSlot(new UVMaterialSlot(UVInput, kUVInputName, kUVInputName, UVChannel.UV0));
118 AddSlot(new SamplerStateMaterialSlot(SamplerInput, kSamplerInputName, kSamplerInputName, SlotType.Input));
119 UpdateMipSamplingModeInputs();
120 RemoveSlotsNameNotMatching(new[] { OutputSlotRGBAId, OutputSlotRId, OutputSlotGId, OutputSlotBId, OutputSlotAId, TextureInputId, UVInput, SamplerInput, MipBiasInput, LodInput, DdxInput, DdyInput });
121 }
122
123 public override void Setup()
124 {
125 base.Setup();
126 var textureSlot = FindInputSlot<Texture2DInputMaterialSlot>(TextureInputId);
127 textureSlot.defaultType = (textureType == TextureType.Normal ? Texture2DShaderProperty.DefaultType.NormalMap : Texture2DShaderProperty.DefaultType.White);
128 }
129
130 // Node generations
131 public virtual void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
132 {
133 var uvName = GetSlotValue(UVInput, generationMode);
134
135 //Sampler input slot
136 var samplerSlot = FindInputSlot<MaterialSlot>(SamplerInput);
137 var edgesSampler = owner.GetEdges(samplerSlot.slotReference);
138
139 var id = GetSlotValue(TextureInputId, generationMode);
140 var result = string.Format("$precision4 {0} = {1}({2}.tex, {3}.samplerstate, {2}.GetTransformedUV({4}) {5});"
141 , GetVariableNameForSlot(OutputSlotRGBAId)
142 , MipSamplingModesUtils.Get2DTextureSamplingMacro(m_MipSamplingMode, usePlatformMacros: !m_EnableGlobalMipBias, isArray: false)
143 , id
144 , edgesSampler.Any() ? GetSlotValue(SamplerInput, generationMode) : id
145 , uvName
146 , MipSamplingModesUtils.GetSamplerMipArgs(this, m_MipSamplingMode, m_Mip2DSamplingInputs, generationMode));
147
148 sb.AppendLine(result);
149
150 if (textureType == TextureType.Normal)
151 {
152 if (normalMapSpace == NormalMapSpace.Tangent)
153 {
154 sb.AppendLine(string.Format("{0}.rgb = UnpackNormal({0});", GetVariableNameForSlot(OutputSlotRGBAId)));
155 }
156 else
157 {
158 sb.AppendLine(string.Format("{0}.rgb = UnpackNormalRGB({0});", GetVariableNameForSlot(OutputSlotRGBAId)));
159 }
160 }
161
162 sb.AppendLine(string.Format("$precision {0} = {1}.r;", GetVariableNameForSlot(OutputSlotRId), GetVariableNameForSlot(OutputSlotRGBAId)));
163
164
165 sb.AppendLine(string.Format("$precision {0} = {1}.g;", GetVariableNameForSlot(OutputSlotGId), GetVariableNameForSlot(OutputSlotRGBAId)));
166 sb.AppendLine(string.Format("$precision {0} = {1}.b;", GetVariableNameForSlot(OutputSlotBId), GetVariableNameForSlot(OutputSlotRGBAId)));
167 sb.AppendLine(string.Format("$precision {0} = {1}.a;", GetVariableNameForSlot(OutputSlotAId), GetVariableNameForSlot(OutputSlotRGBAId)));
168 }
169
170 public bool RequiresMeshUV(UVChannel channel, ShaderStageCapability stageCapability)
171 {
172 using (var tempSlots = PooledList<MaterialSlot>.Get())
173 {
174 GetInputSlots(tempSlots);
175 var result = false;
176 foreach (var slot in tempSlots)
177 {
178 if (slot.RequiresMeshUV(channel))
179 {
180 result = true;
181 break;
182 }
183 }
184
185 tempSlots.Clear();
186 return result;
187 }
188 }
189 }
190}