using System.Collections.Generic; using System.Linq; using System.Text; using UnityEditor.ShaderGraph.Internal; namespace UnityEditor.ShaderGraph { class PropertyCollector { public struct TextureInfo { public string name; public int textureId; public bool modifiable; } public readonly List properties = new List(); public void AddShaderProperty(AbstractShaderProperty chunk) { if (properties.Any(x => x.referenceName == chunk.referenceName)) return; properties.Add(chunk); } public void GetPropertiesDeclaration(ShaderStringBuilder builder, GenerationMode mode, ConcretePrecision inheritedPrecision) { foreach (var prop in properties) { prop.ValidateConcretePrecision(inheritedPrecision); } var batchAll = mode == GenerationMode.Preview; builder.AppendLine("CBUFFER_START(UnityPerMaterial)"); int instancedCount = 0; foreach (var prop in properties.Where(n => batchAll || (n.generatePropertyBlock && n.isBatchable))) { if (!prop.gpuInstanced) builder.AppendLine(prop.GetPropertyDeclarationString()); else instancedCount++; } if (instancedCount > 0) { builder.AppendLine("#ifndef UNITY_DOTS_INSTANCING_ENABLED"); foreach (var prop in properties.Where(n => batchAll || (n.generatePropertyBlock && n.isBatchable))) { if (prop.gpuInstanced) builder.AppendLine(prop.GetPropertyDeclarationString()); } builder.AppendLine("#endif"); } builder.AppendLine("CBUFFER_END"); if (batchAll) return; foreach (var prop in properties.Where(n => !n.isBatchable || !n.generatePropertyBlock)) { builder.AppendLine(prop.GetPropertyDeclarationString()); } } public int GetDotsInstancingPropertiesCount(GenerationMode mode) { var batchAll = mode == GenerationMode.Preview; return properties.Where(n => (batchAll || (n.generatePropertyBlock && n.isBatchable)) && n.gpuInstanced).Count(); } public string GetDotsInstancingPropertiesDeclaration(GenerationMode mode) { var builder = new ShaderStringBuilder(); var batchAll = mode == GenerationMode.Preview; int instancedCount = GetDotsInstancingPropertiesCount(mode); if (instancedCount > 0) { builder.AppendLine("#if defined(UNITY_DOTS_INSTANCING_ENABLED)"); builder.AppendLine("#define SHADER_GRAPH_GENERATED"); builder.Append("#define DOTS_CUSTOM_ADDITIONAL_MATERIAL_VARS\t"); int count = 0; foreach (var prop in properties.Where(n => batchAll || (n.generatePropertyBlock && n.isBatchable))) { if (prop.gpuInstanced) { string varName = $"{prop.referenceName}_Array"; string sType = prop.concreteShaderValueType.ToShaderString(prop.concretePrecision); builder.Append("UNITY_DEFINE_INSTANCED_PROP({0}, {1})", sType, varName); if (count < instancedCount - 1) builder.Append("\\"); builder.AppendLine(""); count++; } } foreach (var prop in properties.Where(n => batchAll || (n.generatePropertyBlock && n.isBatchable))) { if (prop.gpuInstanced) { string varName = $"{prop.referenceName}_Array"; builder.AppendLine("#define {0} UNITY_ACCESS_INSTANCED_PROP(unity_Builtins0, {1})", prop.referenceName, varName); } } } builder.AppendLine("#endif"); return builder.ToString(); } public List GetConfiguredTexutres() { var result = new List(); foreach (var prop in properties.OfType()) { if (prop.referenceName != null) { var textureInfo = new TextureInfo { name = prop.referenceName, textureId = prop.value.texture != null ? prop.value.texture.GetInstanceID() : 0, modifiable = prop.modifiable }; result.Add(textureInfo); } } foreach (var prop in properties.OfType()) { if (prop.referenceName != null) { var textureInfo = new TextureInfo { name = prop.referenceName, textureId = prop.value.textureArray != null ? prop.value.textureArray.GetInstanceID() : 0, modifiable = prop.modifiable }; result.Add(textureInfo); } } foreach (var prop in properties.OfType()) { if (prop.referenceName != null) { var textureInfo = new TextureInfo { name = prop.referenceName, textureId = prop.value.texture != null ? prop.value.texture.GetInstanceID() : 0, modifiable = prop.modifiable }; result.Add(textureInfo); } } foreach (var prop in properties.OfType()) { if (prop.referenceName != null) { var textureInfo = new TextureInfo { name = prop.referenceName, textureId = prop.value.cubemap != null ? prop.value.cubemap.GetInstanceID() : 0, modifiable = prop.modifiable }; result.Add(textureInfo); } } return result; } } }