From b5088329f589a16122e2cb4c80636040f84d297f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Sat, 1 Mar 2025 00:03:38 +0100 Subject: [PATCH] Texture inheritance for materials, also script access --- .../src/Assets/MaterialAssetLoader.bf | 5 +- .../src/EditWindows/ComponentEditWindow.bf | 14 +- GlitchyEditor/src/EditorContentManager.bf | 1 - .../DX11/Renderer/Dx11GraphicsContext.bf | 8 +- GlitchyEngine/src/Renderer/Material.bf | 296 ++++++++++++++---- GlitchyEngine/src/Scripting/ScriptGlue.bf | 68 +++- ScriptCore/Editor/EntityEditor.cs | 37 +++ ScriptCore/Extensions/ActivatorExtension.cs | 37 +++ ScriptCore/Extensions/ImGuiExtension.cs | 6 + ScriptCore/Graphics/Material.cs | 22 ++ ScriptCore/Graphics/MeshRenderer.cs | 37 ++- ScriptCore/Graphics/Texture.cs | 6 + ScriptCore/ScriptGlue.cs | 15 + 13 files changed, 470 insertions(+), 82 deletions(-) create mode 100644 ScriptCore/Graphics/Texture.cs diff --git a/GlitchyEditor/src/Assets/MaterialAssetLoader.bf b/GlitchyEditor/src/Assets/MaterialAssetLoader.bf index 6d2dd01..4dc4dbe 100644 --- a/GlitchyEditor/src/Assets/MaterialAssetLoader.bf +++ b/GlitchyEditor/src/Assets/MaterialAssetLoader.bf @@ -476,10 +476,11 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader materialFile.Textures = new .(); materialFile.Variables = new .(); - for (let (slotName, texture) in material.[Friend]_textures) + // TODO: Fix + /*for (let (slotName, texture) in material.[Friend]_textures) { materialFile.Textures.Add(new String(slotName), texture.Handle); - } + }*/ Effect effect = material.Effect; diff --git a/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf b/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf index d8d47e3..4ec27c4 100644 --- a/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf +++ b/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf @@ -19,6 +19,13 @@ namespace GlitchyEditor.EditWindows { private static uint32 TableId; + public static this() + { + ScriptGlue.OnRegisterNativeCalls.Add(new () => { + ScriptGlue.RegisterCall("ScriptGlue::ImGuiExtension_ShowAssetDropTarget", => ShowAssetDropTarget); + }); + } + public static void ShowComponents(Entity entity, Type componentType = null) { float cellPaddingY = ImGui.GetTextLineHeight() / 3.0f; @@ -497,8 +504,10 @@ namespace GlitchyEditor.EditWindows ShowAssetDropTarget(ref spriteRendererComponent.Material); } - private static void ShowAssetDropTarget(ref AssetHandle target) + private static bool ShowAssetDropTarget(ref AssetHandle target) { + bool changed = false; + Asset currentAsset = Content.GetAsset(target); StringView identifier = currentAsset?.Identifier ?? (target.IsValid ? "" : "None"); @@ -521,10 +530,13 @@ namespace GlitchyEditor.EditWindows // TODO: Somehow validate the type, please! target = (AssetHandle)Content.LoadAsset(path); + changed = true; } ImGui.EndDragDropTarget(); } + + return changed; } private static void ShowAssetDropTarget(ref AssetHandle target) where T : Asset diff --git a/GlitchyEditor/src/EditorContentManager.bf b/GlitchyEditor/src/EditorContentManager.bf index a06f317..1a3357c 100644 --- a/GlitchyEditor/src/EditorContentManager.bf +++ b/GlitchyEditor/src/EditorContentManager.bf @@ -207,7 +207,6 @@ class EditorContentManager : IContentManager { delete key; } - delete:append _; }; private append List _assetImporters = .() ~ ClearAndDeleteItems!(_); diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GraphicsContext.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GraphicsContext.bf index bdbed7c..e8bb62f 100644 --- a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GraphicsContext.bf +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11GraphicsContext.bf @@ -440,14 +440,14 @@ namespace GlitchyEngine.Renderer if (shaderStage.HasFlag(.Vertex)) { - _vsShaderResources[slot] = textureBinding._nativeShaderResourceView; - _vsSamplers[slot] = textureBinding._nativeSamplerState; + _vsShaderResources[slot] = textureBinding?._nativeShaderResourceView; + _vsSamplers[slot] = textureBinding?._nativeSamplerState; } if (shaderStage.HasFlag(.Pixel)) { - _psShaderResources[slot] = textureBinding._nativeShaderResourceView; - _psSamplers[slot] = textureBinding._nativeSamplerState; + _psShaderResources[slot] = textureBinding?._nativeShaderResourceView; + _psSamplers[slot] = textureBinding?._nativeSamplerState; } } diff --git a/GlitchyEngine/src/Renderer/Material.bf b/GlitchyEngine/src/Renderer/Material.bf index 798ad46..47752b8 100644 --- a/GlitchyEngine/src/Renderer/Material.bf +++ b/GlitchyEngine/src/Renderer/Material.bf @@ -21,10 +21,10 @@ public class Material : Asset private Effect _effect ~ _?.ReleaseRef(); - private Dictionary Handle, TextureDimension Dimension, int32? groupTarget)> _textures = new .() ~ DeleteDictionaryAndKeys!(_); - private Dictionary _variables = new .() ~ delete _; + private TextureCollection _textureCollection ~ delete _; + private BufferCollection _bufferCollection ~ _?.ReleaseRef(); public Effect Effect @@ -64,39 +64,9 @@ public class Material : Asset } private void Init() - { - decltype(_textures) newTextures = new .(); - - // Get texture slots from effect - for(let (name, effectTexture) in _effect.Textures) - { - // TODO: We need to be able to define default textures in the shader. - // At least things like "Black", "White", "Normal" - // At best whole paths. Shouldn't be that hard to do... - - AssetHandle textureHandle = .Invalid; - int32? groupTarget = null; - - if (_textures.TryGetValue(name, let oldMaterialTexture)) - { - textureHandle = oldMaterialTexture.Handle; - groupTarget = oldMaterialTexture.groupTarget; - } - - if (textureHandle.IsValid) - { - if (textureHandle.Dimension != effectTexture.TextureDimension) - textureHandle = .Invalid; - } - - newTextures[new String(name)] = (textureHandle, effectTexture.TextureDimension, groupTarget); - } - - DeleteDictionaryAndKeys!(_textures); - _textures = newTextures; - - //InitRawData(); + { InitBuffers(); + InitTextures(); } private void InitBuffers() @@ -142,6 +112,61 @@ public class Material : Asset } } + private void InitTextures() + { + delete _textureCollection; + _textureCollection = new TextureCollection(_parent?._textureCollection); + + if (_parent == null) + { + for(let (name, effectTexture) in _effect.Textures) + { + // TODO: We need to be able to define default textures in the shader. + // At least things like "Black", "White", "Normal" + // At best whole paths. Shouldn't be that hard to do... + AssetHandle textureHandle = .Invalid; + int32? groupTarget = null; + + if (textureHandle.IsValid) + { + if (textureHandle.Dimension != effectTexture.TextureDimension) + textureHandle = .Invalid; + } + + int32 textureSlot = -1; + + // TODO: This is a hack, because PsSlot and VsSlot actually break because they are references to dictionary items which sometimes get reallocated... + // But it is enough for now to detect if the slot exists. + if (effectTexture.PsSlot != null) + { + textureSlot = (.)_effect.PixelShader.Textures[name].Index; + } + else if (effectTexture.VsSlot != null) + { + textureSlot = (.)_effect.VertexShader.Textures[name].Index; + } + + Log.EngineLogger.AssertDebug(textureSlot != -1); + + _textureCollection.AddTexture(name, effectTexture.TextureDimension, textureSlot, textureHandle, groupTarget); + } + } + else + { + for(let (name, entry) in _parent._textureCollection.[Friend]_entries) + { + TextureCollection.TextureFlags flags = .Unset; + + if (entry.Flags.HasFlag(.Locked)) + { + flags |= .Locked | .Readonly; + } + + _textureCollection.AddTexture(name, entry.Dimension, entry.TextureSlot, .Invalid, null, flags); + } + } + } + /** * Binds the materials Shaders and Parameters to the given context. */ @@ -149,24 +174,6 @@ public class Material : Asset { Debug.Profiler.ProfileRendererFunction!(); - // TODO: Bind textures, don't go through effect for that - for(let (name, texture) in _textures) - { - switch (texture.Dimension) - { - //case .Texture1D, .Texture1DArray: - case .Texture2D, .Texture2DArray: - AssetHandle handle2D = .(texture.Handle); - _effect.SetTexture(name, handle2D); - case .TextureCube, .TextureCubeArray: - AssetHandle cubeHandle = .(texture.Handle); - _effect.SetTexture(name, cubeHandle); - //case .Texture3D: - default: - Log.EngineLogger.Error("Tryied to bind undefined texture dimension!"); - } - } - for (let (bufferName, buffer) in _bufferCollection) { if (let cbuffer = buffer as ConstantBuffer) @@ -175,32 +182,31 @@ public class Material : Asset } } - /*for(let (name, variable) in _variables) - { - variable.Variable.SetRawData(RawPointer!(variable.Offset)); - }*/ - - //_effect.ApplyChanges(); _effect.Bind(); RenderCommand.BindConstantBuffers(_bufferCollection); + + _textureCollection.Bind(); + } /** @brief Sets a texture of the material. * @param name The name of the texture to set. * @param texture The texture to bind to the effect. */ - public void SetTexture(String name, AssetHandle texture, int32? groupTargetIndex = null) + public Result SetTexture(StringView name, AssetHandle texture, int32? groupTargetIndex = null) { - if(_textures.TryGetValue(name, var entry)) - { - _textures[name].Handle = texture; - _textures[name].groupTarget = groupTargetIndex; - } - else - { - Log.EngineLogger.Error($"Material doesn't have the texture slot \"{name}\""); - } + return _textureCollection.SetTexture(name, texture, groupTargetIndex); + } + + public Result, TextureCollection.SetTextureError> GetTexture(StringView name, out int32? groupTargetIndex) + { + return _textureCollection.GetTexture(name, out groupTargetIndex); + } + + public Result ResetTexture(StringView name) + { + return _textureCollection.ResetTexture(name); } private mixin SetVariable(StringView name, var value) @@ -306,3 +312,157 @@ public class Material : Asset } } } + +public class TextureCollection +{ + public enum TextureFlags + { + None = 0x0, + /// The texture slot is dirty and needs to be sent do the GPU. + Dirty = 0x1, + /// The texture slot is locked, its value cannot be overwritten in child materials. + Locked = 0x2, + /// (For inherited textures only) The texture slot doesn't override the value set in the parent material. + Unset = 0x4, + /// The texture slots value cannot be changed. (i.e. it is locked in the parent material) + Readonly = 0x8 + } + + private struct TextureEntry + { + public AssetHandle TextureHandle; + public int32? groupTarget; + public TextureDimension Dimension; + public TextureFlags Flags; + public int32 TextureSlot; + } + + protected int _generation = 0; + protected int _parentGeneration = 0; + private TextureCollection _parent; + + private Dictionary _entries = new .() ~ DeleteDictionaryAndKeys!(_); + + public enum SetTextureError + { + TextureNotFound, + DimensionMismatch, + TextureSlotReadonly + } + + public this(TextureCollection parent = null) + { + _parent = parent; + } + + internal void AddTexture(StringView name, TextureDimension dimension, int32 slot, AssetHandle texture, int32? groupTargetIndex = null, TextureFlags flags = .None) + { + _entries.Add(new String(name), + TextureEntry() { + TextureHandle = texture, + groupTarget = groupTargetIndex, + Dimension = dimension, + TextureSlot = slot, + Flags = flags + }); + } + + public Result SetTexture(StringView name, AssetHandle texture, int32? groupTargetIndex = null) + { + if (_entries.TryGetRefAlt(name, ?, let entry)) + { + if (entry.Flags.HasFlag(.Readonly)) + { + return .Err(.TextureSlotReadonly); + } + + Texture textureAsset = texture.Get(); + + if (textureAsset != null && textureAsset.Dimension != entry.Dimension) + { + return .Err(.DimensionMismatch); + } + + entry.TextureHandle = texture; + + // TODO: Assert group target index + // We have to figure out how to properly use/pass them anyway + + entry.groupTarget = groupTargetIndex; + + Enum.ClearFlag(ref entry.Flags, .Unset); + Enum.SetFlag(ref entry.Flags, .Dirty); + + return .Ok; + } + + return .Err(.TextureNotFound); + } + + public Result, SetTextureError> GetTexture(StringView name, out int32? groupTargetIndex) + { + if (_entries.TryGetRefAlt(name, ?, let entry)) + { + if (entry.Flags.HasFlag(.Unset) && _parent != null) + { + return _parent.GetTexture(name, out groupTargetIndex); + } + + groupTargetIndex = entry.groupTarget; + + return entry.TextureHandle; + } + + groupTargetIndex = -1; + + return .Err(.TextureNotFound); + } + + public Result ResetTexture(StringView name) + { + if (_entries.TryGetRefAlt(name, ?, let entry)) + { + if (entry.Flags.HasFlag(.Readonly)) + { + return .Err(.TextureSlotReadonly); + } + + entry.TextureHandle = .Invalid; + entry.groupTarget = null; + + Enum.SetFlag(ref entry.Flags, .Unset | .Dirty); + + return .Ok; + } + + return .Err(.TextureNotFound); + } + + public void Bind() + { + for (var (name, entry) in _entries) + { + AssetHandle handle = entry.TextureHandle; + TextureCollection parentCollection = _parent; + TextureFlags flags = entry.Flags; + + // If necessary, look for a texture in the parent collection + while (flags.HasFlag(.Unset) && parentCollection != null) + { + TextureEntry parentEntry = parentCollection._entries[name]; + handle = parentEntry.TextureHandle; + parentCollection = parentCollection._parent; + flags = parentEntry.Flags; + } + + Texture texture = handle.Get(); + + using (let viewBinding = texture?.GetViewBinding()) + { + RenderCommand.BindTexture(viewBinding, entry.TextureSlot, .All); + } + } + } + + protected extern Result SetTexturePlatform(); +} \ No newline at end of file diff --git a/GlitchyEngine/src/Scripting/ScriptGlue.bf b/GlitchyEngine/src/Scripting/ScriptGlue.bf index b1a7c23..e8a4a27 100644 --- a/GlitchyEngine/src/Scripting/ScriptGlue.bf +++ b/GlitchyEngine/src/Scripting/ScriptGlue.bf @@ -76,6 +76,8 @@ static class ScriptGlue } } + public static Event OnRegisterNativeCalls ~ _.Dispose(); + public static void Init() { RegisterCalls(); @@ -104,6 +106,7 @@ static class ScriptGlue [RegisterMethod] private static void RegisterCalls() { + OnRegisterNativeCalls.Invoke(); } private static void RegisterComponent(StringView cSharpClassName = "") where T : struct, new @@ -1191,6 +1194,23 @@ static class ScriptGlue assetId = meshRenderer.Material; } + [RegisterCall("ScriptGlue::MeshRenderer_GetSharedMaterial")] + static void MeshRenderer_GetSharedMaterial(UUID entityId, out AssetHandle assetId) + { + MeshRendererComponent* meshRenderer = GetComponentSafe(entityId); + + Material material = GetAssetOrThrow!((AssetHandle)meshRenderer.Material); + + if (material.IsRuntimeInstance) + { + assetId = material.Parent.Handle; + } + else + { + assetId = meshRenderer.Material; + } + } + [RegisterCall("ScriptGlue::MeshRenderer_SetMaterial")] static void MeshRenderer_SetMaterial(UUID entityId, AssetHandle assetId) { @@ -1429,7 +1449,7 @@ static class ScriptGlue Mono.mono_free(rawVariableName); } - + [RegisterCall("ScriptGlue::Material_ResetVariable")] static void Material_ResetVariable(AssetHandle assetHandle, MonoString* managedVariableName) { @@ -1442,6 +1462,49 @@ static class ScriptGlue Mono.mono_free(rawVariableName); } + [RegisterCall("ScriptGlue::Material_SetTexture")] + static void Material_SetTexture(AssetHandle materialHandle, MonoString* managedVariableName, AssetHandle textureHandle) + { + Material material = GetAssetOrThrow!(materialHandle); + + char8* rawVariableName = Mono.mono_string_to_utf8(managedVariableName); + + material.SetTexture(StringView(rawVariableName), textureHandle); + + Mono.mono_free(rawVariableName); + } + + [RegisterCall("ScriptGlue::Material_GetTexture")] + static void Material_GetTexture(AssetHandle materialHandle, MonoString* managedVariableName, out AssetHandle textureHandle) + { + Material material = GetAssetOrThrow!(materialHandle); + + char8* rawVariableName = Mono.mono_string_to_utf8(managedVariableName); + + var v = material.GetTexture(StringView(rawVariableName), ?); + + if (v case .Err(let err)) + { + ThrowInvalidOperationException(scope $"Error while getting texture from material {err}"); + } + + textureHandle = v.Value; + + Mono.mono_free(rawVariableName); + } + + [RegisterCall("ScriptGlue::Material_ResetTexture")] + static void Material_ResetTexture(AssetHandle materialHandle, MonoString* managedVariableName) + { + Material material = GetAssetOrThrow!(materialHandle); + + char8* rawVariableName = Mono.mono_string_to_utf8(managedVariableName); + + material.ResetTexture(StringView(rawVariableName)); + + Mono.mono_free(rawVariableName); + } + #endregion #region ImGui Extension @@ -1452,10 +1515,9 @@ static class ScriptGlue ImGui.ImGui.ListElementGrabber(); } - #endregion - private static void RegisterCall(String name, T method) where T : var + public static void RegisterCall(String name, T method) where T : var { Mono.mono_add_internal_call(scope $"GlitchyEngine.{name}", (void*)method); } diff --git a/ScriptCore/Editor/EntityEditor.cs b/ScriptCore/Editor/EntityEditor.cs index b3c2683..c9cf0dc 100644 --- a/ScriptCore/Editor/EntityEditor.cs +++ b/ScriptCore/Editor/EntityEditor.cs @@ -12,6 +12,7 @@ using System.Runtime.InteropServices; using System.Text; using GlitchyEngine.Core; using GlitchyEngine.Extensions; +using GlitchyEngine.Graphics; using GlitchyEngine.Math; using GlitchyEngine.Math.Attributes; using ImGuiNET; @@ -570,6 +571,10 @@ internal class EntityEditor { newValue = ShowComponentDropTarget(fieldName, fieldType, reference, attributes); } + else if (fieldType.IsSubclassOf(typeof(Asset))) + { + newValue = ShowAssetDropTarget(fieldName, fieldType, reference, attributes); + } else if (fieldType == typeof(string)) { newValue = ShowStringEditor(reference, fieldType, fieldName, attributes); @@ -864,6 +869,38 @@ internal class EntityEditor return newValue; } + private static object? ShowAssetDropTarget(string fieldName, Type fieldType, object? currentValue, IEnumerable? attributes) + { + object? newValue = DidNotChange; + + string fieldId = StartNewProperty(fieldName, attributes); + + Asset? asset = currentValue as Asset; + + UUID uuid = asset?.UUID ?? UUID.Zero; + + if (ImGuiExtension.ShowAssetDropTarget(ref uuid)) + { + if (uuid == UUID.Zero) + { + newValue = null; + } + else + { + try + { + newValue = ActivatorExtension.CreateEngineObject(fieldType, uuid); + } + catch (Exception e) + { + Log.Exception(e); + } + } + } + + return newValue; + } + private static object? ShowEntityDropTarget(string fieldName, Type fieldType, object? currentValue, IEnumerable? attributes) { object? newValue = DidNotChange; diff --git a/ScriptCore/Extensions/ActivatorExtension.cs b/ScriptCore/Extensions/ActivatorExtension.cs index 9a289b5..2e59806 100644 --- a/ScriptCore/Extensions/ActivatorExtension.cs +++ b/ScriptCore/Extensions/ActivatorExtension.cs @@ -51,6 +51,43 @@ public static class ActivatorExtension return null; } + /// + /// Creates an instance of the given type inheriting from engine object and sets it's id. + /// + /// The type of the engine object. + /// The objects id. + /// An instance of the engine object type; or if the creation failed. + internal static EngineObject? CreateEngineObject(Type engineObjectType, UUID objectId) + { + EngineObject? engineObject = (EngineObject?)CreateInstanceSafe(engineObjectType); + + if (engineObject != null) + engineObject._uuid = objectId; + + return engineObject; + } + + /// + /// Creates an instance of the given type inheriting from engine object and sets it's id. + /// + /// The type of the engine object. + /// The objects id. + /// An instance of the engine object type; or if the creation failed. + internal static T? CreateEngineObject(Type engineObjectType, UUID objectId) where T : EngineObject + { + if (!typeof(T).IsAssignableFrom(engineObjectType)) + { + return null; + } + + EngineObject? engineObject = (EngineObject?)CreateInstanceSafe(engineObjectType); + + if (engineObject != null) + engineObject._uuid = objectId; + + return (T?)engineObject; + } + /// /// Creates an instance of the given component type and sets it's entities id. /// diff --git a/ScriptCore/Extensions/ImGuiExtension.cs b/ScriptCore/Extensions/ImGuiExtension.cs index 6889206..9fa1a00 100644 --- a/ScriptCore/Extensions/ImGuiExtension.cs +++ b/ScriptCore/Extensions/ImGuiExtension.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.CompilerServices; +using GlitchyEngine.Core; using GlitchyEngine.Math; using ImGuiNET; @@ -74,6 +75,11 @@ public static class ImGuiExtension ScriptGlue.ImGuiExtension_ListElementGrabber(); } + public static bool ShowAssetDropTarget(ref UUID uuid) + { + return ScriptGlue.ImGuiExtension_ShowAssetDropTarget(ref uuid); + } + public static bool Checkbox2(string label, ref bool2 value) => CheckboxN(2, label, ref value.X); public static bool Checkbox3(string label, ref bool3 value) => CheckboxN(3, label, ref value.X); public static bool Checkbox4(string label, ref bool4 value) => CheckboxN(4, label, ref value.X); diff --git a/ScriptCore/Graphics/Material.cs b/ScriptCore/Graphics/Material.cs index 1255ea7..77de02a 100644 --- a/ScriptCore/Graphics/Material.cs +++ b/ScriptCore/Graphics/Material.cs @@ -1,4 +1,5 @@ using System.Diagnostics.SymbolStore; +using GlitchyEngine.Core; using GlitchyEngine.Math; namespace GlitchyEngine.Graphics; @@ -20,4 +21,25 @@ public class Material : Asset { ScriptGlue.Material_ResetVariable(_uuid, name); } + + public void SetTexture(string name, Texture? texture) + { + ScriptGlue.Material_SetTexture(_uuid, name, texture?._uuid ?? UUID.Zero); + } + + public Texture? GetTexture(string name) + { + ScriptGlue.Material_GetTexture(_uuid, name, out UUID textureId); + + // TODO: Support different texture types? + return new Texture + { + _uuid = textureId + }; + } + + public void ResetTexture(string name) + { + ScriptGlue.Material_ResetTexture(_uuid, name); + } } diff --git a/ScriptCore/Graphics/MeshRenderer.cs b/ScriptCore/Graphics/MeshRenderer.cs index edd8b73..468db51 100644 --- a/ScriptCore/Graphics/MeshRenderer.cs +++ b/ScriptCore/Graphics/MeshRenderer.cs @@ -8,11 +8,16 @@ namespace GlitchyEngine.Graphics; public class MeshRenderer : Component { /// - /// Gets or sets the Material of this . + /// Gets or sets the instance Material of this . /// /// - /// If you get the and it is not yet a runtime-instance, - /// a new runtime-instance will be created and returned in its place. + /// If you get the and it is not yet a runtime-instance, + /// a new runtime-instance will be created and returned in its place. If you want to get the actual material instance, + /// use instead. + /// + /// Note: While the behaviour differs for getting and , + /// the setter behaves identical for both properties. + /// /// public Material Material { @@ -24,4 +29,30 @@ public class MeshRenderer : Component } set => ScriptGlue.MeshRenderer_SetMaterial(_uuid, value._uuid); } + + /// + /// Gets or sets the shared Material of this . + /// + /// + /// + /// In contrast to the -property this will not create a new runtime-instance and instead + /// always return the actual Material-Asset. + /// Making changes to the instance returned by this property will have global effect. + /// is used (and obviously instances/children of it). + /// + /// + /// Note: While the behaviour differs for getting and , + /// the setter behaves identical for both properties. + /// + /// + public Material SharedMaterial + { + get + { + ScriptGlue.MeshRenderer_GetSharedMaterial(_uuid, out UUID materialHandle); + + return new Material { _uuid = materialHandle }; + } + set => ScriptGlue.MeshRenderer_SetMaterial(_uuid, value._uuid); + } } diff --git a/ScriptCore/Graphics/Texture.cs b/ScriptCore/Graphics/Texture.cs new file mode 100644 index 0000000..3e0dd49 --- /dev/null +++ b/ScriptCore/Graphics/Texture.cs @@ -0,0 +1,6 @@ +namespace GlitchyEngine.Graphics; + +public class Texture : Asset +{ + +} \ No newline at end of file diff --git a/ScriptCore/ScriptGlue.cs b/ScriptCore/ScriptGlue.cs index ae35f44..f2948ac 100644 --- a/ScriptCore/ScriptGlue.cs +++ b/ScriptCore/ScriptGlue.cs @@ -13,6 +13,7 @@ namespace GlitchyEngine; /// /// All methods in here are glued to the ScriptGlue.bf in the engine. +/// TODO: This could be auto-generated fairly easily /// internal static class ScriptGlue { @@ -321,6 +322,8 @@ internal static class ScriptGlue [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void MeshRenderer_SetMaterial(UUID entityId, UUID materialId); + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void MeshRenderer_GetSharedMaterial(UUID entityId, out UUID materialId); #endregion @@ -404,6 +407,15 @@ internal static class ScriptGlue [MethodImpl(MethodImplOptions.InternalCall)] internal static extern bool Material_ResetVariable(UUID assetId, string variableName); + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern bool Material_SetTexture(UUID materialId, string textureName, UUID textureId); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern bool Material_GetTexture(UUID materialId, string textureName, out UUID textureId); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern bool Material_ResetTexture(UUID materialId, string textureName); + #endregion #region ImGui @@ -411,5 +423,8 @@ internal static class ScriptGlue [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void ImGuiExtension_ListElementGrabber(); + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern bool ImGuiExtension_ShowAssetDropTarget(ref UUID assetId); + #endregion }