mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Texture inheritance for materials, also script access
This commit is contained in:
@@ -476,10 +476,11 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
materialFile.Textures = new .();
|
materialFile.Textures = new .();
|
||||||
materialFile.Variables = 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);
|
materialFile.Textures.Add(new String(slotName), texture.Handle);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
Effect effect = material.Effect;
|
Effect effect = material.Effect;
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,13 @@ namespace GlitchyEditor.EditWindows
|
|||||||
{
|
{
|
||||||
private static uint32 TableId;
|
private static uint32 TableId;
|
||||||
|
|
||||||
|
public static this()
|
||||||
|
{
|
||||||
|
ScriptGlue.OnRegisterNativeCalls.Add(new () => {
|
||||||
|
ScriptGlue.RegisterCall<function bool(ref AssetHandle)>("ScriptGlue::ImGuiExtension_ShowAssetDropTarget", => ShowAssetDropTarget);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static void ShowComponents(Entity entity, Type componentType = null)
|
public static void ShowComponents(Entity entity, Type componentType = null)
|
||||||
{
|
{
|
||||||
float cellPaddingY = ImGui.GetTextLineHeight() / 3.0f;
|
float cellPaddingY = ImGui.GetTextLineHeight() / 3.0f;
|
||||||
@@ -497,8 +504,10 @@ namespace GlitchyEditor.EditWindows
|
|||||||
ShowAssetDropTarget<Material>(ref spriteRendererComponent.Material);
|
ShowAssetDropTarget<Material>(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);
|
Asset currentAsset = Content.GetAsset(target);
|
||||||
|
|
||||||
StringView identifier = currentAsset?.Identifier ?? (target.IsValid ? "<Missing Asset>" : "None");
|
StringView identifier = currentAsset?.Identifier ?? (target.IsValid ? "<Missing Asset>" : "None");
|
||||||
@@ -521,10 +530,13 @@ namespace GlitchyEditor.EditWindows
|
|||||||
|
|
||||||
// TODO: Somehow validate the type, please!
|
// TODO: Somehow validate the type, please!
|
||||||
target = (AssetHandle)Content.LoadAsset(path);
|
target = (AssetHandle)Content.LoadAsset(path);
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndDragDropTarget();
|
ImGui.EndDragDropTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ShowAssetDropTarget<T>(ref AssetHandle<T> target) where T : Asset
|
private static void ShowAssetDropTarget<T>(ref AssetHandle<T> target) where T : Asset
|
||||||
|
|||||||
@@ -207,7 +207,6 @@ class EditorContentManager : IContentManager
|
|||||||
{
|
{
|
||||||
delete key;
|
delete key;
|
||||||
}
|
}
|
||||||
delete:append _;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private append List<IAssetImporter> _assetImporters = .() ~ ClearAndDeleteItems!(_);
|
private append List<IAssetImporter> _assetImporters = .() ~ ClearAndDeleteItems!(_);
|
||||||
|
|||||||
@@ -440,14 +440,14 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
if (shaderStage.HasFlag(.Vertex))
|
if (shaderStage.HasFlag(.Vertex))
|
||||||
{
|
{
|
||||||
_vsShaderResources[slot] = textureBinding._nativeShaderResourceView;
|
_vsShaderResources[slot] = textureBinding?._nativeShaderResourceView;
|
||||||
_vsSamplers[slot] = textureBinding._nativeSamplerState;
|
_vsSamplers[slot] = textureBinding?._nativeSamplerState;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shaderStage.HasFlag(.Pixel))
|
if (shaderStage.HasFlag(.Pixel))
|
||||||
{
|
{
|
||||||
_psShaderResources[slot] = textureBinding._nativeShaderResourceView;
|
_psShaderResources[slot] = textureBinding?._nativeShaderResourceView;
|
||||||
_psSamplers[slot] = textureBinding._nativeSamplerState;
|
_psSamplers[slot] = textureBinding?._nativeSamplerState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ public class Material : Asset
|
|||||||
|
|
||||||
private Effect _effect ~ _?.ReleaseRef();
|
private Effect _effect ~ _?.ReleaseRef();
|
||||||
|
|
||||||
private Dictionary<String, (AssetHandle<Texture> Handle, TextureDimension Dimension, int32? groupTarget)> _textures = new .() ~ DeleteDictionaryAndKeys!(_);
|
|
||||||
|
|
||||||
private Dictionary<StringView, BufferVariable> _variables = new .() ~ delete _;
|
private Dictionary<StringView, BufferVariable> _variables = new .() ~ delete _;
|
||||||
|
|
||||||
|
private TextureCollection _textureCollection ~ delete _;
|
||||||
|
|
||||||
private BufferCollection _bufferCollection ~ _?.ReleaseRef();
|
private BufferCollection _bufferCollection ~ _?.ReleaseRef();
|
||||||
|
|
||||||
public Effect Effect
|
public Effect Effect
|
||||||
@@ -65,38 +65,8 @@ public class Material : Asset
|
|||||||
|
|
||||||
private void Init()
|
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<Texture> 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();
|
InitBuffers();
|
||||||
|
InitTextures();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitBuffers()
|
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<Texture> 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.
|
* Binds the materials Shaders and Parameters to the given context.
|
||||||
*/
|
*/
|
||||||
@@ -149,24 +174,6 @@ public class Material : Asset
|
|||||||
{
|
{
|
||||||
Debug.Profiler.ProfileRendererFunction!();
|
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<Texture2D> handle2D = .(texture.Handle);
|
|
||||||
_effect.SetTexture(name, handle2D);
|
|
||||||
case .TextureCube, .TextureCubeArray:
|
|
||||||
AssetHandle<TextureCube> 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)
|
for (let (bufferName, buffer) in _bufferCollection)
|
||||||
{
|
{
|
||||||
if (let cbuffer = buffer as ConstantBuffer)
|
if (let cbuffer = buffer as ConstantBuffer)
|
||||||
@@ -175,32 +182,31 @@ public class Material : Asset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*for(let (name, variable) in _variables)
|
|
||||||
{
|
|
||||||
variable.Variable.SetRawData(RawPointer!<uint8>(variable.Offset));
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//_effect.ApplyChanges();
|
|
||||||
_effect.Bind();
|
_effect.Bind();
|
||||||
|
|
||||||
RenderCommand.BindConstantBuffers(_bufferCollection);
|
RenderCommand.BindConstantBuffers(_bufferCollection);
|
||||||
|
|
||||||
|
_textureCollection.Bind();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Sets a texture of the material.
|
/** @brief Sets a texture of the material.
|
||||||
* @param name The name of the texture to set.
|
* @param name The name of the texture to set.
|
||||||
* @param texture The texture to bind to the effect.
|
* @param texture The texture to bind to the effect.
|
||||||
*/
|
*/
|
||||||
public void SetTexture(String name, AssetHandle<Texture> texture, int32? groupTargetIndex = null)
|
public Result<void, TextureCollection.SetTextureError> SetTexture(StringView name, AssetHandle<Texture> texture, int32? groupTargetIndex = null)
|
||||||
{
|
{
|
||||||
if(_textures.TryGetValue(name, var entry))
|
return _textureCollection.SetTexture(name, texture, groupTargetIndex);
|
||||||
{
|
|
||||||
_textures[name].Handle = texture;
|
|
||||||
_textures[name].groupTarget = groupTargetIndex;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
public Result<AssetHandle<Texture>, TextureCollection.SetTextureError> GetTexture(StringView name, out int32? groupTargetIndex)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"Material doesn't have the texture slot \"{name}\"");
|
return _textureCollection.GetTexture(name, out groupTargetIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Result<void, TextureCollection.SetTextureError> ResetTexture(StringView name)
|
||||||
|
{
|
||||||
|
return _textureCollection.ResetTexture(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private mixin SetVariable(StringView name, var value)
|
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<Texture> 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<String, TextureEntry> _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> 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<void, SetTextureError> SetTexture(StringView name, AssetHandle<Texture> 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<AssetHandle<Texture>, 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<void, SetTextureError> 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<Texture> 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<void> SetTexturePlatform();
|
||||||
|
}
|
||||||
@@ -76,6 +76,8 @@ static class ScriptGlue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Event<delegate void()> OnRegisterNativeCalls ~ _.Dispose();
|
||||||
|
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
RegisterCalls();
|
RegisterCalls();
|
||||||
@@ -104,6 +106,7 @@ static class ScriptGlue
|
|||||||
[RegisterMethod]
|
[RegisterMethod]
|
||||||
private static void RegisterCalls()
|
private static void RegisterCalls()
|
||||||
{
|
{
|
||||||
|
OnRegisterNativeCalls.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RegisterComponent<T>(StringView cSharpClassName = "") where T : struct, new
|
private static void RegisterComponent<T>(StringView cSharpClassName = "") where T : struct, new
|
||||||
@@ -1191,6 +1194,23 @@ static class ScriptGlue
|
|||||||
assetId = meshRenderer.Material;
|
assetId = meshRenderer.Material;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RegisterCall("ScriptGlue::MeshRenderer_GetSharedMaterial")]
|
||||||
|
static void MeshRenderer_GetSharedMaterial(UUID entityId, out AssetHandle assetId)
|
||||||
|
{
|
||||||
|
MeshRendererComponent* meshRenderer = GetComponentSafe<MeshRendererComponent>(entityId);
|
||||||
|
|
||||||
|
Material material = GetAssetOrThrow!<Material>((AssetHandle)meshRenderer.Material);
|
||||||
|
|
||||||
|
if (material.IsRuntimeInstance)
|
||||||
|
{
|
||||||
|
assetId = material.Parent.Handle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assetId = meshRenderer.Material;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[RegisterCall("ScriptGlue::MeshRenderer_SetMaterial")]
|
[RegisterCall("ScriptGlue::MeshRenderer_SetMaterial")]
|
||||||
static void MeshRenderer_SetMaterial(UUID entityId, AssetHandle assetId)
|
static void MeshRenderer_SetMaterial(UUID entityId, AssetHandle assetId)
|
||||||
{
|
{
|
||||||
@@ -1442,6 +1462,49 @@ static class ScriptGlue
|
|||||||
Mono.mono_free(rawVariableName);
|
Mono.mono_free(rawVariableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RegisterCall("ScriptGlue::Material_SetTexture")]
|
||||||
|
static void Material_SetTexture(AssetHandle materialHandle, MonoString* managedVariableName, AssetHandle textureHandle)
|
||||||
|
{
|
||||||
|
Material material = GetAssetOrThrow!<Material>(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!<Material>(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!<Material>(materialHandle);
|
||||||
|
|
||||||
|
char8* rawVariableName = Mono.mono_string_to_utf8(managedVariableName);
|
||||||
|
|
||||||
|
material.ResetTexture(StringView(rawVariableName));
|
||||||
|
|
||||||
|
Mono.mono_free(rawVariableName);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ImGui Extension
|
#region ImGui Extension
|
||||||
@@ -1452,10 +1515,9 @@ static class ScriptGlue
|
|||||||
ImGui.ImGui.ListElementGrabber();
|
ImGui.ImGui.ListElementGrabber();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private static void RegisterCall<T>(String name, T method) where T : var
|
public static void RegisterCall<T>(String name, T method) where T : var
|
||||||
{
|
{
|
||||||
Mono.mono_add_internal_call(scope $"GlitchyEngine.{name}", (void*)method);
|
Mono.mono_add_internal_call(scope $"GlitchyEngine.{name}", (void*)method);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using System.Runtime.InteropServices;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using GlitchyEngine.Core;
|
using GlitchyEngine.Core;
|
||||||
using GlitchyEngine.Extensions;
|
using GlitchyEngine.Extensions;
|
||||||
|
using GlitchyEngine.Graphics;
|
||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
using GlitchyEngine.Math.Attributes;
|
using GlitchyEngine.Math.Attributes;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
@@ -570,6 +571,10 @@ internal class EntityEditor
|
|||||||
{
|
{
|
||||||
newValue = ShowComponentDropTarget(fieldName, fieldType, reference, attributes);
|
newValue = ShowComponentDropTarget(fieldName, fieldType, reference, attributes);
|
||||||
}
|
}
|
||||||
|
else if (fieldType.IsSubclassOf(typeof(Asset)))
|
||||||
|
{
|
||||||
|
newValue = ShowAssetDropTarget(fieldName, fieldType, reference, attributes);
|
||||||
|
}
|
||||||
else if (fieldType == typeof(string))
|
else if (fieldType == typeof(string))
|
||||||
{
|
{
|
||||||
newValue = ShowStringEditor(reference, fieldType, fieldName, attributes);
|
newValue = ShowStringEditor(reference, fieldType, fieldName, attributes);
|
||||||
@@ -864,6 +869,38 @@ internal class EntityEditor
|
|||||||
return newValue;
|
return newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static object? ShowAssetDropTarget(string fieldName, Type fieldType, object? currentValue, IEnumerable<Attribute>? 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<Attribute>? attributes)
|
private static object? ShowEntityDropTarget(string fieldName, Type fieldType, object? currentValue, IEnumerable<Attribute>? attributes)
|
||||||
{
|
{
|
||||||
object? newValue = DidNotChange;
|
object? newValue = DidNotChange;
|
||||||
|
|||||||
@@ -51,6 +51,43 @@ public static class ActivatorExtension
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an instance of the given type inheriting from engine object and sets it's id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="engineObjectType">The type of the engine object.</param>
|
||||||
|
/// <param name="objectId">The objects id.</param>
|
||||||
|
/// <returns>An instance of the engine object type; or <see langword="null"/> if the creation failed.</returns>
|
||||||
|
internal static EngineObject? CreateEngineObject(Type engineObjectType, UUID objectId)
|
||||||
|
{
|
||||||
|
EngineObject? engineObject = (EngineObject?)CreateInstanceSafe(engineObjectType);
|
||||||
|
|
||||||
|
if (engineObject != null)
|
||||||
|
engineObject._uuid = objectId;
|
||||||
|
|
||||||
|
return engineObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an instance of the given type inheriting from engine object and sets it's id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="engineObjectType">The type of the engine object.</param>
|
||||||
|
/// <param name="objectId">The objects id.</param>
|
||||||
|
/// <returns>An instance of the engine object type; or <see langword="null"/> if the creation failed.</returns>
|
||||||
|
internal static T? CreateEngineObject<T>(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;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an instance of the given component type and sets it's entities id.
|
/// Creates an instance of the given component type and sets it's entities id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
@@ -74,6 +75,11 @@ public static class ImGuiExtension
|
|||||||
ScriptGlue.ImGuiExtension_ListElementGrabber();
|
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 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 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);
|
public static bool Checkbox4(string label, ref bool4 value) => CheckboxN(4, label, ref value.X);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Diagnostics.SymbolStore;
|
using System.Diagnostics.SymbolStore;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
|
|
||||||
namespace GlitchyEngine.Graphics;
|
namespace GlitchyEngine.Graphics;
|
||||||
@@ -20,4 +21,25 @@ public class Material : Asset
|
|||||||
{
|
{
|
||||||
ScriptGlue.Material_ResetVariable(_uuid, name);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,16 @@ namespace GlitchyEngine.Graphics;
|
|||||||
public class MeshRenderer : Component
|
public class MeshRenderer : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Material of this <see cref="MeshRenderer"/>.
|
/// Gets or sets the instance Material of this <see cref="MeshRenderer"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// If you get the <see cref="Material"/> and it is not yet a runtime-instance,
|
/// If you get the <see cref="GlitchyEngine.Graphics.Material"/> and it is not yet a runtime-instance,
|
||||||
/// a new runtime-instance will be created and returned in its place.
|
/// a new runtime-instance will be created and returned in its place. If you want to get the actual material instance,
|
||||||
|
/// use <see cref="SharedMaterial"/> instead.
|
||||||
|
/// <para>
|
||||||
|
/// <b>Note:</b> While the behaviour differs for getting <see cref="SharedMaterial"/> and <see cref="Material"/>,
|
||||||
|
/// the setter behaves identical for both properties.
|
||||||
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public Material Material
|
public Material Material
|
||||||
{
|
{
|
||||||
@@ -24,4 +29,30 @@ public class MeshRenderer : Component
|
|||||||
}
|
}
|
||||||
set => ScriptGlue.MeshRenderer_SetMaterial(_uuid, value._uuid);
|
set => ScriptGlue.MeshRenderer_SetMaterial(_uuid, value._uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the shared Material of this <see cref="MeshRenderer"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// In contrast to the <see cref="Material"/>-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.
|
||||||
|
/// <see cref="GlitchyEngine.Graphics.Material"/> is used (and obviously instances/children of it).
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// <b>Note:</b> While the behaviour differs for getting <see cref="SharedMaterial"/> and <see cref="Material"/>,
|
||||||
|
/// the setter behaves identical for both properties.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public Material SharedMaterial
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ScriptGlue.MeshRenderer_GetSharedMaterial(_uuid, out UUID materialHandle);
|
||||||
|
|
||||||
|
return new Material { _uuid = materialHandle };
|
||||||
|
}
|
||||||
|
set => ScriptGlue.MeshRenderer_SetMaterial(_uuid, value._uuid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace GlitchyEngine.Graphics;
|
||||||
|
|
||||||
|
public class Texture : Asset
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ namespace GlitchyEngine;
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All methods in here are glued to the ScriptGlue.bf in the engine.
|
/// All methods in here are glued to the ScriptGlue.bf in the engine.
|
||||||
|
/// TODO: This could be auto-generated fairly easily
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class ScriptGlue
|
internal static class ScriptGlue
|
||||||
{
|
{
|
||||||
@@ -321,6 +322,8 @@ internal static class ScriptGlue
|
|||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
internal static extern void MeshRenderer_SetMaterial(UUID entityId, UUID materialId);
|
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
|
#endregion
|
||||||
|
|
||||||
@@ -404,6 +407,15 @@ internal static class ScriptGlue
|
|||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
internal static extern bool Material_ResetVariable(UUID assetId, string variableName);
|
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
|
#endregion
|
||||||
|
|
||||||
#region ImGui
|
#region ImGui
|
||||||
@@ -411,5 +423,8 @@ internal static class ScriptGlue
|
|||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
internal static extern void ImGuiExtension_ListElementGrabber();
|
internal static extern void ImGuiExtension_ListElementGrabber();
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal static extern bool ImGuiExtension_ShowAssetDropTarget(ref UUID assetId);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user