From 5e50d75eb9e4cebd98bd84d3b66db9c17e85ed51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Sat, 22 Mar 2025 23:40:43 +0100 Subject: [PATCH] Handle EngineBuffers, Preview Names and variable editor types for materials --- .../src/Assets/Editors/MaterialEditor.bf | 197 ++++++++-- .../src/Assets/Exporters/ShaderExporter.bf | 51 +-- GlitchyEditor/src/Assets/Importers/Config.bf | 2 +- .../Processors/ShaderCodePreprocessor.bf | 331 +++++++++++++++++ .../src/Assets/Processors/ShaderCompiler.bf | 95 ++++- .../src/Assets/Processors/ShaderProcessor.bf | 344 ++---------------- .../src/EditWindows/InspectorWindow.bf | 6 +- .../src/Content/Loaders/ShaderLoader.bf | 51 +-- .../src/Renderer/BufferCollection.bf | 18 +- GlitchyEngine/src/Renderer/BufferVariable.bf | 8 +- GlitchyEngine/src/Renderer/ConstantBuffer.bf | 14 +- GlitchyEngine/src/Renderer/Material.bf | 6 +- .../src/Renderer/OverridingConstantBuffer.bf | 4 +- 13 files changed, 696 insertions(+), 431 deletions(-) create mode 100644 GlitchyEditor/src/Assets/Processors/ShaderCodePreprocessor.bf diff --git a/GlitchyEditor/src/Assets/Editors/MaterialEditor.bf b/GlitchyEditor/src/Assets/Editors/MaterialEditor.bf index 1bb952e..9da249c 100644 --- a/GlitchyEditor/src/Assets/Editors/MaterialEditor.bf +++ b/GlitchyEditor/src/Assets/Editors/MaterialEditor.bf @@ -9,12 +9,14 @@ namespace GlitchyEditor.Assets.Editors; class MaterialEditor { - public static void ShowEditor(AssetFile assetFile) + public static bool ShowEditor(AssetFile assetFile) { + bool isDirty = false; + let material = assetFile.LoadedAsset as Material; if (material == null) - return; + return isDirty; ImGui.PropertyTableStartNewProperty("Base Material"); @@ -30,8 +32,15 @@ class MaterialEditor ImGui.PropertyTableStartNewRow(); if (ImGui.CollapsingHeader("Parameters", .DefaultOpen | .AllowOverlap | .Framed | .SpanFullWidth | .SpanAllColumns)) { + String prettyVariableName = scope .(); for (let (variableName, bufferVariable) in material.Variables) { + // Don't show engine buffer variables + if (!bufferVariable.ConstantBuffer.EngineBufferName.IsEmpty) + { + continue; + } + ImGui.PushID(variableName); ImGui.PropertyTableStartNewRow(); @@ -47,47 +56,90 @@ class MaterialEditor ImGui.SameLine(); - StringView displayName = variableName; + StringView displayName = bufferVariable.PreviewName; + + if (displayName.IsEmpty) + { + ToPrettyName(variableName, prettyVariableName); + displayName = prettyVariableName; + } ImGui.PropertyTableName(displayName); // TODO: Somehow pass display name and type from imported shader to here! - switch (bufferVariable.ElementType) + bool handled = false; + + switch (bufferVariable.EditorTypeName) { - case .Float: - // TODO: min and max values specified in shader - // TODO: support drag and enter number (specified in shader) - - //for (int r < bufferVariable.Rows) - if (bufferVariable.Rows == 1) + case "Color", "ColorHDR": + if (bufferVariable.ElementType != .Float || bufferVariable.Rows != 1 || + bufferVariable.Columns < 3) { - switch (bufferVariable.Columns) + break; + } + + ImGui.ColorEditFlags flags = .None; + + if (_ == "ColorHDR") + { + flags |= .HDR | .Float; + } + + if (bufferVariable.Columns == 3) + { + material.GetVariable(bufferVariable.Name, var value); + if (ImGui.ColorEdit3("", ref *(float[3]*)&value, flags)) + material.SetVariable(bufferVariable.Name, value); + } + else if (bufferVariable.Columns == 4) + { + material.GetVariable(bufferVariable.Name, var value); + if (ImGui.ColorEdit4("", ref *(float[4]*)&value, flags)) + material.SetVariable(bufferVariable.Name, value); + } + + handled = true; + } + + if (!handled) + { + switch (bufferVariable.ElementType) + { + case .Float: + // TODO: min and max values specified in shader + // TODO: support drag and enter number (specified in shader) + + //for (int r < bufferVariable.Rows) + if (bufferVariable.Rows == 1) { - case 1: - material.GetVariable(bufferVariable.Name, var value); - - //float[1] minV = hasMin ? min.Get() : .(float.MinValue); - //float[1] maxV = hasMax ? max.Get() : .(float.MaxValue); + switch (bufferVariable.Columns) + { + case 1: + material.GetVariable(bufferVariable.Name, var value); + + //float[1] minV = hasMin ? min.Get() : .(float.MinValue); + //float[1] maxV = hasMax ? max.Get() : .(float.MaxValue); - if (ImGui.VectorEditor<1>("", ref *(float[1]*)&value, .(), 0.1f /*, minV, maxV*/)) - material.SetVariable(bufferVariable.Name, value); - case 2: - material.GetVariable(bufferVariable.Name, var value); - if (ImGui.Float2Editor("", ref value, .Zero, 0.1f, 100.0f)) - material.SetVariable(bufferVariable.Name, value); - case 3: - material.GetVariable(bufferVariable.Name, var value); - if (ImGui.Float3Editor("", ref value, .Zero, 0.1f, 100.0f)) - material.SetVariable(bufferVariable.Name, value); - case 4: - material.GetVariable(bufferVariable.Name, var value); - if (ImGui.Float4Editor("", ref value, .Zero, 0.1f, 100.0f)) - material.SetVariable(bufferVariable.Name, value); + if (ImGui.VectorEditor<1>("", ref *(float[1]*)&value, .(), 0.1f /*, minV, maxV*/)) + material.SetVariable(bufferVariable.Name, value); + case 2: + material.GetVariable(bufferVariable.Name, var value); + if (ImGui.Float2Editor("", ref value, .Zero, 0.1f, 100.0f)) + material.SetVariable(bufferVariable.Name, value); + case 3: + material.GetVariable(bufferVariable.Name, var value); + if (ImGui.Float3Editor("", ref value, .Zero, 0.1f, 100.0f)) + material.SetVariable(bufferVariable.Name, value); + case 4: + material.GetVariable(bufferVariable.Name, var value); + if (ImGui.Float4Editor("", ref value, .Zero, 0.1f, 100.0f)) + material.SetVariable(bufferVariable.Name, value); + } } + default: + ImGui.TextUnformatted(scope $"Element Type {_} not supported"); } - default: - ImGui.TextUnformatted(scope $"Element Type {_} not supported"); } ImGui.EndDisabled(); @@ -99,6 +151,7 @@ class MaterialEditor ImGui.PropertyTableStartNewRow(); if (ImGui.CollapsingHeader("Textures", .DefaultOpen | .AllowOverlap | .Framed | .SpanFullWidth | .SpanAllColumns)) { + String prettyVariableName = scope .(); for (var (textureName, texture) in ref material.Textures) { ImGui.PushID(textureName); @@ -116,7 +169,17 @@ class MaterialEditor ImGui.SameLine(); - ImGui.PropertyTableName(textureName); + // TODO: Preview Name for textures + StringView displayName = "";//texture.PreviewName; + + if (displayName.IsEmpty) + { + ToPrettyName(textureName, prettyVariableName); + displayName = prettyVariableName; + } + + + ImGui.PropertyTableName(displayName); if (ComponentEditWindow.ShowAssetDropTarget(ref texture.TextureHandle)) { @@ -128,6 +191,8 @@ class MaterialEditor ImGui.PopID(); } } + + return isDirty; } private static bool DrawLockButton(bool isLocked) @@ -166,4 +231,70 @@ class MaterialEditor return result; } + + /// + /// Converts a variable name to a pretty name as good as reasonably possible. + /// + /// The name of a variable to prettify. + /// The pretty string. + public static void ToPrettyName(StringView uglyName, String outPrettyName) + { + outPrettyName.PrepareBuffer(uglyName.Length); + outPrettyName.Clear(); + + bool wasUpper = false; + bool inWord = false; + bool inNumber = false; + + for (char8 c in uglyName) + { + if (c.IsLetter) + { + if (inNumber) + { + outPrettyName.Append(' '); + inNumber = false; + } + + bool newWord = !inWord; + + if (c.IsUpper && !wasUpper) + { + newWord = true; + wasUpper = true; + + if (inWord) + { + outPrettyName.Append(' '); + } + } + else if (c.IsLower) + { + wasUpper = false; + } + + outPrettyName.Append(newWord ? c.ToUpper : c.ToLower); + + inWord = true; + } + else if (c.IsDigit) + { + if (inWord) + { + outPrettyName.Append(' '); + inWord = false; + inNumber = true; + } + + outPrettyName.Append(c); + } + else if (inWord || inNumber) + { + outPrettyName.Append(' '); + inWord = false; + inNumber = false; + wasUpper = false; + } + } + } } \ No newline at end of file diff --git a/GlitchyEditor/src/Assets/Exporters/ShaderExporter.bf b/GlitchyEditor/src/Assets/Exporters/ShaderExporter.bf index 878023f..6899d48 100644 --- a/GlitchyEditor/src/Assets/Exporters/ShaderExporter.bf +++ b/GlitchyEditor/src/Assets/Exporters/ShaderExporter.bf @@ -23,8 +23,8 @@ class ShaderExporter : IAssetExporter File Format: Vertex Shader Blob Length (uint64 / 8 bytes) (0 if null) - Vertex Shader Data... Pixel Shader Blob Length (uint64 / 8 bytes) (0 if null) + Vertex Shader Data... Pixel Shader Data... Texture Count (uint16) Textures @@ -57,6 +57,11 @@ class ShaderExporter : IAssetExporter ArraySize (uint64) Name Length (uint16) Name Data... + Preview Name Length (uint16) + Preview Name Data... + Type Editor Name Length (uint16) + Type Editor Name Data... + # TODO: Min and Max } RawData... } @@ -92,11 +97,7 @@ class ShaderExporter : IAssetExporter Try!(stream.Write((uint8)textureEntry.TextureDimension)); Try!(stream.Write((int32)textureEntry.VertexShaderBindPoint)); Try!(stream.Write((int32)textureEntry.PixelShaderBindPoint)); - - Log.EngineLogger.Assert(textureName.Length < int16.MaxValue); - - Try!(stream.Write((int16)textureName.Length)); - Try!(stream.Write(textureName)); + WriteSizedString(stream, textureName); } return .Ok; @@ -116,19 +117,10 @@ class ShaderExporter : IAssetExporter Try!(stream.Write((int32)bufferEntry.VertexShaderBindPoint)); Try!(stream.Write((int32)bufferEntry.PixelShaderBindPoint)); + + WriteSizedString(stream, bufferName); - Log.EngineLogger.Assert(bufferName.Length < int16.MaxValue); - - Try!(stream.Write((uint16)bufferName.Length)); - Try!(stream.Write(bufferName)); - - int engineBufferNameLength = bufferEntry.ConstantBuffer.EngineBufferName.Length; - Log.EngineLogger.Assert(engineBufferNameLength < int16.MaxValue); - - Try!(stream.Write((uint16)engineBufferNameLength)); - - if (engineBufferNameLength > 0) - Try!(stream.Write(bufferEntry.ConstantBuffer.EngineBufferName)); + WriteSizedString(stream, bufferEntry.ConstantBuffer.EngineBufferName); Log.EngineLogger.Assert(buffer.Variables.Count < int16.MaxValue); @@ -148,10 +140,9 @@ class ShaderExporter : IAssetExporter Try!(stream.Write((uint8)variable.Columns)); Try!(stream.Write((uint64)variable.ArraySize)); - Log.EngineLogger.Assert(variableName.Length < int16.MaxValue); - - Try!(stream.Write((uint16)variableName.Length)); - Try!(stream.Write(variableName)); + WriteSizedString(stream, variableName); + WriteSizedString(stream, variable.PreviewName); + WriteSizedString(stream, variable.EditorType); } Try!(stream.Write(Span(buffer.RawData, 0, buffer.Size))); @@ -159,4 +150,20 @@ class ShaderExporter : IAssetExporter return .Ok; } + + private static Result WriteSizedString(Stream stream, StringView string) + where Tint : IInteger + where int : operator explicit Tint + where Tint : operator explicit int + where Tint : struct + { + Log.EngineLogger.Assert(string.Length < (int)typeof(Tint).MaxValue); + + Try!(stream.Write((Tint)string.Length)); + + if (string.Length > 0) + Try!(stream.WriteStrUnsized(string)); + + return .Ok; + } } diff --git a/GlitchyEditor/src/Assets/Importers/Config.bf b/GlitchyEditor/src/Assets/Importers/Config.bf index 5113c0a..ee3a1f2 100644 --- a/GlitchyEditor/src/Assets/Importers/Config.bf +++ b/GlitchyEditor/src/Assets/Importers/Config.bf @@ -8,7 +8,7 @@ namespace GlitchyEditor.Assets.Importers; abstract class Config { [BonIgnore] - protected bool _changed = true; + protected bool _changed = false; public bool Changed => _changed; diff --git a/GlitchyEditor/src/Assets/Processors/ShaderCodePreprocessor.bf b/GlitchyEditor/src/Assets/Processors/ShaderCodePreprocessor.bf new file mode 100644 index 0000000..54b0c1d --- /dev/null +++ b/GlitchyEditor/src/Assets/Processors/ShaderCodePreprocessor.bf @@ -0,0 +1,331 @@ +using System; +using System.Collections; +using GlitchyEngine; +using GlitchyEngine.Math; + +namespace GlitchyEditor.Assets.Processors; + +static class ShaderCodePreprocessor +{ + public static Result ProcessFileContent(String fileContent, String outVsName, String outPsName, + Dictionary outVarDescs, + List outBufferNames, Dictionary outEngineBuffers) + { + Debug.Profiler.ProfileResourceFunction!(); + + Dictionary arguments = scope .(); + + int index = 0; + + while (true) + { + if ((int Start, int End) value = GetNextPreprocessor(fileContent, index, let name, arguments..Clear())) + { + index = value.End; + + switch(name) + { + case "Effect": + for (let (argName, argValue) in arguments) + { + switch(argName) + { + case "VS", "VertexShader": + outVsName.Append(argValue); + case "PS", "PixelShader": + outPsName.Append(argValue); + default: + Log.EngineLogger.Error($"Unknown parameter name \"{name}\"."); + return .Err; + } + } + case "EditorVariable": + Try!(ProcessEditorVariables(arguments, outVarDescs)); + case "EngineBuffer": + Try!(ProcessEngineBuffer(arguments, outBufferNames, outEngineBuffers)); + default: + continue; + } + + CommentLine(fileContent, value.Start); + } + else + { + break; + } + } + + return .Ok; + } + + private static void CommentLine(StringView code, int commentPosition) + { + code[commentPosition] = '/'; + code[commentPosition + 1] = '/'; + } + + private static Result<(int Start, int End)> GetNextPreprocessor(StringView code, int startindex, out StringView name, Dictionary arguments) + { + var startindex; + + name = .(); + + int startOfLine = -1; + int startOfPragma = -1; + int endOfLine = startindex; + do + { + repeat + { + startindex = endOfLine; + + startOfPragma = code.IndexOf("#pragma", startindex); + + if (startOfPragma == -1) + return .Err; + + endOfLine = code.IndexOf('\n', startOfPragma); + + startOfLine = code[...startOfPragma].LastIndexOf('\n'); + + // If the line is commented out, look for the next + } while (startOfLine != -1 && code[startOfLine...startOfPragma].Contains("//")); + + StringView line = (endOfLine != -1) ? code.Substring(startOfPragma, endOfLine - startOfPragma) : code.Substring(startOfPragma); + + // cut off the #pragma + line = line.Substring(7); + + int lBracketIndex = line.IndexOf('['); + + if (lBracketIndex == -1) + { + name = line..Trim(); + break; + } + + name = line.Substring(0, lBracketIndex); + name.Trim(); + + int rBracketIndex = line.IndexOf(']'); + + if (rBracketIndex == -1) + { + Log.EngineLogger.Error($"Pragma is missing closing Bracket (\"{line}\")"); + rBracketIndex = line.Length; + } + + StringView argumentText = line.Substring(lBracketIndex + 1, rBracketIndex - lBracketIndex - 1); + + for (StringView argument in argumentText.Split(';')) + { + int equalsIndex = argument.IndexOf('='); + + StringView argumentName = .(); + StringView argumentValue = .(); + + if (equalsIndex == -1) + { + argumentName = argument; + argumentName.Trim(); + } + else + { + argumentName = argument.Substring(0, equalsIndex); + argumentName.Trim(); + + argumentValue = argument.Substring(equalsIndex + 1); + argumentValue.Trim(); + } + + if (arguments.ContainsKey(argumentName)) + { + Log.EngineLogger.Error($"Arguments \"{argumentName}\" already exists."); + continue; + } + + arguments.Add(argumentName, argumentValue); + } + } + + return .Ok((startOfPragma, endOfLine)); + } + + private static Result ProcessEngineBuffer(Dictionary arguments, + List outBufferNames, Dictionary outEngineBuffers) + { + String nameInEngine = null; + String nameInShader = null; + + defer + { + if (@return case .Err) + { + delete nameInEngine; + delete nameInShader; + } + } + + for (var (argName, argValue) in arguments) + { + if (argValue.StartsWith('"') && argValue.EndsWith('"')) + { + argValue = argValue[1...^2]; + } + switch (argName) + { + case "Name": + nameInShader = new String(argValue); + case "Binding": + nameInEngine = new String(argValue); + default: + Log.EngineLogger.Error($"Unknown parameter for EngineBuffer: \"{argName}\"."); + return .Err; + } + } + + if (String.IsNullOrWhiteSpace(nameInEngine) || String.IsNullOrWhiteSpace(nameInShader)) + { + Log.EngineLogger.Error($"Name and Binding need to be defined."); + return .Err; + } + + outBufferNames.Add(nameInShader); + outBufferNames.Add(nameInEngine); + outEngineBuffers.Add(nameInShader, nameInEngine); + + return .Ok; + } + + private static Result ProcessEditorVariables(Dictionary arguments, Dictionary outVarDescs) + { + ShaderVariable variable = new .(); + + defer + { + if (@return case .Err) + delete variable; + } + + for (var (name, value) in arguments) + { + if (value.StartsWith('"') && value.EndsWith('"')) + { + value = value[1...^2]; + } + + switch(name) + { + case "Name": + variable.Name = value; + case "Preview": + variable.PreviewName = value; + case "Type": + variable.EditorType = value; + case "Min": + variable.MinValue = Try!(ParseVariableValue(value)); + case "Max": + variable.MaxValue = Try!(ParseVariableValue(value)); + default: + Variant paramValue = Variant.Create(new String(value), true); + variable.AddParameter(name, paramValue); + } + } + + if (variable.Name.IsWhiteSpace) + { + Log.EngineLogger.Error("Failed to process shader: Missing argument \"Name\" int variable description."); + return .Err; + } + + outVarDescs.Add(variable.Name, variable); + + return .Ok; + } + + private static Result ParseVariableValue(StringView valueString) + { + // TODO: Simply always use double? + + if (valueString[0].IsDigit || valueString[0] == '-') + { + var valueString; + + if (valueString.EndsWith('f')) + valueString.Length--; + + float value = Try!(float.Parse(valueString)); + + return Variant.Create(value); + } + else if (valueString.StartsWith("float")) + { + int index = 5; + + int numComponents = valueString[index++] - '0'; + + while (valueString[index] != '(') + { + if (!valueString[index].IsWhiteSpace) + { + Log.EngineLogger.Error("Failed to process shader: Expected '('."); + return .Err; + } + + index++; + } + + if (numComponents < 2 || numComponents > 4) + { + Log.EngineLogger.Error($"Failed to process shader: Unsupported component count {numComponents}. Value must be between 2 and 4."); + return .Err; + } + + float[] floats = scope float[numComponents]; + + for (int i < numComponents) + { + while (true) + { + char8 c = valueString[++index]; + + if (c.IsDigit || c == '.' || c == '-') + break; + } + + int start = index; + + while (true) + { + char8 c = valueString[++index]; + + if (!c.IsDigit && c != '.') + break; + } + + int end = index; + + StringView numberView = .(valueString, start, end - start); + + var result = float.Parse(numberView); + + if (result case .Ok(let value)) + { + floats[i] = value; + } + } + + if (numComponents == 2) + return Variant.Create(*(float2*)floats.Ptr); + else if (numComponents == 3) + return Variant.Create(*(float3*)floats.Ptr); + else + return Variant.Create(*(float4*)floats.Ptr); + } + else + { + Log.EngineLogger.Error($"Failed to process shader: Unsupported variable value: \"{valueString}\"."); + return .Err; + } + } +} \ No newline at end of file diff --git a/GlitchyEditor/src/Assets/Processors/ShaderCompiler.bf b/GlitchyEditor/src/Assets/Processors/ShaderCompiler.bf index 03f335a..84a4e54 100644 --- a/GlitchyEditor/src/Assets/Processors/ShaderCompiler.bf +++ b/GlitchyEditor/src/Assets/Processors/ShaderCompiler.bf @@ -109,6 +109,8 @@ class ReflectedTexture class ReflectedConstantBufferVariable { private String _name ~ delete _; + private String _previewName ~ delete _; + private String _editorType ~ delete _; public StringView Name { @@ -116,6 +118,18 @@ class ReflectedConstantBufferVariable set => String.NewOrSet!(_name, value); } + public StringView PreviewName + { + get => _previewName; + set => String.NewOrSet!(_previewName, value); + } + + public StringView EditorType + { + get => _editorType; + set => String.NewOrSet!(_editorType, value); + } + public int Offset; public int SizeInBytes; public bool IsUsed; @@ -125,6 +139,9 @@ class ReflectedConstantBufferVariable public int Columns; public int ArraySize; + + public Variant MinValue; + public Variant MaxValue; } // TODO: Dx11 @@ -146,30 +163,43 @@ class ShaderCompiler CompiledShader shader = new CompiledShader(); - Try!(PlatformCompileShaderFromSource(code, assetIdentifier, entryPoint, compileTarget, defines, shader)); + ShaderCompilationContext context = scope .(); - Try!(PlatformReflectShader(shader)); + Try!(PlatformCompileShaderFromSource(code, assetIdentifier, entryPoint, compileTarget, defines, shader, context)); + + Try!(PlatformReflectShader(shader, context)); return shader; } - protected static extern Result PlatformCompileShaderFromSource(StringView code, AssetIdentifier fileName, StringView entryPoint, StringView compileTarget, Span defines, CompiledShader outShader); + protected static extern Result PlatformCompileShaderFromSource(StringView code, AssetIdentifier fileName, StringView entryPoint, StringView compileTarget, Span defines, CompiledShader outShader, ShaderCompilationContext context); - protected static extern Result PlatformReflectShader(CompiledShader shader); + protected static extern Result PlatformReflectShader(CompiledShader shader, ShaderCompilationContext context); +} + +class ShaderCompilationContext +{ + public append String VsName = String(); + public append String PsName = String(); + + public append Dictionary Variables = .() ~ ClearDictionaryAndDeleteValues!(_); + public append List BufferNames = .() ~ ClearAndDeleteItems!(_); + // Name in Shader -> Name in Engine + public append Dictionary EngineBuffers = .(); } // TODO: Dx11 extension ShaderCompiler { // TODO: This should be a setting per shader, really! - protected const ShaderCompileFlags DefaultCompileFlags = .EnableStrictness | + protected const ShaderCompileFlags DefaultCompileFlags = .EnableStrictness | #if DEBUG .Debug; #else .OptimizationLevel3; #endif - protected static override Result PlatformCompileShaderFromSource(StringView code, AssetIdentifier fileName, StringView entryPoint, StringView compileTarget, Span defines, CompiledShader outShader) + protected static override Result PlatformCompileShaderFromSource(StringView code, AssetIdentifier fileName, StringView entryPoint, StringView compileTarget, Span defines, CompiledShader outShader, ShaderCompilationContext context) { Debug.Profiler.ProfileResourceFunction!(); @@ -192,7 +222,11 @@ extension ShaderCompiler Path.GetDirectoryPath(fileName, directory); - using (let includer = Includer(directory)) + String shaderCode = new:ScopedAlloc! String(code); + + Try!(ShaderCodePreprocessor.ProcessFileContent(shaderCode, context.VsName, context.PsName, context.Variables, context.BufferNames, context.EngineBuffers)); + + using (let includer = PreprocessingIncluder(directory, context)) { var result = D3DCompiler.D3DCompile(code.Ptr, (.)code.Length, fileName.FullIdentifier.ToScopeCStr!(), nativeMacros, &includer, entryPoint.ToScopeCStr!(), compileTarget.ToScopeCStr!(), DefaultCompileFlags /* Pass down compile flags? */, .None, &outShader._shaderBlob, &errorBlob); @@ -210,7 +244,7 @@ extension ShaderCompiler return .Ok; } - protected override static Result PlatformReflectShader(CompiledShader shader) + protected override static Result PlatformReflectShader(CompiledShader shader, ShaderCompilationContext context) { Debug.Profiler.ProfileResourceFunction!(); @@ -253,7 +287,7 @@ extension ShaderCompiler // ConstantBuffer if(bufferDesc.Type == .D3D11_CT_CBUFFER) { - ReflectedConstantBuffer cbuffer = Try!(ReflectConstantBuffer(bindDesc, bufferReflection)); + ReflectedConstantBuffer cbuffer = Try!(ReflectConstantBuffer(bindDesc, bufferReflection, context)); shader.AddConstantBuffer(cbuffer); } case .Texture: @@ -290,7 +324,7 @@ extension ShaderCompiler return .Ok; } - private static Result ReflectConstantBuffer(ShaderInputBindDescription bindDesc, ID3D11ShaderReflectionConstantBuffer* bufferReflection) + private static Result ReflectConstantBuffer(ShaderInputBindDescription bindDesc, ID3D11ShaderReflectionConstantBuffer* bufferReflection, ShaderCompilationContext context) { Debug.Profiler.ProfileResourceFunction!(); @@ -310,17 +344,22 @@ extension ShaderCompiler { ID3D11ShaderReflectionVariable* variableReflection = bufferReflection.GetVariableByIndex(v); - if (ReflectConstantBufferVariable(buffer, variableReflection) case .Err) + if (ReflectConstantBufferVariable(buffer, variableReflection, context) case .Err) { delete buffer; return .Err; } } + if (context.EngineBuffers.TryGetValue(buffer.Name, let engineBufferName)) + { + buffer.EngineBufferName = engineBufferName; + } + return buffer; } - private static Result ReflectConstantBufferVariable(ReflectedConstantBuffer buffer, ID3D11ShaderReflectionVariable* variableReflection) + private static Result ReflectConstantBufferVariable(ReflectedConstantBuffer buffer, ID3D11ShaderReflectionVariable* variableReflection, ShaderCompilationContext context) { Debug.Profiler.ProfileResourceFunction!(); @@ -375,13 +414,23 @@ extension ShaderCompiler Internal.MemCpy(&buffer.RawData[variable.Offset], variableDescription.DefaultValue, variable.SizeInBytes); } + if (context.Variables.TryGetValue(variable.Name, let variableAnnotation)) + { + variable.PreviewName = variableAnnotation.PreviewName; + variable.EditorType = variableAnnotation.EditorType; + + // TODO: We need to somehow validate against our variable type + variable.MinValue = variableAnnotation.MinValue; + variable.MaxValue = variableAnnotation.MaxValue; + } + buffer.AddVariable(variable); return .Ok; } } -struct Includer : ID3DInclude, IDisposable +struct PreprocessingIncluder : ID3DInclude, IDisposable { private VTable _vTable; @@ -389,7 +438,9 @@ struct Includer : ID3DInclude, IDisposable private String _parentFileDirectory; - public this(String parentFileDirectory) + private ShaderCompilationContext _context; + + public this(String parentFileDirectory, ShaderCompilationContext context) { _parentFileDirectory = parentFileDirectory; _loadedFiles = new Dictionary(); @@ -398,6 +449,8 @@ struct Includer : ID3DInclude, IDisposable _vTable.Close = => Close; _vt = &_vTable; + + _context = context; } public void Dispose() @@ -413,7 +466,7 @@ struct Includer : ID3DInclude, IDisposable public static HResult Open(ID3DInclude* self, IncludeType includeType, char8* fileNamePtr, void* parentData, void** data, uint32* bytes) { - Includer* includer = (.)self; + PreprocessingIncluder* includer = (.)self; StringView fileName = StringView(fileNamePtr); @@ -424,7 +477,7 @@ struct Includer : ID3DInclude, IDisposable return .S_OK; } - + String fullPath = scope .(); Path.Combine(fullPath, includer._parentFileDirectory, fileName); @@ -453,6 +506,7 @@ struct Includer : ID3DInclude, IDisposable if (fileStream == null) { + return .E_FILENOTFOUND; } String fileContent = new String(); @@ -469,6 +523,13 @@ struct Includer : ID3DInclude, IDisposable delete fileStream; + String trashbin = scope String(); + + if (ShaderCodePreprocessor.ProcessFileContent(fileContent, trashbin, trashbin, includer._context.Variables, includer._context.BufferNames, includer._context.EngineBuffers) case .Err) + { + return .E_FAIL; + } + *data = (void*)fileContent.Ptr; *bytes = (uint32)fileContent.Length; @@ -477,7 +538,7 @@ struct Includer : ID3DInclude, IDisposable public static HResult Close(ID3DInclude* self, void** data) { - Includer* includer = (.)self; + PreprocessingIncluder* includer = (.)self; for (var v in includer._loadedFiles) { diff --git a/GlitchyEditor/src/Assets/Processors/ShaderProcessor.bf b/GlitchyEditor/src/Assets/Processors/ShaderProcessor.bf index a8c0224..f208772 100644 --- a/GlitchyEditor/src/Assets/Processors/ShaderProcessor.bf +++ b/GlitchyEditor/src/Assets/Processors/ShaderProcessor.bf @@ -69,6 +69,8 @@ class ProcessedShader : ProcessedResource class ShaderVariable { private String _name ~ delete _; + private String _previewName ~ delete _; + private String _editorType ~ delete _; private Dictionary _parameters = new .() ~ { for (var (entryKey, entry) in _) @@ -84,6 +86,21 @@ class ShaderVariable get => _name; set => String.NewOrSet!(_name, value); } + + public StringView PreviewName + { + get => _previewName; + set => String.NewOrSet!(_previewName, value); + } + + public StringView EditorType + { + get => _editorType; + set => String.NewOrSet!(_editorType, value); + } + + public Variant MinValue ~ _.Dispose(); + public Variant MaxValue ~ _.Dispose(); public Dictionary Parameters => _parameters; @@ -134,10 +151,12 @@ class ShaderProcessor : IAssetProcessor } } - String code = new String(importedShader.HlslCode); - defer { delete code; } + String tmpCode = new String(importedShader.HlslCode); - Try!(ProcessFileContent(code, vsName, psName, variables, bufferNames, engineBuffers)); + // TODO: This is terrible. Currently we process too often... (here + each shader stage) + Try!(ShaderCodePreprocessor.ProcessFileContent(tmpCode , vsName, psName, variables, bufferNames, engineBuffers)); + + delete tmpCode; if (String.IsNullOrWhiteSpace(vsName) && String.IsNullOrWhiteSpace(psName)) { @@ -147,28 +166,24 @@ class ShaderProcessor : IAssetProcessor processedShader = new ProcessedShader(new AssetIdentifier(importedShader.AssetIdentifier), config.AssetHandle); - Try!(CompileAndReflect(vsName, psName, importedShader, code, processedShader)); + Try!(CompileAndReflect(vsName, psName, importedShader, importedShader.HlslCode, processedShader)); - Try!(MergeResources(processedShader, variables, engineBuffers)); + Try!(MergeResources(processedShader)); outProcessedResources.Add(processedShader); return .Ok; } - private static Result MergeResources(ProcessedShader processedShader, - Dictionary variables, - Dictionary engineBuffers) + private static Result MergeResources(ProcessedShader processedShader) { - Try!(MergeConstantBuffers(processedShader, variables, engineBuffers)); + Try!(MergeConstantBuffers(processedShader)); Try!(MergeTextures(processedShader)); return .Ok; } - private static Result MergeConstantBuffers(ProcessedShader processedShader, - Dictionary variables, - Dictionary engineBuffers) + private static Result MergeConstantBuffers(ProcessedShader processedShader) { HashSet bufferNames = scope .(); @@ -211,11 +226,6 @@ class ShaderProcessor : IAssetProcessor Log.EngineLogger.Assert(constantBufferEntry.ConstantBuffer != null); Log.EngineLogger.Assert(constantBufferEntry.VertexShaderBindPoint > -1 || constantBufferEntry.PixelShaderBindPoint > -1); - if (engineBuffers.TryGetValue(constantBufferEntry.ConstantBuffer.Name, let engineBufferName)) - { - constantBufferEntry.ConstantBuffer.EngineBufferName = engineBufferName; - } - processedShader.AddConstantBuffer(constantBufferEntry); } @@ -283,304 +293,4 @@ class ShaderProcessor : IAssetProcessor return ShaderCompiler.CompileAndReflectShader(code, importedShader.AssetIdentifier, vsName, "ps_5_0", .()); } - - private static Result ProcessFileContent(String fileContent, String outVsName, String outPsName, - Dictionary outVarDescs, - List outBufferNames, Dictionary outEngineBuffers) - { - Debug.Profiler.ProfileResourceFunction!(); - - Dictionary arguments = scope .(); - - int index = 0; - - while (true) - { - if ((int Start, int End) value = GetNextPreprocessor(fileContent, index, let name, arguments..Clear())) - { - index = value.End; - - switch(name) - { - case "Effect": - for (let (argName, argValue) in arguments) - { - switch(argName) - { - case "VS", "VertexShader": - outVsName.Append(argValue); - case "PS", "PixelShader": - outPsName.Append(argValue); - default: - Log.EngineLogger.Error($"Unknown parameter name \"{name}\"."); - return .Err; - } - } - case "EditorVariable": - Try!(ProcessEditorVariables(arguments, outVarDescs)); - case "EngineBuffer": - Try!(ProcessEngineBuffer(arguments, outBufferNames, outEngineBuffers)); - default: - continue; - } - - CommentLine(fileContent, value.Start); - } - else - { - break; - } - } - - return .Ok; - } - - private static void CommentLine(StringView code, int commentPosition) - { - code[commentPosition] = '/'; - code[commentPosition + 1] = '/'; - } - - private static Result<(int Start, int End)> GetNextPreprocessor(StringView code, int startindex, out StringView name, Dictionary arguments) - { - name = .(); - - int startOfLine; - int endOfLine; - do - { - startOfLine = code.IndexOf("#pragma", startindex); - - if (startOfLine == -1) - return .Err; - - endOfLine = code.IndexOf('\n', startOfLine); - - StringView line = (endOfLine != -1) ? code.Substring(startOfLine, endOfLine - startOfLine) : code.Substring(startOfLine); - - // cut off the #pragma - line = line.Substring(7); - - int lBracketIndex = line.IndexOf('['); - - if (lBracketIndex == -1) - { - name = line..Trim(); - break; - } - - name = line.Substring(0, lBracketIndex); - name.Trim(); - - int rBracketIndex = line.IndexOf(']'); - - if (rBracketIndex == -1) - { - Log.EngineLogger.Error($"Pragma is missing closing Bracket (\"{line}\")"); - rBracketIndex = line.Length; - } - - StringView argumentText = line.Substring(lBracketIndex + 1, rBracketIndex - lBracketIndex - 1); - - for (StringView argument in argumentText.Split(';')) - { - int equalsIndex = argument.IndexOf('='); - - StringView argumentName = .(); - StringView argumentValue = .(); - - if (equalsIndex == -1) - { - argumentName = argument; - argumentName.Trim(); - } - else - { - argumentName = argument.Substring(0, equalsIndex); - argumentName.Trim(); - - argumentValue = argument.Substring(equalsIndex + 1); - argumentValue.Trim(); - } - - if (arguments.ContainsKey(argumentName)) - { - Log.EngineLogger.Error($"Arguments \"{argumentName}\" already exists."); - continue; - } - - arguments.Add(argumentName, argumentValue); - } - } - - return .Ok((startOfLine, endOfLine)); - } - - private static Result ProcessEngineBuffer(Dictionary arguments, - List outBufferNames, Dictionary outEngineBuffers) - { - String nameInEngine = null; - String nameInShader = null; - - for (var (argName, argValue) in arguments) - { - if (argValue.StartsWith('"') && argValue.EndsWith('"')) - { - argValue = argValue[1...^2]; - } - switch (argName) - { - case "Name": - nameInShader = new String(argValue); - case "Binding": - nameInEngine = new String(argValue); - default: - Log.EngineLogger.Error($"Unknown parameter for EngineBuffer: \"{argName}\"."); - delete nameInEngine; - delete nameInShader; - return .Err; - } - } - - if (String.IsNullOrWhiteSpace(nameInEngine) || String.IsNullOrWhiteSpace(nameInShader)) - { - Log.EngineLogger.Error($"Name and Binding need to be defined."); - delete nameInEngine; - delete nameInShader; - return .Err; - } - - outBufferNames.Add(nameInShader); - outBufferNames.Add(nameInEngine); - outEngineBuffers.Add(nameInShader, nameInEngine); - - return .Ok; - } - - private static Result ProcessEditorVariables(Dictionary arguments, Dictionary outVarDescs) - { - ShaderVariable variable = new .(); - - for (var (name, value) in arguments) - { - if (value.StartsWith('"') && value.EndsWith('"')) - { - value = value[1...^2]; - } - - switch(name) - { - case "Name": - variable.Name = value; - case "Min", "Max": - if (Variant paramValue = ParseVariableValue(value)) - variable.AddParameter(name, paramValue); - else - { - delete variable; - return .Err; - } - default: - Variant paramValue = Variant.Create(new String(value), true); - variable.AddParameter(name, paramValue); - } - } - - if (variable.Name.IsWhiteSpace) - { - Log.EngineLogger.Error("Failed to process shader: Missing argument \"Name\" int variable description."); - - delete variable; - - return .Err; - } - - outVarDescs.Add(variable.Name, variable); - - return .Ok; - } - - private static Result ParseVariableValue(StringView valueString) - { - if (valueString[0].IsDigit || valueString[0] == '-') - { - var valueString; - - if (valueString.EndsWith('f')) - valueString.Length--; - - float value = Try!(float.Parse(valueString)); - - return Variant.Create(value); - } - else if (valueString.StartsWith("float")) - { - int index = 5; - - int numComponents = valueString[index++] - '0'; - - while (valueString[index] != '(') - { - if (!valueString[index].IsWhiteSpace) - { - Log.EngineLogger.Error("Failed to process shader: Expected '('."); - return .Err; - } - - index++; - } - - if (numComponents < 2 || numComponents > 4) - { - Log.EngineLogger.Error($"Failed to process shader: Unsupported component count {numComponents}. Value must be between 2 and 4."); - return .Err; - } - - float[] floats = scope float[numComponents]; - - for (int i < numComponents) - { - while (true) - { - char8 c = valueString[++index]; - - if (c.IsDigit || c == '.' || c == '-') - break; - } - - int start = index; - - while (true) - { - char8 c = valueString[++index]; - - if (!c.IsDigit && c != '.') - break; - } - - int end = index; - - StringView numberView = .(valueString, start, end - start); - - var result = float.Parse(numberView); - - if (result case .Ok(let value)) - { - floats[i] = value; - } - } - - if (numComponents == 2) - return Variant.Create(*(float2*)floats.Ptr); - else if (numComponents == 3) - return Variant.Create(*(float3*)floats.Ptr); - else - return Variant.Create(*(float4*)floats.Ptr); - } - else - { - Log.EngineLogger.Error($"Failed to process shader: Unsupported variable value: \"{valueString}\"."); - return .Err; - } - } } diff --git a/GlitchyEditor/src/EditWindows/InspectorWindow.bf b/GlitchyEditor/src/EditWindows/InspectorWindow.bf index 06d2c57..d2039d8 100644 --- a/GlitchyEditor/src/EditWindows/InspectorWindow.bf +++ b/GlitchyEditor/src/EditWindows/InspectorWindow.bf @@ -172,16 +172,14 @@ class InspectorWindow : EditorWindow (assetFile.AssetConfig?.ProcessorConfig?.Changed == true) || (assetFile.AssetConfig?.ExporterConfig?.Changed == true); - if (!hasChanges) - ImGui.BeginDisabled(); + ImGui.BeginDisabled(!hasChanges); if (ImGui.Button("Apply")) { assetFile.SaveAssetConfigIfChanged(); } - if (!hasChanges) - ImGui.EndDisabled(); + ImGui.EndDisabled(); } private static void ShowEntityProperties(UUID entityId, Editor editor, Type componentType = null) diff --git a/GlitchyEngine/src/Content/Loaders/ShaderLoader.bf b/GlitchyEngine/src/Content/Loaders/ShaderLoader.bf index 3922d04..f178415 100644 --- a/GlitchyEngine/src/Content/Loaders/ShaderLoader.bf +++ b/GlitchyEngine/src/Content/Loaders/ShaderLoader.bf @@ -86,6 +86,22 @@ class ShaderLoader : IProcessedAssetLoader return effect; } + private static mixin ReadScopedSizedString(Stream stream) + where Tint : IInteger + where int : operator explicit Tint + where Tint : operator explicit int + where Tint : struct + { + int bufferNameLength = (int)Try!(stream.Read()); + + String string = scope:mixin String(bufferNameLength); + + if (bufferNameLength > 0) + stream.ReadStrSized32(bufferNameLength, string); + + string + } + private static Result LoadBuffer(Stream stream, Effect effect) { int64 bufferSize = Try!(stream.Read()); @@ -93,24 +109,10 @@ class ShaderLoader : IProcessedAssetLoader int32 vertexShaderBindPoint = Try!(stream.Read()); int32 pixelShaderBindPoint = Try!(stream.Read()); - int16 bufferNameLength = Try!(stream.Read()); - String bufferName = scope String(bufferNameLength); - stream.ReadStrSized32(bufferNameLength, bufferName); + String bufferName = ReadScopedSizedString!(stream); + String engineBufferName = ReadScopedSizedString!(stream); - int16 engineBufferNameLength = Try!(stream.Read()); - String engineBufferName = null; - - if (engineBufferNameLength > 0) - { - scope String(engineBufferNameLength); - stream.ReadStrSized32(engineBufferNameLength, engineBufferName); - - // TODO: Engine buffers currently do nothing. The bind points for each engine buffer are hardcoded. - // It only marks the buffer as engine buffer, preventing the variables from becomming accessible. - //effect.[Friend]_engineBuffers.Add() - } - - using (ConstantBuffer buffer = new ConstantBuffer(bufferName, bufferSize)) + using (ConstantBuffer buffer = new ConstantBuffer(bufferName, bufferSize, engineBufferName)) { uint16 variableCount = Try!(stream.Read()); @@ -124,26 +126,25 @@ class ShaderLoader : IProcessedAssetLoader uint8 columns = Try!(stream.Read()); uint64 arraySize = Try!(stream.Read()); - int16 variableNameLength = Try!(stream.Read()); - String variableName = scope String(variableNameLength); - stream.ReadStrSized32(variableNameLength, variableName); + String variableName = ReadScopedSizedString!(stream); + String previewName = ReadScopedSizedString!(stream); + String editorTypeName = ReadScopedSizedString!(stream); - if (engineBufferName == null) - buffer.AddVariable(variableName, variableOffset, sizeInBytes, isUsed, type, rows, columns, arraySize); + buffer.AddVariable(variableName, previewName, editorTypeName, variableOffset, sizeInBytes, isUsed, type, rows, columns, arraySize); } Try!(stream.TryRead(buffer.RawData)); Try!(buffer.Apply()); if (vertexShaderBindPoint != -1) - effect.VertexShader.Buffers.Add(vertexShaderBindPoint, buffer.Name, buffer); + effect.VertexShader.Buffers.Add(vertexShaderBindPoint, buffer.Name, engineBufferName, buffer); if (pixelShaderBindPoint != -1) - effect.PixelShader.Buffers.Add(pixelShaderBindPoint, buffer.Name, buffer); + effect.PixelShader.Buffers.Add(pixelShaderBindPoint, buffer.Name, engineBufferName, buffer); // TODO: Allow binding buffers to different indices? Does this theoretically work with textures? let tempBindPoint = (vertexShaderBindPoint != -1) ? vertexShaderBindPoint : pixelShaderBindPoint; - effect.Buffers.Add(tempBindPoint, buffer.Name, buffer); + effect.Buffers.Add(tempBindPoint, buffer.Name, engineBufferName, buffer); for (var variable in buffer.Variables) { diff --git a/GlitchyEngine/src/Renderer/BufferCollection.bf b/GlitchyEngine/src/Renderer/BufferCollection.bf index 3e2619d..face2c4 100644 --- a/GlitchyEngine/src/Renderer/BufferCollection.bf +++ b/GlitchyEngine/src/Renderer/BufferCollection.bf @@ -4,15 +4,16 @@ using GlitchyEngine.Core; namespace GlitchyEngine.Renderer { - public class BufferCollection : RefCounter, IEnumerable<(String Name, Buffer Buffer)> + public class BufferCollection : RefCounter, IEnumerable<(String Name, String EngineBufferName, Buffer Buffer)> { public static extern int MaxBufferSlotCount { get; } - public typealias BufferEntry = (String Name, Buffer Buffer); + public typealias BufferEntry = (String Name, String EngineBufferName, Buffer Buffer); BufferEntry[] _buffers ~ DeleteBufferEntries!(_); Dictionary _strToBuf ~ delete _; + Dictionary _engineBuffers ~ delete _; [AllowAppend] public this() @@ -22,9 +23,11 @@ namespace GlitchyEngine.Renderer // Todo: append allocate as soon as it's fixed let buffers = new BufferEntry[MaxBufferSlotCount]; let strToBuf = new Dictionary(); + let engineBuffers = new Dictionary(); _buffers = buffers; _strToBuf = strToBuf; + _engineBuffers = engineBuffers; } public ~this() @@ -40,6 +43,7 @@ namespace GlitchyEngine.Renderer for(let entry in entries) { delete entry.Name; + delete entry.EngineBufferName; entry.Buffer?.ReleaseRef(); } @@ -120,13 +124,21 @@ namespace GlitchyEngine.Renderer } } - public void Add(int slot, StringView name, Buffer buffer) + public void Add(int slot, StringView name, StringView engineBufferName, Buffer buffer) { ref BufferEntry bufferEntry = ref _buffers[slot]; SetReference!(bufferEntry.Buffer, buffer); String.NewOrSet!(bufferEntry.Name, name); + if (engineBufferName.IsEmpty) + DeleteAndNullify!(bufferEntry.EngineBufferName); + else + { + String.NewOrSet!(bufferEntry.EngineBufferName, engineBufferName); + _engineBuffers.Add(bufferEntry.EngineBufferName, &bufferEntry); + } + _strToBuf.Add(bufferEntry.Name, &bufferEntry); } diff --git a/GlitchyEngine/src/Renderer/BufferVariable.bf b/GlitchyEngine/src/Renderer/BufferVariable.bf index 3612bad..fcd6255 100644 --- a/GlitchyEngine/src/Renderer/BufferVariable.bf +++ b/GlitchyEngine/src/Renderer/BufferVariable.bf @@ -24,6 +24,8 @@ namespace GlitchyEngine.Renderer private ConstantBuffer _constantBuffer; private String _name ~ delete _; + protected String _previewName ~ delete _; + protected String _editorTypeName ~ delete _; private ShaderVariableType _elementType; @@ -41,6 +43,8 @@ namespace GlitchyEngine.Renderer public ShaderVariableType ElementType => _elementType; public String Name => _name; + public StringView PreviewName => _previewName; + public StringView EditorTypeName => _editorTypeName; public bool IsUsed => _flags.HasFlag(.Used); @@ -70,9 +74,11 @@ namespace GlitchyEngine.Renderer [Inline] internal uint8* firstByte => _constantBuffer.rawData.CArray() + _offset; - public this(StringView name, ConstantBuffer constantBuffer, ShaderVariableType type, uint32 columns, uint32 rows, uint32 offset, uint32 sizeInBytes, uint32 arrayElements, bool isUsed) + public this(StringView name, ConstantBuffer constantBuffer, ShaderVariableType type, uint32 columns, uint32 rows, uint32 offset, uint32 sizeInBytes, uint32 arrayElements, bool isUsed, StringView previewName, StringView editorTypeName) { _name = new String(name); + _previewName = new String(previewName); + _editorTypeName = new String(editorTypeName); _constantBuffer = constantBuffer; // Only hold a weak reference. This variable has to die with the buffer _elementType = type; _columns = columns; diff --git a/GlitchyEngine/src/Renderer/ConstantBuffer.bf b/GlitchyEngine/src/Renderer/ConstantBuffer.bf index 4db50ed..676924d 100644 --- a/GlitchyEngine/src/Renderer/ConstantBuffer.bf +++ b/GlitchyEngine/src/Renderer/ConstantBuffer.bf @@ -9,6 +9,7 @@ namespace GlitchyEngine.Renderer public class ConstantBuffer : Buffer { protected String _name ~ delete _; + protected String _engineBufferName ~ delete _; /** * The buffer that contains the buffer data on the CPU. @@ -23,6 +24,7 @@ namespace GlitchyEngine.Renderer /// Gets the name of the constant buffer. public StringView Name => _name; + public StringView EngineBufferName => _engineBufferName; public BufferVariableCollection Variables => _variables; @@ -31,9 +33,15 @@ namespace GlitchyEngine.Renderer protected this() {} - public this(StringView name, int64 size) + public this(StringView name, int64 size, StringView engineBufferName = "") { _name = new String(name); + + if (!engineBufferName.IsEmpty) + { + _engineBufferName = new String(engineBufferName); + } + rawData = new uint8[size]; ConstructBuffer(); } @@ -43,9 +51,9 @@ namespace GlitchyEngine.Renderer _variables.Add(ownVariable); } - public void AddVariable(StringView name, uint64 offset, uint64 sizeInBytes, bool isUsed, ShaderVariableType type, uint8 rows, uint8 columns, uint64 arraySize) + public void AddVariable(StringView name, StringView previewName, StringView editorTypeName, uint64 offset, uint64 sizeInBytes, bool isUsed, ShaderVariableType type, uint8 rows, uint8 columns, uint64 arraySize) { - _variables.Add(new BufferVariable(name, this, type, columns, rows, (uint32)offset, (uint32)sizeInBytes, (uint32)arraySize, isUsed)); + _variables.Add(new BufferVariable(name, this, type, columns, rows, (uint32)offset, (uint32)sizeInBytes, (uint32)arraySize, isUsed, previewName, editorTypeName)); } /** diff --git a/GlitchyEngine/src/Renderer/Material.bf b/GlitchyEngine/src/Renderer/Material.bf index b82e22e..af856d2 100644 --- a/GlitchyEngine/src/Renderer/Material.bf +++ b/GlitchyEngine/src/Renderer/Material.bf @@ -95,7 +95,7 @@ public class Material : Asset BufferCollection parentBuffers = _parent?._bufferCollection ?? _effect.Buffers; - for (let (bufferName, buffer) in parentBuffers) + for (let (bufferName, engineBufferName, buffer) in parentBuffers) { if (buffer == null) continue; @@ -104,7 +104,7 @@ public class Material : Asset { using (OverridingConstantBuffer childConstBuffer = new OverridingConstantBuffer(parentConstBuffer)) { - _bufferCollection.Add(@bufferName.Index, childConstBuffer.Name, childConstBuffer); + _bufferCollection.Add(@bufferName.Index, childConstBuffer.Name, engineBufferName, childConstBuffer); InitVariables(childConstBuffer); } } @@ -177,7 +177,7 @@ public class Material : Asset { Debug.Profiler.ProfileRendererFunction!(); - for (let (bufferName, buffer) in _bufferCollection) + for (let (bufferName, engineBufferName, buffer) in _bufferCollection) { if (let cbuffer = buffer as ConstantBuffer) { diff --git a/GlitchyEngine/src/Renderer/OverridingConstantBuffer.bf b/GlitchyEngine/src/Renderer/OverridingConstantBuffer.bf index c9fdab9..659e5be 100644 --- a/GlitchyEngine/src/Renderer/OverridingConstantBuffer.bf +++ b/GlitchyEngine/src/Renderer/OverridingConstantBuffer.bf @@ -12,7 +12,7 @@ class OverridingConstantBuffer : ConstantBuffer public ConstantBuffer Parent => _parent; - public this(ConstantBuffer parent) : base(parent.Name, parent.RawData.Length) + public this(ConstantBuffer parent) : base(parent.Name, parent.RawData.Length, parent.EngineBufferName) { Log.EngineLogger.AssertDebug(parent != null); _parent = parent; @@ -25,7 +25,7 @@ class OverridingConstantBuffer : ConstantBuffer for (BufferVariable parentVariable in _parent.Variables) { BufferVariable newVariable = new BufferVariable(parentVariable.Name, this, parentVariable.ElementType, parentVariable.Columns, - parentVariable.Rows, parentVariable.Offset, parentVariable._sizeInBytes, parentVariable.ArrayElements, parentVariable.IsUsed); + parentVariable.Rows, parentVariable.Offset, parentVariable._sizeInBytes, parentVariable.ArrayElements, parentVariable.IsUsed, parentVariable.PreviewName, parentVariable.EditorTypeName); if (parentVariable.Flags.HasFlag(.Locked)) {