using System; using GlitchyEngine.Math; namespace GlitchyEngine.Renderer { using internal GlitchyEngine.Renderer; public class BufferVariable { private ConstantBuffer _constantBuffer; private String _name ~ delete _; private ShaderVariableType _type; internal uint32 _columns; internal uint32 _rows; private uint32 _offset; internal uint32 _sizeInBytes; // Number of elements in the array internal uint32 _elements; private bool _isUsed; public ConstantBuffer ConstantBuffer => _constantBuffer; public ShaderVariableType Type => _type; public String Name => _name; public bool IsUsed => _isUsed; /** * Gets a pointer to the start of the variable in the constant buffers backing data. */ [Inline] internal uint8* firstByte => _constantBuffer.rawData.CArray() + _offset; public this(ConstantBuffer constantBuffer, ShaderVariableType type, uint32 columns, uint32 rows, uint32 offset, uint32 sizeInBytes, uint32 elements, bool isUsed) { _constantBuffer = constantBuffer..AddRef(); _type = type; _columns = columns; _rows = rows; _offset = offset; _sizeInBytes = sizeInBytes; _elements = elements; _isUsed = isUsed; } public void EnsureTypeMatch(int rows, int cols, ShaderVariableType type) { #if GE_SHADER_MATRIX_MISMATCH_IS_ERROR Log.EngineLogger.Assert(rows == _rows || cols == _columns, scope $"The matrix-dimensions do not match: Expected {_rows} rows and {_rows} columns but Received {rows} rows and {cols} columns instead. Variable: \"{_name}\" of buffer: \"{_constantBuffer.Name}\""); #elif GE_SHADER_MATRIX_MISMATCH_IS_WARNING if (rows != _rows || cols != _columns) Log.EngineLogger.Warning($"The matrix-dimensions do not match: Expected {_rows} rows and {_rows} columns but Received {rows} rows and {cols} columns instead. Variable: \"{_name}\" of buffer: \"{_constantBuffer.Name}\""); #endif #if GE_SHADER_VAR_TYPE_MISMATCH_IS_ERROR Log.EngineLogger.Assert(type == _type, scope $"The types do not match: Expected \"{_type}\" but Received \"{type}\" instead. Variable: \"{_name}\" of buffer: \"{_constantBuffer.Name}\""); #elif GE_SHADER_VAR_TYPE_MISMATCH_IS_WARNING if (type != _type) Log.EngineLogger.Warning($"The types do not match: Expected \"{_type}\" but Received \"{type}\" instead. Variable: \"{_name}\" of buffer: \"{_constantBuffer.Name}\""); #endif } public void EnsureTypeMatch() { switch(typeof(T)) { case typeof(bool): EnsureTypeMatch(1, 1, .Bool); case typeof(float): EnsureTypeMatch(1, 1, .Float); case typeof(Vector2): EnsureTypeMatch(1, 2, .Float); case typeof(Vector3): EnsureTypeMatch(1, 3, .Float); case typeof(Vector4): EnsureTypeMatch(1, 4, .Float); case typeof(int32): EnsureTypeMatch(1, 1, .Int); case typeof(Int32_2): EnsureTypeMatch(1, 2, .Int); case typeof(Int32_3): EnsureTypeMatch(1, 3, .Int); case typeof(Int32_4): EnsureTypeMatch(1, 4, .Int); case typeof(Matrix4x3): EnsureTypeMatch(4, 3, .Float); case typeof(Matrix3x3): EnsureTypeMatch(3, 3, .Float); case typeof(Matrix): EnsureTypeMatch(4, 4, .Float); case typeof(ColorRGB): EnsureTypeMatch(1, 3, .Float); case typeof(ColorRGBA): EnsureTypeMatch(1, 4, .Float); case typeof(Color): EnsureTypeMatch(1, 4, .Float); } } [Inline] private void SetData(T value) { EnsureTypeMatch(); *(T*)firstByte = value; } [Inline] private T GetData() { return *(T*)firstByte; } public void SetData(bool value) => SetData(value); public void SetData(float value) => SetData(value); public void SetData(Vector2 value) => SetData(value); public void SetData(Vector3 value) => SetData(value); public void SetData(Vector4 value) => SetData(value); public void SetData(int32 value) => SetData(value); public void SetData(Int32_2 value) => SetData(value); public void SetData(Int32_3 value) => SetData(value); public void SetData(Int32_4 value) => SetData(value); public void SetData(ColorRGB value) => SetData(value); public void SetData(ColorRGBA value) => SetData(value); public void SetData(Color value) => SetData((ColorRGBA)value); public void SetData(Matrix4x3 value) => SetData(value); public void SetData(Matrix4x3[] value) { EnsureTypeMatch(); // TODO: assert length Internal.MemCpy(firstByte, value.Ptr, sizeof(Matrix4x3) * Math.Min(value.Count, _elements)); } public void SetData(Matrix3x3 value) { EnsureTypeMatch(); *(Matrix4x3*)firstByte = Matrix4x3(value); // Todo: maybe manual copy } public void SetData(Matrix3x3[] value) { EnsureTypeMatch(); // TODO: assert length for(int i < Math.Min(value.Count, _elements)) { ((Matrix4x3*)firstByte)[i] = Matrix4x3(value[i]); } } public void SetData(Matrix value) => SetData(value); public void SetData(Matrix[] value) { EnsureTypeMatch(); // TODO: assert length Internal.MemCpy(firstByte, value.Ptr, sizeof(Matrix) * Math.Min(value.Count, _elements)); } // Todo: add all the other SetData-Methods /** * Sets the raw data of the variable. * @param rawData The pointer to the raw data. If rawData is null the raw data will be set to zero. */ internal void SetRawData(void* rawData) { #if GE_SHADER_UNUSED_VARIABLE_IS_ERROR Log.EngineLogger.Assert(_isUsed, scope $"Setting data for unused Variable \"{_name}\" of constant buffer \"{_constantBuffer.Name}\"."); #elif GE_SHADER_UNUSED_VARIABLE_IS_WARNING if(!_isUsed) { Log.EngineLogger.Warning($"Setting data for unused Variable \"{_name}\" of constant buffer \"{_constantBuffer.Name}\"."); } #endif if(rawData != null) Internal.MemCpy(firstByte, rawData, _sizeInBytes); else Internal.MemSet(firstByte, 0, _sizeInBytes); } } }