diff --git a/GlitchyEditor/resources/Materials/Default 2D.mat b/GlitchyEditor/resources/Materials/Default 2D.mat new file mode 100644 index 0000000..dc36e32 --- /dev/null +++ b/GlitchyEditor/resources/Materials/Default 2D.mat @@ -0,0 +1,5 @@ +{ + Effect = 7757902626263730438, + Textures = [], + Constants = [] +} \ No newline at end of file diff --git a/GlitchyEditor/resources/Materials/Default 2D.mat.ass b/GlitchyEditor/resources/Materials/Default 2D.mat.ass new file mode 100644 index 0000000..008c77c --- /dev/null +++ b/GlitchyEditor/resources/Materials/Default 2D.mat.ass @@ -0,0 +1,13 @@ +{ + AssetLoader = null, + Config = null, + Importer = "MaterialImporter", + ImporterConfig = null, + Processor = null, + ProcessorConfig = null, + Exporter = null, + ExporterConfig = { + _compression = .None + }, + AssetHandle = 14657247797693923776 +} \ No newline at end of file diff --git a/GlitchyEditor/resources/Materials/Default Lit.mat b/GlitchyEditor/resources/Materials/Default Lit.mat new file mode 100644 index 0000000..e405067 --- /dev/null +++ b/GlitchyEditor/resources/Materials/Default Lit.mat @@ -0,0 +1,5 @@ +{ + Effect = 2172704887168568810, + Textures = [], + Constants = [] +} \ No newline at end of file diff --git a/GlitchyEditor/resources/Materials/Default Lit.mat.ass b/GlitchyEditor/resources/Materials/Default Lit.mat.ass new file mode 100644 index 0000000..c74fed6 --- /dev/null +++ b/GlitchyEditor/resources/Materials/Default Lit.mat.ass @@ -0,0 +1,13 @@ +{ + AssetLoader = null, + Config = null, + Importer = "MaterialImporter", + ImporterConfig = null, + Processor = null, + ProcessorConfig = null, + Exporter = null, + ExporterConfig = { + _compression = .None + }, + AssetHandle = 15110879072477854834 +} \ No newline at end of file diff --git a/GlitchyEditor/src/EditWindows/AssetViewer.bf b/GlitchyEditor/src/EditWindows/AssetViewer.bf index a32df67..3c6a9e7 100644 --- a/GlitchyEditor/src/EditWindows/AssetViewer.bf +++ b/GlitchyEditor/src/EditWindows/AssetViewer.bf @@ -187,11 +187,12 @@ class TextureViewer Width = 100, Height = 100, ColorTargetDescriptions = TargetDescription[]( - .(.R8G8B8A8_UNorm, clearColor: .Color(ColorRGBA.Pink)), - .(.R32_UInt) + .(.R8G8B8A8_UNorm, clearColor: .Color(ColorRGBA.Pink), ownDebugName: new $"Color"), + .(.R32_UInt, ownDebugName: new $"Enity ID (Unused)") ), - DepthTargetDescription = .(.D24_UNorm_S8_UInt) + DepthTargetDescription = .(.D24_UNorm_S8_UInt, ownDebugName: new $"Depth Stencil") }); + _targets.[Friend]Identifier = "Asset Viewer"; } float2 _position; diff --git a/GlitchyEditor/src/EditorLayer.bf b/GlitchyEditor/src/EditorLayer.bf index 751afa2..1b66957 100644 --- a/GlitchyEditor/src/EditorLayer.bf +++ b/GlitchyEditor/src/EditorLayer.bf @@ -342,11 +342,12 @@ namespace GlitchyEditor Width = 100, Height = 100, ColorTargetDescriptions = TargetDescription[]( - .(.R16G16B16A16_Float), - .(.R32_UInt) + .(.R16G16B16A16_Float, ownDebugName: new String("HDR Color")), + .(.R32_UInt, ownDebugName: new String("EntityID")) ), DepthTargetDescription = .(.D24_UNorm_S8_UInt) }); + _cameraTarget.[Friend]Identifier = "Camera Target"; _editorViewportTarget = new RenderTargetGroup(.() { @@ -355,6 +356,7 @@ namespace GlitchyEditor ColorTargetDescriptions = TargetDescription[]( .(.R8G8B8A8_UNorm)) }); + _editorViewportTarget.[Friend]Identifier = "Editor Viewport Target"; _gameViewportTarget = new RenderTargetGroup(.() { @@ -363,6 +365,7 @@ namespace GlitchyEditor ColorTargetDescriptions = TargetDescription[]( .(.R8G8B8A8_UNorm)) }); + _editorViewportTarget.[Friend]Identifier = "Game Viewport Target"; _editorIcons = new EditorIcons("Resources/Textures/EditorIcons.dds", .(64, 64)); _editorIcons.SamplerState = SamplerStateManager.AnisotropicClamp; diff --git a/GlitchyEngine/src/Renderer/BufferVariable.bf b/GlitchyEngine/src/Renderer/BufferVariable.bf index 07d7925..3612bad 100644 --- a/GlitchyEngine/src/Renderer/BufferVariable.bf +++ b/GlitchyEngine/src/Renderer/BufferVariable.bf @@ -109,6 +109,26 @@ namespace GlitchyEngine.Renderer #endif } + public enum TypematchResult + { + Ok, + MatrixDimensionMismatch, + ElementTypeMismatch, + } + + public TypematchResult CheckTypematch(int rows, int cols, ShaderVariableType type) + { + Debug.Profiler.ProfileRendererFunction!(); + + if (rows != _rows || cols != _columns) + return .MatrixDimensionMismatch; + + if (type != _elementType) + return .ElementTypeMismatch; + + return .Ok; + } + public void EnsureTypeMatch() { switch(typeof(T)) diff --git a/GlitchyEngine/src/Renderer/Material.bf b/GlitchyEngine/src/Renderer/Material.bf index 4aa086c..6b5ab84 100644 --- a/GlitchyEngine/src/Renderer/Material.bf +++ b/GlitchyEngine/src/Renderer/Material.bf @@ -196,7 +196,7 @@ public class Material : Asset } } - private mixin SetVariable(String name, var value) + private mixin SetVariable(StringView name, var value) { if(_variables.TryGetValue(name, let entry)) { @@ -204,35 +204,72 @@ public class Material : Asset } } - public void SetVariable(String name, bool value) => SetVariable!(name, value); - public void SetVariable(String name, bool2 value) => SetVariable!(name, value); - public void SetVariable(String name, bool3 value) => SetVariable!(name, value); - public void SetVariable(String name, bool4 value) => SetVariable!(name, value); - - public void SetVariable(String name, int32 value) => SetVariable!(name, value); - public void SetVariable(String name, int2 value) => SetVariable!(name, value); - public void SetVariable(String name, int3 value) => SetVariable!(name, value); - public void SetVariable(String name, int4 value) => SetVariable!(name, value); + public enum SetVariableError + { + VariableNotFound, + ElementTypeMismatch, + MatrixDimensionMismatch, + ProvidedBufferTooShort, + } - public void SetVariable(String name, uint32 value) => SetVariable!(name, value); - public void SetVariable(String name, uint2 value) => SetVariable!(name, value); - public void SetVariable(String name, uint3 value) => SetVariable!(name, value); - public void SetVariable(String name, uint4 value) => SetVariable!(name, value); + internal Result SetVariableRaw(StringView name, ShaderVariableType elementType, int32 rows, int32 columns, int32 arrayLength, Span rawData) + { + if(!_variables.TryGetValue(name, let variable)) + { + return .Err(.VariableNotFound); + } - public void SetVariable(String name, float value) => SetVariable!(name, value); - public void SetVariable(String name, float2 value) => SetVariable!(name, value); - public void SetVariable(String name, float3 value) => SetVariable!(name, value); - public void SetVariable(String name, float4 value) => SetVariable!(name, value); + let matchResult = variable.CheckTypematch(rows, columns, elementType); - public void SetVariable(String name, Color value) => SetVariable!(name, value); - public void SetVariable(String name, ColorRGB value) => SetVariable!(name, value); - public void SetVariable(String name, ColorRGBA value) => SetVariable!(name, value); + switch (matchResult) + { + case .Ok: + // Nothing went wrong. + case .ElementTypeMismatch: + return .Err(.ElementTypeMismatch); + case .MatrixDimensionMismatch: + return .Err(.MatrixDimensionMismatch); + } - public void SetVariable(String name, Matrix3x3 value) => SetVariable!(name, value); - public void SetVariable(String name, Matrix4x3 value) => SetVariable!(name, value); - public void SetVariable(String name, Matrix value) => SetVariable!(name, value); + if (rawData.Length < variable._sizeInBytes) + return .Err(.ProvidedBufferTooShort); - public void GetVariable(String name, out T value) where T : struct + // TODO: This method is very stupid atm. + // We could e.g. allow array length mismatches by simply copying the smaller amount of elements. + variable.SetRawData(rawData.Ptr); + + return .Ok; + } + + public void SetVariable(StringView name, bool value) => SetVariable!(name, value); + public void SetVariable(StringView name, bool2 value) => SetVariable!(name, value); + public void SetVariable(StringView name, bool3 value) => SetVariable!(name, value); + public void SetVariable(StringView name, bool4 value) => SetVariable!(name, value); + + public void SetVariable(StringView name, int32 value) => SetVariable!(name, value); + public void SetVariable(StringView name, int2 value) => SetVariable!(name, value); + public void SetVariable(StringView name, int3 value) => SetVariable!(name, value); + public void SetVariable(StringView name, int4 value) => SetVariable!(name, value); + + public void SetVariable(StringView name, uint32 value) => SetVariable!(name, value); + public void SetVariable(StringView name, uint2 value) => SetVariable!(name, value); + public void SetVariable(StringView name, uint3 value) => SetVariable!(name, value); + public void SetVariable(StringView name, uint4 value) => SetVariable!(name, value); + + public void SetVariable(StringView name, float value) => SetVariable!(name, value); + public void SetVariable(StringView name, float2 value) => SetVariable!(name, value); + public void SetVariable(StringView name, float3 value) => SetVariable!(name, value); + public void SetVariable(StringView name, float4 value) => SetVariable!(name, value); + + public void SetVariable(StringView name, Color value) => SetVariable!(name, value); + public void SetVariable(StringView name, ColorRGB value) => SetVariable!(name, value); + public void SetVariable(StringView name, ColorRGBA value) => SetVariable!(name, value); + + public void SetVariable(StringView name, Matrix3x3 value) => SetVariable!(name, value); + public void SetVariable(StringView name, Matrix4x3 value) => SetVariable!(name, value); + public void SetVariable(StringView name, Matrix value) => SetVariable!(name, value); + + public void GetVariable(StringView name, out T value) where T : struct { Debug.Profiler.ProfileRendererFunction!(); diff --git a/GlitchyEngine/src/Renderer/Renderer.bf b/GlitchyEngine/src/Renderer/Renderer.bf index 1fd994a..9ac0163 100644 --- a/GlitchyEngine/src/Renderer/Renderer.bf +++ b/GlitchyEngine/src/Renderer/Renderer.bf @@ -98,6 +98,7 @@ namespace GlitchyEngine.Renderer static GBuffer _gBuffer; static AssetHandle TestFullscreenEffect; + static Material TestDeferredMaterial ~ _?.ReleaseRef(); static AssetHandle s_tonemappingEffect; static BlendState _gBufferBlend; @@ -179,6 +180,9 @@ namespace GlitchyEngine.Renderer static void InitDeferredRenderer() { TestFullscreenEffect = Content.LoadAsset("Resources/Shaders/simpleLight.fx", null, true); + + TestDeferredMaterial = new Material(TestFullscreenEffect); + s_tonemappingEffect = Content.LoadAsset("Resources/Shaders/SimpleTonemapping.fx", null, true); _gBuffer = new GBuffer(); @@ -362,32 +366,56 @@ namespace GlitchyEngine.Renderer { Debug.Profiler.ProfileRendererScope!("Draw Light"); - Effect fsEffect = TestFullscreenEffect.Get(); + //Effect fsEffect = TestFullscreenEffect.Get(); - if (fsEffect == null) + if (TestDeferredMaterial == null) continue; float3 lightDir = -light.Transform.Forward; - fsEffect.SetTexture("GBuffer_Albedo", _gBuffer.Target, 0); - fsEffect.SetTexture("GBuffer_Normal", _gBuffer.Target, 1); - fsEffect.SetTexture("GBuffer_Tangent", _gBuffer.Target, 2); - fsEffect.SetTexture("GBuffer_Position", _gBuffer.Target, 3); - fsEffect.SetTexture("GBuffer_Emissive", _gBuffer.Target, 4); - fsEffect.SetTexture("GBuffer_Material", _gBuffer.Target, 5); + /*TestDeferredMaterial.SetTexture("GBuffer_Albedo", _gBuffer.Target, 0); + TestDeferredMaterial.SetTexture("GBuffer_Normal", _gBuffer.Target, 1); + TestDeferredMaterial.SetTexture("GBuffer_Tangent", _gBuffer.Target, 2); + TestDeferredMaterial.SetTexture("GBuffer_Position", _gBuffer.Target, 3); + TestDeferredMaterial.SetTexture("GBuffer_Emissive", _gBuffer.Target, 4); + TestDeferredMaterial.SetTexture("GBuffer_Material", _gBuffer.Target, 5);*/ - fsEffect.Variables["LightColor"].SetData(light.Light.Color); - fsEffect.Variables["Illuminance"].SetData(light.Light.Illuminance); - fsEffect.Variables["LightDir"].SetData(lightDir); + TestDeferredMaterial.SetVariable("LightColor", light.Light.Color); + TestDeferredMaterial.SetVariable("Illuminance", light.Light.Illuminance); + TestDeferredMaterial.SetVariable("LightDir", lightDir); - fsEffect.Variables["CameraPos"].SetData(_sceneConstants.CameraPosition); + TestDeferredMaterial.SetVariable("CameraPos", _sceneConstants.CameraPosition); - fsEffect.Variables["Scaling"].SetData(scaling); + TestDeferredMaterial.SetVariable("Scaling", scaling); - fsEffect.ApplyChanges(); - fsEffect.Bind(); - - //RenderCommand.BindEffect(TestFullscreenEffect); + TestDeferredMaterial.Bind(); + + // TODO: Don't do that please... + + using (let vb = _gBuffer.Target.GetViewBinding(0)) + { + RenderCommand.BindTexture(vb, 0, .Pixel); + } + using (let vb = _gBuffer.Target.GetViewBinding(1)) + { + RenderCommand.BindTexture(vb, 1, .Pixel); + } + using (let vb = _gBuffer.Target.GetViewBinding(2)) + { + RenderCommand.BindTexture(vb, 2, .Pixel); + } + using (let vb = _gBuffer.Target.GetViewBinding(3)) + { + RenderCommand.BindTexture(vb, 3, .Pixel); + } + using (let vb = _gBuffer.Target.GetViewBinding(4)) + { + RenderCommand.BindTexture(vb, 4, .Pixel); + } + using (let vb = _gBuffer.Target.GetViewBinding(5)) + { + RenderCommand.BindTexture(vb, 5, .Pixel); + } FullscreenQuad.Draw(); } diff --git a/GlitchyEngine/src/Renderer/Renderer2D.bf b/GlitchyEngine/src/Renderer/Renderer2D.bf index a08230e..8308d3c 100644 --- a/GlitchyEngine/src/Renderer/Renderer2D.bf +++ b/GlitchyEngine/src/Renderer/Renderer2D.bf @@ -640,9 +640,9 @@ namespace GlitchyEngine.Renderer return; s_quadInstanceBuffer.SetData(s_rawQuadInstances.Ptr, s_setQuadInstances, 0, .WriteDiscard); - - //s_currentQuadEffect.ApplyChanges(); - //s_currentQuadEffect.Bind(); + + // TODO: Bind scene buffer + material.SetVariable("ViewProjection", sceneViewProjection); material.Bind(); using (TextureViewBinding tvb = texture.GetViewBinding()) @@ -1151,8 +1151,8 @@ namespace GlitchyEngine.Renderer uvTransform = sprite.TextureCoordinates; } - // TODO: Material for Sprite renderer - DrawQuad(transform, spriteTexture ?? s_whiteTexture, null, spriteRenderer.Color, uvTransform, entityId); + Material material = spriteRenderer.Material.Get(); + DrawQuad(transform, spriteTexture ?? s_whiteTexture, material, spriteRenderer.Color, uvTransform, entityId); } public static void DrawCircle(Matrix transform, CircleRendererComponent* spriteRenderer, uint32 entityId) diff --git a/GlitchyEngine/src/Scripting/ScriptGlue.bf b/GlitchyEngine/src/Scripting/ScriptGlue.bf index ccc8d91..99f57e4 100644 --- a/GlitchyEngine/src/Scripting/ScriptGlue.bf +++ b/GlitchyEngine/src/Scripting/ScriptGlue.bf @@ -12,15 +12,18 @@ using GlitchyEngine.Scripting; using GlitchyEngine.Serialization; using GlitchyEngine.Editor; using GlitchyEngine.World.Components; +using GlitchyEngine.Content; +using GlitchyEngine.Renderer; using static GlitchyEngine.Renderer.Text.FontRenderer; namespace GlitchyEngine.Scripting; using internal GlitchyEngine.Scripting; +using internal GlitchyEngine.Content; class MessageOrigin { - private String _fileName; + private String _fileName ~ delete:append _; private int _lineNumber; public StringView FileName => _fileName; @@ -91,8 +94,11 @@ static class ScriptGlue RegisterComponent("GlitchyEngine.Core.Transform"); RegisterComponent("GlitchyEngine.Physics.Rigidbody2D"); RegisterComponent("GlitchyEngine.Core.Camera"); + RegisterComponent("GlitchyEngine.Graphics.SpriteRenderer"); RegisterComponent("GlitchyEngine.Graphics.CircleRenderer"); RegisterComponent("GlitchyEngine.Graphics.Text.TextRenderer"); + RegisterComponent("GlitchyEngine.Graphics.Mesh"); + RegisterComponent("GlitchyEngine.Graphics.MeshRenderer"); } [RegisterMethod] @@ -211,13 +217,29 @@ static class ScriptGlue #region Exception Helpers - /// Throws an argument exception. + /// Throws an ArgumentException in the mono runtime. [NoReturn] static void ThrowArgumentException(char8* argument, char8* message) { MonoException* exception = Mono.mono_get_exception_argument(argument, message); Mono.mono_raise_exception(exception); } + + /// Throws an InvalidOperationException in the mono runtime. + [NoReturn] + static void ThrowInvalidOperationException(char8* message) + { + MonoException* exception = Mono.mono_get_exception_invalid_operation(message); + Mono.mono_raise_exception(exception); + } + + /// Throws an NotImplementedException in the mono runtime. + [NoReturn] + static void ThrowNotImplementedException(char8* message) + { + MonoException* exception = Mono.mono_get_exception_invalid_operation(message); + Mono.mono_raise_exception(exception); + } #endregion @@ -998,6 +1020,53 @@ static class ScriptGlue #endregion +#region SpriteRenderer + + [RegisterCall("ScriptGlue::SpriteRenderer_GetColor")] + static void SpriteRenderer_GetColor(UUID entityId, out ColorRGBA color) + { + SpriteRendererComponent* spriteRenderer = GetComponentSafe(entityId); + color = spriteRenderer.Color; + } + + [RegisterCall("ScriptGlue::SpriteRenderer_SetColor")] + static void SpriteRenderer_SetColor(UUID entityId, ColorRGBA color) + { + SpriteRendererComponent* spriteRenderer = GetComponentSafe(entityId); + spriteRenderer.Color = color; + } + + [RegisterCall("ScriptGlue::SpriteRenderer_GetUvTransform")] + static void SpriteRenderer_GetUvTransform(UUID entityId, out float4 uvTransform) + { + SpriteRendererComponent* spriteRenderer = GetComponentSafe(entityId); + uvTransform = spriteRenderer.UvTransform; + } + + [RegisterCall("ScriptGlue::SpriteRenderer_SetUvTransform")] + static void SpriteRenderer_SetUvTransform(UUID entityId, float4 uvTransform) + { + SpriteRendererComponent* spriteRenderer = GetComponentSafe(entityId); + spriteRenderer.UvTransform = uvTransform; + } + + [RegisterCall("ScriptGlue::SpriteRenderer_GetMaterial")] + static void SpriteRenderer_GetMaterial(UUID entityId, out AssetHandle assetId) + { + SpriteRendererComponent* spriteRenderer = GetComponentSafe(entityId); + assetId = spriteRenderer.Material; + } + + [RegisterCall("ScriptGlue::SpriteRenderer_SetMaterial")] + static void SpriteRenderer_SetMaterial(UUID entityId, AssetHandle assetId) + { + SpriteRendererComponent* spriteRenderer = GetComponentSafe(entityId); + spriteRenderer.Material = assetId; + } + + +#endregion + #region TextRenderer [RegisterCall("ScriptGlue::TextRenderer_SetIsRichText")] @@ -1084,6 +1153,27 @@ static class ScriptGlue #endregion +#region Mesh +#endregion + +#region MeshRenderer + + [RegisterCall("ScriptGlue::MeshRenderer_GetMaterial")] + static void MeshRenderer_GetMaterial(UUID entityId, out AssetHandle assetId) + { + MeshRendererComponent* meshRenderer = GetComponentSafe(entityId); + assetId = meshRenderer.Material; + } + + [RegisterCall("ScriptGlue::MeshRenderer_SetMaterial")] + static void MeshRenderer_SetMaterial(UUID entityId, AssetHandle assetId) + { + MeshRendererComponent* meshRenderer = GetComponentSafe(entityId); + meshRenderer.Material = assetId; + } + +#endregion + #region Math private static void RegisterMathFunctions() @@ -1234,6 +1324,89 @@ static class ScriptGlue #endregion +#region Asset + + /*static mixin GetAssetOrThrow(UUID assetId) + { + AssetHandle handle = .(assetId); + Asset asset = Content.GetAsset(handle, blocking: true); + + if (asset == null) + { + ThrowInvalidOperationException(scope $"No asset exists for AssetHandle \"{assetId}\"."); + } + + asset + }*/ + + static mixin GetAssetOrThrow(UUID assetId) where T : Asset + { + AssetHandle handle = .(assetId); + T asset = Content.GetAsset(handle, blocking: true); + + if (asset == null) + { + ThrowInvalidOperationException(scope $"No asset exists for AssetHandle \"{assetId}\"."); + } + + asset + } + + static mixin GetAssetOrThrow(AssetHandle assetHandle) where T : Asset + { + T asset = Content.GetAsset(assetHandle, blocking: true); + + if (asset == null) + { + ThrowInvalidOperationException(scope $"No asset exists for AssetHandle \"{assetHandle}\"."); + } + + asset + } + + [RegisterCall("ScriptGlue::Asset_GetIdentifier")] + static void Asset_GetIdentifier(UUID assetId, out MonoString* text) + { + Asset asset = GetAssetOrThrow!(assetId); + + text = Mono.mono_string_new_len(ScriptEngine.[Friend]s_AppDomain, asset.Identifier.Ptr, (uint32)asset.Identifier.Length); + } + + [RegisterCall("ScriptGlue::Asset_SetIdentifier")] + static void Asset_GetIdentifier(UUID assetId, MonoString* text) + { + ThrowNotImplementedException("Asset.GetIdentifier is not implemented."); + + /*AssetHandle handle = .(assetId); + Asset asset = Content.GetAsset(handle, blocking: true); + + char8* rawText = Mono.mono_string_to_utf8(text); + + // TODO: I think it's not THAT easy. + asset.Identifier = StringView(rawText); + + Mono.mono_free(rawText);*/ + } + +#endregion + +#region Material + + [RegisterCall("ScriptGlue::Material_SetVariable")] + static void Material_SetVariable(AssetHandle assetHandle, MonoString* managedVariableName, ShaderVariableType elementType, int32 rows, int32 columns, int32 arrayLength, uint8* rawData, int32 dataLength) + { + Material material = GetAssetOrThrow!(assetHandle); + + char8* rawVariableName = Mono.mono_string_to_utf8(managedVariableName); + defer Mono.mono_free(rawVariableName); + + StringView variableName = StringView(rawVariableName); + + material.[Friend]SetVariableRaw(variableName, elementType, rows, columns , arrayLength, Span(rawData, dataLength)); + } + +#endregion + #region ImGui Extension [RegisterCall("ScriptGlue::ImGuiExtension_ListElementGrabber")] @@ -1242,6 +1415,7 @@ static class ScriptGlue ImGui.ImGui.ListElementGrabber(); } + #endregion private static void RegisterCall(String name, T method) where T : var diff --git a/GlitchyEngine/src/World/Components/Components.bf b/GlitchyEngine/src/World/Components/Components.bf index 17c79eb..de47225 100644 --- a/GlitchyEngine/src/World/Components/Components.bf +++ b/GlitchyEngine/src/World/Components/Components.bf @@ -49,6 +49,8 @@ namespace GlitchyEngine.World public ColorRGBA Color = .White; public float4 UvTransform = .(0, 0, 1, 1); + + public AssetHandle Material = .Invalid; public this() { diff --git a/GlitchyEngine/src/World/SceneRenderer.bf b/GlitchyEngine/src/World/SceneRenderer.bf index 7c7ccee..a53c7ed 100644 --- a/GlitchyEngine/src/World/SceneRenderer.bf +++ b/GlitchyEngine/src/World/SceneRenderer.bf @@ -233,8 +233,6 @@ class SceneRenderer FontRenderer.DrawText(text.PreparedText, transform.WorldTransform, text.Color, entity.Index); } - //FontRenderer.DrawText(_smallLinesInfo, 0, 0); - Renderer2D.EndScene(); Renderer2D.BeginScene(camera, .BackToFront); diff --git a/GlitchyEngineHelper/src/Mono/Mono.bf b/GlitchyEngineHelper/src/Mono/Mono.bf index 48cf8c4..12f6bee 100644 --- a/GlitchyEngineHelper/src/Mono/Mono.bf +++ b/GlitchyEngineHelper/src/Mono/Mono.bf @@ -293,6 +293,12 @@ static class Mono [LinkName(.C)] public static extern MonoException* mono_get_exception_argument(char8* arg, char8* msg); + [LinkName(.C)] + public static extern MonoException* mono_get_exception_invalid_operation(char8* msg); + + [LinkName(.C)] + public static extern MonoException* mono_get_exception_not_implemented(char8* msg); + #endregion [LinkName(.C)] diff --git a/ScriptCore/Editor/EntityEditor.cs b/ScriptCore/Editor/EntityEditor.cs index 0f6ff67..b3c2683 100644 --- a/ScriptCore/Editor/EntityEditor.cs +++ b/ScriptCore/Editor/EntityEditor.cs @@ -276,9 +276,12 @@ internal class EntityEditor var value = (T)reference!; - if (format == null && value is float || value is double || value is Half) + if (format == null) { - format = "0.#####"; + if (value is float || value is double || value is Half) + format = "0.#####"; + else + format = "0"; } if (!format.StartsWith("%")) @@ -512,14 +515,44 @@ internal class EntityEditor { newValue = ShowDecimalEditor(reference, fieldType, fieldName, attributes); } + else if (fieldType == typeof(ColorHSV)) + { + string fieldId = StartNewProperty(fieldName, attributes); + + ColorHSV value = (ColorHSV)reference!; + value.H /= 360.0f; + if (ImGui.ColorEdit3(fieldId, ref Unsafe.As(ref value), + ImGuiColorEditFlags.DisplayHSV | ImGuiColorEditFlags.InputHSV | ImGuiColorEditFlags.Float)) + { + value.H *= 360.0f; + newValue = value; + } + } + else if (fieldType == typeof(ColorRGB)) + { + string fieldId = StartNewProperty(fieldName, attributes); + + ColorRGB value = (ColorRGB)reference!; + if (ImGui.ColorEdit3(fieldId, ref Unsafe.As(ref value), ImGuiColorEditFlags.Float)) + newValue = value; + } else if (fieldType == typeof(ColorRGBA)) { string fieldId = StartNewProperty(fieldName, attributes); ColorRGBA value = (ColorRGBA)reference!; - if (ImGui.ColorEdit4(fieldId, ref Unsafe.As(ref value))) + if (ImGui.ColorEdit4(fieldId, ref Unsafe.As(ref value), ImGuiColorEditFlags.Float)) newValue = value; } + else if (fieldType == typeof(Color)) + { + string fieldId = StartNewProperty(fieldName, attributes); + + Color value = (Color)reference!; + ColorRGBA color = (ColorRGBA)value; + if (ImGui.ColorEdit4(fieldId, ref Unsafe.As(ref color))) + newValue = (Color)color; + } else if (fieldType.TryGetCustomAttribute(out VectorAttribute vectorAttribute)) { newValue = ShowVectorEditor(reference, fieldType, fieldName, vectorAttribute, attributes); diff --git a/ScriptCore/Graphics/Asset.cs b/ScriptCore/Graphics/Asset.cs new file mode 100644 index 0000000..4b65d75 --- /dev/null +++ b/ScriptCore/Graphics/Asset.cs @@ -0,0 +1,22 @@ +using GlitchyEngine.Core; + +namespace GlitchyEngine.Graphics; + +/// +/// The base class for all assets. +/// +public class Asset : EngineObject +{ + /// + /// Gets or sets the Identifier of the asset. + /// + public string Identifier + { + get + { + ScriptGlue.Asset_GetIdentifier(_uuid, out string identifier); + return identifier; + } + set => ScriptGlue.Asset_SetIdentifier(_uuid, value); + } +} diff --git a/ScriptCore/Graphics/CircleRenderer.cs b/ScriptCore/Graphics/CircleRenderer.cs index 9778b1a..94b0847 100644 --- a/ScriptCore/Graphics/CircleRenderer.cs +++ b/ScriptCore/Graphics/CircleRenderer.cs @@ -26,7 +26,7 @@ public class CircleRenderer : Component /// /// Gets or sets the UV transform for the texture. XY are an offset, ZW are scaling /// - public float4 UvTransform + public float4 UVTransform { get { diff --git a/ScriptCore/Graphics/Material.cs b/ScriptCore/Graphics/Material.cs new file mode 100644 index 0000000..98d11e0 --- /dev/null +++ b/ScriptCore/Graphics/Material.cs @@ -0,0 +1,15 @@ +using System.Diagnostics.SymbolStore; +using GlitchyEngine.Math; + +namespace GlitchyEngine.Graphics; + +public class Material : Asset +{ + public void SetVariable(string name, float4 value) + { + unsafe + { + ScriptGlue.Material_SetVariable(_uuid, name, ScriptGlue.ShaderVariableType.Float, 1, 4, 1, &value, sizeof(float4)); + } + } +} diff --git a/ScriptCore/Graphics/Mesh.cs b/ScriptCore/Graphics/Mesh.cs new file mode 100644 index 0000000..08f94d4 --- /dev/null +++ b/ScriptCore/Graphics/Mesh.cs @@ -0,0 +1,12 @@ +using GlitchyEngine.Core; + +namespace GlitchyEngine.Graphics; + +/// +/// Holds a reference to a Mesh. +/// Can be used in combination with a on the same to render the mesh. +/// +public class Mesh : Component +{ + +} diff --git a/ScriptCore/Graphics/MeshRenderer.cs b/ScriptCore/Graphics/MeshRenderer.cs new file mode 100644 index 0000000..6f655ea --- /dev/null +++ b/ScriptCore/Graphics/MeshRenderer.cs @@ -0,0 +1,23 @@ +using GlitchyEngine.Core; + +namespace GlitchyEngine.Graphics; + +/// +/// Renders a Mesh. The Mesh can be specified by adding a component to the same . +/// +public class MeshRenderer : Component +{ + /// + /// Gets or sets the Material of this . + /// + public Material Material + { + get + { + ScriptGlue.MeshRenderer_GetMaterial(_uuid, out UUID materialHandle); + + return new Material { _uuid = materialHandle }; + } + set => ScriptGlue.MeshRenderer_SetMaterial(_uuid, value._uuid); + } +} diff --git a/ScriptCore/Graphics/SpriteRenderer.cs b/ScriptCore/Graphics/SpriteRenderer.cs new file mode 100644 index 0000000..920f969 --- /dev/null +++ b/ScriptCore/Graphics/SpriteRenderer.cs @@ -0,0 +1,52 @@ +using GlitchyEngine.Core; +using GlitchyEngine.Math; + +namespace GlitchyEngine.Graphics; + +/// +/// Component that renders a sprite. +/// +public class SpriteRenderer : Component +{ + // TODO: Texture2D/Sprite + + /// + /// Gets or sets the tint color. + /// + public ColorRGBA Color + { + get + { + ScriptGlue.SpriteRenderer_GetColor(_uuid, out ColorRGBA color); + return color; + } + set => ScriptGlue.SpriteRenderer_SetColor(_uuid, value); + } + + /// + /// Gets or sets the UV-transform. + /// + public UVTransform UVTransform + { + get + { + ScriptGlue.SpriteRenderer_GetUvTransform(_uuid, out UVTransform uvTransform); + return uvTransform; + } + set => ScriptGlue.SpriteRenderer_SetUvTransform(_uuid, value); + } + + /// + /// Gets or sets the Material of this SpriteRenderer. + /// + public Material Material + { + get + { + ScriptGlue.SpriteRenderer_GetMaterial(_uuid, out UUID materialHandle); + + return new Material { _uuid = materialHandle }; + } + set => ScriptGlue.SpriteRenderer_SetMaterial(_uuid, value._uuid); + } +} diff --git a/ScriptCore/Graphics/UVTransform.cs b/ScriptCore/Graphics/UVTransform.cs new file mode 100644 index 0000000..9211bc0 --- /dev/null +++ b/ScriptCore/Graphics/UVTransform.cs @@ -0,0 +1,39 @@ +using System.Runtime.InteropServices; +using GlitchyEngine.Math; + +namespace GlitchyEngine.Graphics; + +/// +/// Stores transformations that can be applied to UV-Coordinates. +/// +[StructLayout(LayoutKind.Sequential, Pack=1)] +public struct UVTransform +{ + /// + /// The offset that will be added to the UV-Coordinate. + /// + public float2 Offset; + /// + /// The scaling that will be applied to the UV-Coordinate. + /// + public float2 Scale; + + /// + /// Creates a new instance of with the given scale and offset. + /// + /// + /// + public UVTransform(float2 offset, float2 scale) + { + Offset = offset; + Scale = scale; + } + + /// + /// Transforms the given uv-coordinate. + /// + public float2 Transform(float2 uvCoordinate) + { + return Offset + uvCoordinate * Scale; + } +} diff --git a/ScriptCore/Math/ColorHSV.cs b/ScriptCore/Math/ColorHSV.cs new file mode 100644 index 0000000..aaece33 --- /dev/null +++ b/ScriptCore/Math/ColorHSV.cs @@ -0,0 +1,115 @@ +namespace GlitchyEngine.Math; + +/// +/// Represents a color with hue, saturation and value. +/// +public struct ColorHSV +{ + /// + /// The hue of the color. Range: 0 - 360° + /// + public float H; + /// + /// The saturation of the color. Range: 0 - 1 + /// + public float S; + /// + /// The value of the color. Range: 0 - 1 + /// + public float V; + + /// + /// Creates a new instance of a based on the given hue, saturation and value. + /// + /// + /// + /// + public ColorHSV(float h, float s, float v) + { + H = h; + S = s; + V = v; + } + + /// + /// Creates a new instance of a based on the given . + /// + /// The RGB color that is to be converted to an HSV color + public ColorHSV(ColorRGB colorRGB) + { + this = (ColorHSV)colorRGB; + } + + public static explicit operator ColorRGB(ColorHSV hsv) + { + float c = hsv.V * hsv.S; + float x = c * (1.0f - Math.abs((hsv.H / 60.0f) % 2.0f - 1.0f)); + + float m = hsv.V - c; + + ColorRGB rgb = new ColorRGB(); + + hsv.H %= 360.0f; + + if (hsv.H < 60.0f) + rgb = new ColorRGB(c, x, 0); + else if (hsv.H < 120.0f) + rgb = new ColorRGB(x, c, 0); + else if (hsv.H < 180.0f) + rgb = new ColorRGB(0, c, x); + else if (hsv.H < 240.0f) + rgb = new ColorRGB(0, x, c); + else if (hsv.H < 300.0f) + rgb = new ColorRGB(x, 0, c); + else if (hsv.H < 360.0f) + rgb = new ColorRGB(c, 0, x); + + return new ColorRGB(rgb.R + m, rgb.G + m, rgb.B + m); + } + + public static explicit operator ColorHSV(ColorRGB rgb) + { + float r = rgb.R; + float g = rgb.G; + float b = rgb.B; + + float h; + float s; + float v; + + float maxChannel = Math.max(r, Math.max(g, b)); + float minChannel = Math.min(r, Math.min(g, b)); + v = maxChannel; + + if (minChannel == maxChannel) + { + h = 0.0f; + s = 0.0f; + } + else + { + s = (maxChannel - minChannel) / maxChannel; + float rc = (maxChannel - r) / (maxChannel - minChannel); + float gc = (maxChannel - g) / (maxChannel - minChannel); + float bc = (maxChannel - b) / (maxChannel - minChannel); + + if (r == maxChannel) + { + h = 0.0f + bc - gc; + } + else if (g == maxChannel) + { + h = 2.0f + rc - bc; + } + else + { + h = 4.0f + gc - rc; + } + + h = (h / 6.0f) % 1.0f; + h *= 360.0f; + } + + return new ColorHSV(h, s, v); + } +} diff --git a/ScriptCore/ScriptGlue.cs b/ScriptCore/ScriptGlue.cs index 722d5a7..cbf4bff 100644 --- a/ScriptCore/ScriptGlue.cs +++ b/ScriptCore/ScriptGlue.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using GlitchyEngine.Core; using GlitchyEngine.Editor; +using GlitchyEngine.Graphics; using GlitchyEngine.Graphics.Text; using GlitchyEngine.Math; using GlitchyEngine.Physics; @@ -256,6 +257,28 @@ internal static class ScriptGlue #endregion +#region SpriteRenderer + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void SpriteRenderer_GetColor(UUID entityId, out ColorRGBA color); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void SpriteRenderer_SetColor(UUID entityId, ColorRGBA color); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void SpriteRenderer_GetUvTransform(UUID entityId, out UVTransform uvTransform); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void SpriteRenderer_SetUvTransform(UUID entityId, UVTransform uvTransform); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void SpriteRenderer_GetMaterial(UUID entityId, out UUID materialId); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void SpriteRenderer_SetMaterial(UUID entityId, UUID materialId); + +#endregion + #region TextRenderer [MethodImpl(MethodImplOptions.InternalCall)] @@ -290,6 +313,17 @@ internal static class ScriptGlue #endregion +#region MeshRenderer + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void MeshRenderer_GetMaterial(UUID entityId, out UUID materialId); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void MeshRenderer_SetMaterial(UUID entityId, UUID materialId); + + +#endregion + #region Math [MethodImpl(MethodImplOptions.InternalCall)] @@ -309,7 +343,7 @@ internal static class ScriptGlue [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void UUID_CreateNew(out UUID uuid); - #region Application +#region Application [MethodImpl(MethodImplOptions.InternalCall)] internal static extern bool Application_IsEditor(); @@ -323,9 +357,9 @@ internal static class ScriptGlue [MethodImpl(MethodImplOptions.InternalCall)] internal static extern bool Application_IsInPlayMode(); - #endregion +#endregion - #region Serialization +#region Serialization [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void Serialization_SerializeField(IntPtr serializationContext, SerializationType type, string name, object? value, string? fullTypeName = null); @@ -342,7 +376,32 @@ internal static class ScriptGlue [MethodImpl(MethodImplOptions.InternalCall)] public static extern void Serialization_GetObjectTypeName(IntPtr internalContext, out string fullTypeName); - #endregion +#endregion + +#region Asset + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void Asset_GetIdentifier(UUID assetId, out string text); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void Asset_SetIdentifier(UUID assetId, string text); + +#endregion + +#region Material + + public enum ShaderVariableType : byte + { + Bool, + Float, + Int, + UInt + } + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern unsafe bool Material_SetVariable(UUID assetId, String variableName, ShaderVariableType elementType, int rows, int columns, int arrayLength, void* rawData, int dataLength); + +#endregion #region ImGui