Author SHA1 Message Date
Simon Lübeß 75513bea3d Removed obsolete texture viewer 2023-07-28 21:09:33 +02:00
Simon Lübeß 16c3d7c44d Updated ImGui 2023-07-28 13:38:59 +02:00
Simon Lübeß 7ae069baf6 Fixed loading UI font 2023-07-28 12:26:15 +02:00
Simon Lübeß 00dc3faa19 Failed to show and edit script sctruct
+ SizeInBytes for MonoFields
2023-07-28 11:48:01 +02:00
Simon Lübeß f39acdadb3 Show enum fields in Edit mode 2023-07-28 00:07:10 +02:00
Simon Lübeß 1254d01545 Handle exceptions from C# Scripts + Log window + EditorLogger
+ Renamed Platform/DX11/ImGui.bf to .../Dx11ImGui.bf for clarity
+ ImGuiExtension: ImageButtonEx thata takes a TextureViewBinding
+ EditorLogger that logs to the LogWindow
+ Current logger can now be changed
+ Info, Trace, Warning and Error Icons
2023-07-27 21:58:42 +02:00
Simon Lübeß 0bc517842f Allow changing logger 2023-07-27 00:42:42 +02:00
Simon Lübeß 3e63281508 Fixed mono debugging... 2023-07-26 22:56:43 +02:00
Simon Lübeß ef486b7082 Basic entity highlighting 2023-07-25 19:37:13 +02:00
Simon Lübeß 81a61d5a90 Drag'n'drop for components
+ Added CreateInstance to ScriptClass
+ Added CreateComponentInstance to ScriptInstance
2023-07-25 16:37:41 +02:00
Simon Lübeß 37197cbdf1 Allow dragging and dropping of Entities in editor
+ New Dictionary Helpers
+ Made ImGui Payloads safer
+ Start of Component drag'n'drop
2023-07-24 23:17:00 +02:00
Simon Lübeß b53ed2d8f2 Made script deserialization more robust 2023-07-24 21:28:58 +02:00
38 changed files with 1813 additions and 579 deletions
@@ -11,9 +11,9 @@ namespace Sandbox
public enum MyEnum public enum MyEnum
{ {
Yes, Yes = 1,
No, No,
Maybe Maybe = 1337
} }
public struct MyStruct public struct MyStruct
@@ -25,36 +25,38 @@ namespace Sandbox
class MyTestEntity : Entity class MyTestEntity : Entity
{ {
//[ShowInEditor] [ShowInEditor]
RigidBody2D _rigidBody; RigidBody2D _rigidBody;
public bool Bo; //public bool Bo;
public byte By; //public byte By;
public ushort Us; //public ushort Us;
public uint Ui; //public uint Ui;
public ulong Ul; //public ulong Ul;
public sbyte Sb; //public sbyte Sb;
public short Sh; //public short Sh;
public int In; //public int In;
public long Lo; //public long Lo;
public float Fl; //public float Fl;
public double Do; //public double Do;
public float2 V2; //public float2 V2;
public float3 V3; //public float3 V3;
public float4 V4; //public float4 V4;
public Entity TheEntity; public Entity TheEntity;
public float JumpForce = 2000; public float JumpForce = 2000;
[ShowInEditor] float MoveForce = 1000; [ShowInEditor] float MoveForce = 1000;
[ShowInEditor] private int MyNumber = 1337; [ShowInEditor] private int MyNumber = 1337;
[ShowInEditor] public double MyDouble = 1000.0f; //[ShowInEditor] public double MyDouble = 1000.0f;
public MyStruct AStruct; public MyStruct AStruct;
public MyEnum AEnum = MyEnum.Maybe;
public Camera Camera; public Camera Camera;
/// <summary> /// <summary>
@@ -66,8 +68,16 @@ namespace Sandbox
Log.Info($"Jump Force: {JumpForce}"); Log.Info($"Jump Force: {JumpForce}");
_rigidBody ??= GetComponent<RigidBody2D>() ?? AddComponent<RigidBody2D>(); //_rigidBody ??= GetComponent<RigidBody2D>() ?? AddComponent<RigidBody2D>();
if (_rigidBody == null)
{
Log.Error("_rigidBody was not set in editor.");
}
if (Camera == null)
{
Log.Warning("Camera wasn't set in editor. Searching...");
Camera = FindEntityWithName("Camera").As<Camera>(); Camera = FindEntityWithName("Camera").As<Camera>();
if (Camera == null) if (Camera == null)
@@ -75,6 +85,23 @@ namespace Sandbox
Log.Error("Camera not found."); Log.Error("Camera not found.");
} }
} }
Log.Warning("Achtung.");
try
{
SubVoid();
}
catch (Exception e)
{
Console.WriteLine(e);
throw e;
}
}
void SubVoid()
{
throw new Exception("Ouha!", new IndexOutOfRangeException("Bist du jecke2?!", new AccessViolationException("Haleluja")));
}
/// <summary> /// <summary>
/// Called every frame. /// Called every frame.
@@ -105,6 +132,9 @@ namespace Sandbox
force.Y += JumpForce; force.Y += JumpForce;
} }
if (Input.IsKeyPressing(Key.N))
SubVoid();
_rigidBody.ApplyForceToCenter(force); _rigidBody.ApplyForceToCenter(force);
if (Input.IsMouseButtonReleasing(MouseButton.MiddleButton)) if (Input.IsMouseButtonReleasing(MouseButton.MiddleButton))
@@ -15,7 +15,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>portable</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\</OutputPath> <OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
+22 -47
View File
@@ -71,8 +71,8 @@
SpriteRendererComponent = { SpriteRendererComponent = {
Color = { Color = {
R = 1, R = 1,
G = 0.941886961, G = 0.941887021,
B = 0.401484549, B = 0.401484489,
A = 1 A = 1
}, },
Sprite = "", Sprite = "",
@@ -162,7 +162,7 @@
OrthographicHeight = 10, OrthographicHeight = 10,
OrthographicNearPlane = 0, OrthographicNearPlane = 0,
OrthographicFarPlane = 10, OrthographicFarPlane = 10,
AspectRatio = 0.884925187, AspectRatio = 2.05582929,
FixedAspectRatio = false FixedAspectRatio = false
}, },
ScriptComponent = { ScriptComponent = {
@@ -195,8 +195,8 @@
}, },
TransformComponent = { TransformComponent = {
Position = { Position = {
X = -0.121203184, X = -0.121203206,
Y = 0.660160959, Y = 0.660161078,
Z = 0 Z = 0
}, },
Rotation = { Rotation = {
@@ -234,37 +234,12 @@
ScriptComponent = { ScriptComponent = {
ScriptClass = "Sandbox.MyTestEntity", ScriptClass = "Sandbox.MyTestEntity",
Fields = [ Fields = [
Bo = (Bool)false, _rigidBody = (Component)15710354273720487680,
By = (Byte)0,
Us = (UShort)57,
Ui = (UInt)54,
Ul = (ULong)53,
Sb = (SByte)-128,
Sh = (Short)95,
In = (Int)-149,
Lo = (Long)82,
Fl = (Float)-98.122963,
Do = (Double)118,
V2 = (float2){
X = 11,
Y = 12
},
V3 = (float3){
X = 13,
Y = 14,
Z = 15
},
V4 = (float4){
X = 14,
Y = 17,
Z = 18,
W = 19
},
TheEntity = (Entity)0, TheEntity = (Entity)0,
JumpForce = (Float)200, JumpForce = (Float)200,
MoveForce = (Float)148, MoveForce = (Float)148,
MyNumber = (Int)22, MyNumber = (Int)22,
MyDouble = (Double)23 Camera = (Entity)1491484622542812645
] } ] }
}, },
{ {
@@ -301,7 +276,7 @@
Color = { Color = {
R = 0.985467017, R = 0.985467017,
G = 1, G = 1,
B = 0.569978058 B = 0.569977939
} }
} }
}, },
@@ -348,8 +323,8 @@
SpriteRendererComponent = { SpriteRendererComponent = {
Color = { Color = {
R = 0.425658971, R = 0.425658971,
G = 0.855207562, G = 0.855207443,
B = 0.0558161102, B = 0.0558161177,
A = 1 A = 1
}, },
Sprite = "", Sprite = "",
@@ -363,14 +338,14 @@
TransformComponent = { TransformComponent = {
Position = { Position = {
X = 6.74610233, X = 6.74610233,
Y = -2.03225899, Y = -2.03225946,
Z = 0 Z = 0
}, },
Rotation = { Rotation = {
X = 0, X = 0,
Y = 0, Y = 0,
Z = -0.331792623, Z = -0.331792623,
W = 0.943352342 W = 0.94335258
}, },
Scale = { Scale = {
X = 5.29557419, X = 5.29557419,
@@ -409,7 +384,7 @@
}, },
SpriteRendererComponent = { SpriteRendererComponent = {
Color = { Color = {
R = 0.666116953, R = 0.666117013,
G = 0.0600316115, G = 0.0600316115,
B = 1, B = 1,
A = 1 A = 1
@@ -424,8 +399,8 @@
}, },
TransformComponent = { TransformComponent = {
Position = { Position = {
X = 15.2321301, X = 15.2321281,
Y = -1.98709249, Y = -1.98709273,
Z = 0 Z = 0
}, },
Rotation = { Rotation = {
@@ -435,7 +410,7 @@
W = 0.990847468 W = 0.990847468
}, },
Scale = { Scale = {
X = 13.9764566, X = 13.9764528,
Y = 1, Y = 1,
Z = 1 Z = 1
}, },
@@ -471,7 +446,7 @@
}, },
SpriteRendererComponent = { SpriteRendererComponent = {
Color = { Color = {
R = 0.176544324, R = 0.176544309,
G = 0.666713238, G = 0.666713238,
B = 0.687030852, B = 0.687030852,
A = 1 A = 1
@@ -487,24 +462,24 @@
TransformComponent = { TransformComponent = {
Position = { Position = {
X = -6.27842855, X = -6.27842855,
Y = 2.62550211, Y = 2.62550163,
Z = 0 Z = 0
}, },
Rotation = { Rotation = {
X = 0, X = 0,
Y = 0, Y = 0,
Z = 0.187087834, Z = 0.187087879,
W = 0.982343197 W = 0.982343197
}, },
Scale = { Scale = {
X = 0.999999523, X = 0.999999464,
Y = 6.49634314, Y = 6.49634314,
Z = 1 Z = 1
}, },
EditorEulerRotation = { EditorEulerRotation = {
X = 0, X = 0,
Y = 0, Y = 0,
Z = 0.376393586 Z = 0.376393616
} }
}, },
Rigidbody2D = { Rigidbody2D = {
@@ -522,7 +497,7 @@
}, },
Density = 1, Density = 1,
Friction = 0.5, Friction = 0.5,
Restitution = 0.899999976, Restitution = 0.899999857,
RestitutionThreshold = 0.5 RestitutionThreshold = 0.5
} }
} }
Binary file not shown.
@@ -9,8 +9,8 @@
AddressModeU = .Clamp, AddressModeU = .Clamp,
AddressModeV = .Clamp, AddressModeV = .Clamp,
AddressModeW = .Clamp, AddressModeW = .Clamp,
MipMinLOD = -340282346638528859811704183484516925440, MipMinLOD = -3.40282347e+38,
MipMaxLOD = 340282346638528859811704183484516925440, MipMaxLOD = 3.40282347e+38,
MaxAnisotropy = 1, MaxAnisotropy = 1,
BorderColor = { BorderColor = {
R = 1, R = 1,
Binary file not shown.
@@ -9,12 +9,21 @@
".NETStandard,Version=v2.0/": { ".NETStandard,Version=v2.0/": {
"ScriptCore/1.0.0": { "ScriptCore/1.0.0": {
"dependencies": { "dependencies": {
"Half": "1.0.0",
"NETStandard.Library": "2.0.3" "NETStandard.Library": "2.0.3"
}, },
"runtime": { "runtime": {
"ScriptCore.dll": {} "ScriptCore.dll": {}
} }
}, },
"Half/1.0.0": {
"runtime": {
"lib/netstandard2.0/System.Half.dll": {
"assemblyVersion": "1.0.0.0",
"fileVersion": "1.0.0.0"
}
}
},
"Microsoft.NETCore.Platforms/1.1.0": {}, "Microsoft.NETCore.Platforms/1.1.0": {},
"NETStandard.Library/2.0.3": { "NETStandard.Library/2.0.3": {
"dependencies": { "dependencies": {
@@ -29,6 +38,13 @@
"serviceable": false, "serviceable": false,
"sha512": "" "sha512": ""
}, },
"Half/1.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-EPLLPQA1UjF9QM3ymNhWLhgcnBNc8e1po4qWRWTD3Hd9xiohYlkCob0QjDIbJs6Nvfd4eAbsjxIwRyh7httyXA==",
"path": "half/1.0.0",
"hashPath": "half.1.0.0.nupkg.sha512"
},
"Microsoft.NETCore.Platforms/1.1.0": { "Microsoft.NETCore.Platforms/1.1.0": {
"type": "package", "type": "package",
"serviceable": true, "serviceable": true,
@@ -33,7 +33,7 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -78,7 +78,7 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -120,7 +120,7 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
value = (float3)ColorRGB.LinearToSRGB((ColorRGB)value); value = (float3)ColorRGB.LinearToSRGB((ColorRGB)value);
if (ImGui.ColorEdit3(displayName.Ptr, *(float[3]*)&value)) if (ImGui.ColorEdit3(displayName.Ptr, ref *(float[3]*)&value))
{ {
value = (float3)ColorRGB.SRgbToLinear((ColorRGB)value); value = (float3)ColorRGB.SRgbToLinear((ColorRGB)value);
material.SetVariable(variable.Name, value); material.SetVariable(variable.Name, value);
@@ -132,7 +132,7 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
value = (float4)ColorRGBA.LinearToSRGB((ColorRGBA)value); value = (float4)ColorRGBA.LinearToSRGB((ColorRGBA)value);
if (ImGui.ColorEdit4(displayName.Ptr, *(float[4]*)&value)) if (ImGui.ColorEdit4(displayName.Ptr, ref *(float[4]*)&value))
{ {
value = (float4)ColorRGBA.SRgbToLinear((ColorRGBA)value); value = (float4)ColorRGBA.SRgbToLinear((ColorRGBA)value);
material.SetVariable(variable.Name, value); material.SetVariable(variable.Name, value);
@@ -149,7 +149,7 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
value = (float3)ColorRGB.LinearToSRGB((ColorRGB)value); value = (float3)ColorRGB.LinearToSRGB((ColorRGB)value);
if (ImGui.ColorEdit3(displayName.Ptr, *(float[3]*)&value, .HDR | .Float)) if (ImGui.ColorEdit3(displayName.Ptr, ref *(float[3]*)&value, .HDR | .Float))
{ {
value = (float3)ColorRGB.SRgbToLinear((ColorRGB)value); value = (float3)ColorRGB.SRgbToLinear((ColorRGB)value);
material.SetVariable(variable.Name, value); material.SetVariable(variable.Name, value);
@@ -161,7 +161,7 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
value = (float4)ColorRGBA.LinearToSRGB((ColorRGBA)value); value = (float4)ColorRGBA.LinearToSRGB((ColorRGBA)value);
if (ImGui.ColorEdit4(displayName.Ptr, *(float[4]*)&value, .HDR | .Float)) if (ImGui.ColorEdit4(displayName.Ptr, ref *(float[4]*)&value, .HDR | .Float))
{ {
value = (float4)ColorRGBA.SRgbToLinear((ColorRGBA)value); value = (float4)ColorRGBA.SRgbToLinear((ColorRGBA)value);
material.SetVariable(variable.Name, value); material.SetVariable(variable.Name, value);
+56 -6
View File
@@ -31,7 +31,58 @@ class AssetViewer : EditorWindow
ImGui.PushStyleVar(.CellPadding, .(0, 0)); ImGui.PushStyleVar(.CellPadding, .(0, 0));
bool alt_pressed = ImGui.GetIO().KeyAlt; ImGui.Columns(2);
if (ImGui.BeginChild("Assets"))
{
DrawAssetList();
ImGui.EndChild();
}
ImGui.NextColumn();
if (ImGui.BeginChild("Files"))
{
DrawAssetViewer();
ImGui.EndChild();
}
ImGui.Columns(1);
/*if (ImGui.BeginTable("AssetViewerTable", 2, .BordersInnerV | .Resizable | .Reorderable | .NoPadOuterX))
{
if (alt_pressed)
{
// Header anzeigen, damit sie neu angeordnet werden können
ImGui.TableSetupColumn("Assets");
ImGui.TableSetupColumn("Viewer");
ImGui.TableHeadersRow();
}
ImGui.TableNextRow();
ImGui.TableSetColumnIndex(0);
if (ImGui.BeginChild("Assets"))
{
//DrawAssetList();
ImGui.EndChild();
}
ImGui.TableNextColumn();
if (ImGui.BeginChild("Files"))
{
//DrawAssetViewer();
ImGui.EndChild();
}
ImGui.EndTable();
}*/
/*bool alt_pressed = ImGui.GetIO().KeyAlt;
if (ImGui.BeginTable("AssetViewerTable", 2, .BordersInnerV | .Resizable | .Reorderable | .NoPadOuterX)) if (ImGui.BeginTable("AssetViewerTable", 2, .BordersInnerV | .Resizable | .Reorderable | .NoPadOuterX))
{ {
@@ -42,13 +93,12 @@ class AssetViewer : EditorWindow
ImGui.TableSetupColumn("Viewer"); ImGui.TableSetupColumn("Viewer");
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
} }
ImGui.TableNextRow(); ImGui.TableNextRow();
ImGui.TableSetColumnIndex(0); ImGui.TableSetColumnIndex(0);
if (ImGui.BeginChild("Assets")) if (ImGui.BeginChild("Assets"))
{ {
DrawAssetList(); //DrawAssetList();
ImGui.EndChild(); ImGui.EndChild();
} }
@@ -57,13 +107,13 @@ class AssetViewer : EditorWindow
if (ImGui.BeginChild("Files")) if (ImGui.BeginChild("Files"))
{ {
DrawAssetViewer(); //DrawAssetViewer();
ImGui.EndChild(); ImGui.EndChild();
} }
ImGui.EndTable(); ImGui.EndTable();
} }*/
ImGui.PopStyleVar(1); ImGui.PopStyleVar(1);
@@ -211,7 +261,7 @@ class TexturererViewerer
float maxDimension = max(width, height); float maxDimension = max(width, height);
ImGui.SliderFloat2("Position", *(float[2]*)&_position, 2 * -maxDimension * _zoom, 2 * maxDimension * _zoom); ImGui.SliderFloat2("Position", ref *(float[2]*)&_position, 2 * -maxDimension * _zoom, 2 * maxDimension * _zoom);
ImGui.Separator(); ImGui.Separator();
@@ -7,6 +7,8 @@ using GlitchyEngine.Renderer;
using GlitchyEngine; using GlitchyEngine;
using GlitchyEngine.Content; using GlitchyEngine.Content;
using GlitchyEngine.Scripting; using GlitchyEngine.Scripting;
using GlitchyEngine.Core;
using Mono;
namespace GlitchyEditor.EditWindows namespace GlitchyEditor.EditWindows
{ {
@@ -278,7 +280,7 @@ namespace GlitchyEditor.EditWindows
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -306,7 +308,7 @@ namespace GlitchyEditor.EditWindows
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -338,7 +340,7 @@ namespace GlitchyEditor.EditWindows
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -512,11 +514,89 @@ namespace GlitchyEditor.EditWindows
scriptInstance.SetFieldValue<T>(scriptField, value); scriptInstance.SetFieldValue<T>(scriptField, value);
} }
T GetData<T>(void* instance, ScriptField scriptField)
{
T data = default;
Mono.mono_field_get_value((.)instance, scriptField.[Friend]_monoField, &data);
return data;
}
void GetData<T>(void* instance, ScriptField scriptField, T* data)
{
Mono.mono_field_get_value((.)instance, scriptField.[Friend]_monoField, data);
}
void SetData<T>(void* instance, ScriptField scriptField, in T value)
{
Mono.mono_field_set_value((.)instance, scriptField.[Friend]_monoField, &value);
}
void SetData<T>(void* instance, ScriptField scriptField, T* data)
{
Mono.mono_field_set_value((.)instance, scriptField.[Friend]_monoField, data);
}
if (scriptComponent.Instance?.IsInitialized == true) if (scriptComponent.Instance?.IsInitialized == true)
{ {
SharpClass sharpClass = scriptComponent.Instance.ScriptClass; SharpClass sharpClass = scriptComponent.Instance.ScriptClass;
ScriptInstance scriptInstance = scriptComponent.Instance; ScriptInstance scriptInstance = scriptComponent.Instance;
/*void DoFunnyStuff(void* instance, SharpType sharpType)
{
for (let (fieldName, scriptField) in sharpType.Fields)
{
var monoField = scriptField.[Friend]_monoField;
switch (scriptField.FieldType)
{
case .Float:
var value = GetData<float>(instance, scriptField);
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .Float, &value))
SetData(instance, scriptField, value);
case .Struct:
{
var v = Mono.mono_field_get_value_object(ScriptEngine.[Friend]s_AppDomain, scriptField.[Friend]_monoField, (.)instance);
void* dataPtr = Mono.mono_object_unbox(v);
Span<uint8> data = .((.)dataPtr, scriptField.SizeInBytes);
if (ImGui.CollapsingHeader(fieldName.Ptr))
{
DoFunnyStuff(dataPtr, scriptField.SharpType);
}
SetData<MonoObject>(instance, scriptField, v);
//Mono.mono_field_set_value_object(ScriptEngine.[Friend]s_AppDomain, scriptField.[Friend]_monoField, (.)instance);
//uint8* data = ;
/*uint8[] data = scope .[scriptField.SizeInBytes];
GetData(instance, scriptField, data.Ptr);
if (ImGui.CollapsingHeader(fieldName.Ptr))
{
DoFunnyStuff(data.Ptr, scriptField.SharpType);
}
MonoObject* boxed = Mono.mono_value_box(ScriptEngine.[Friend]s_AppDomain, ((SharpClass)scriptField.SharpType).[Friend]_monoClass, data.Ptr);
SetData<MonoObject>(instance, scriptField, boxed);*/
//Mono.mono_field_get_value(instance, scriptField.[Friend]_monoField, data.Ptr);
}
default:
//Log.EngineLogger.Error($"Unhandled field type {scriptField.FieldType}");
}
}
}
DoFunnyStuff(scriptInstance.[Friend]_instance, sharpClass);*/
for (let (fieldName, scriptField) in sharpClass.Fields) for (let (fieldName, scriptField) in sharpClass.Fields)
{ {
var monoField = scriptField.[Friend]_monoField; var monoField = scriptField.[Friend]_monoField;
@@ -592,6 +672,22 @@ namespace GlitchyEditor.EditWindows
// TODO! // TODO!
case .Struct: case .Struct:
// TODO! // TODO!
/*{
uint8[] data = scope .[scriptField.SizeInBytes];
Mono.mono_field_get_value(scriptInstance.[Friend]_instance, scriptField.[Friend]_monoField, data.Ptr);
//scriptField.
//scriptInstance.GetFieldValue();
//scriptInstance.ScriptClass.Fields[]
/*
var value = GetFieldValue<double>(scriptInstance, scriptField);
if (ImGui.DragScalar(fieldName.ToScopeCStr!(), .Double, &value))
SetFieldValue(scriptInstance, scriptField, value);
*/
}*/
default: default:
Log.EngineLogger.Error($"Unhandled field type {scriptField.FieldType}"); Log.EngineLogger.Error($"Unhandled field type {scriptField.FieldType}");
} }
@@ -601,107 +697,111 @@ namespace GlitchyEditor.EditWindows
{ {
let scriptFields = ScriptEngine.GetScriptFieldMap(entity); let scriptFields = ScriptEngine.GetScriptFieldMap(entity);
for (var (name, field) in ref scriptFields) for (var (fieldName, field) in ref scriptFields)
{ {
switch (field.Type) switch (field.Type)
{ {
case .Bool: case .Bool:
var value = field.GetData<bool>(); var value = field.GetData<bool>();
if (ImGui.Checkbox(name.CStr(), &value)) if (ImGui.Checkbox(fieldName.CStr(), &value))
field.SetData(value); field.SetData(value);
case .SByte: case .SByte:
var value = field.GetData<int8>(); var value = field.GetData<int8>();
if (ImGui.DragScalar(name.CStr(), .S8, &value)) if (ImGui.DragScalar(fieldName.CStr(), .S8, &value))
field.SetData(value); field.SetData(value);
case .Short: case .Short:
var value = field.GetData<int16>(); var value = field.GetData<int16>();
if (ImGui.DragScalar(name.CStr(), .S16, &value)) if (ImGui.DragScalar(fieldName.CStr(), .S16, &value))
field.SetData(value); field.SetData(value);
case .Int: case .Int:
var value = field.GetData<int32>(); var value = field.GetData<int32>();
if (ImGui.DragScalar(name.CStr(), .S32, &value)) if (ImGui.DragScalar(fieldName.CStr(), .S32, &value))
field.SetData(value); field.SetData(value);
case .Int2: case .Int2:
var value = field.GetData<int2>(); var value = field.GetData<int2>();
if (ImGui.DragScalarN(name.CStr(), .S32, &value, 2)) if (ImGui.DragScalarN(fieldName.CStr(), .S32, &value, 2))
field.SetData(value); field.SetData(value);
case .Int3: case .Int3:
var value = field.GetData<int3>(); var value = field.GetData<int3>();
if (ImGui.DragScalarN(name.CStr(), .S32, &value, 3)) if (ImGui.DragScalarN(fieldName.CStr(), .S32, &value, 3))
field.SetData(value); field.SetData(value);
case .Int4: case .Int4:
var value = field.GetData<int4>(); var value = field.GetData<int4>();
if (ImGui.DragScalarN(name.CStr(), .S32, &value, 4)) if (ImGui.DragScalarN(fieldName.CStr(), .S32, &value, 4))
field.SetData(value); field.SetData(value);
case .Long: case .Long:
var value = field.GetData<int64>(); var value = field.GetData<int64>();
if (ImGui.DragScalar(name.CStr(), .S64, &value)) if (ImGui.DragScalar(fieldName.CStr(), .S64, &value))
field.SetData(value); field.SetData(value);
case .Byte: case .Byte:
var value = field.GetData<uint8>(); var value = field.GetData<uint8>();
if (ImGui.DragScalar(name.CStr(), .U8, &value)) if (ImGui.DragScalar(fieldName.CStr(), .U8, &value))
field.SetData(value); field.SetData(value);
case .UShort: case .UShort:
var value = field.GetData<uint16>(); var value = field.GetData<uint16>();
if (ImGui.DragScalar(name.CStr(), .U16, &value)) if (ImGui.DragScalar(fieldName.CStr(), .U16, &value))
field.SetData(value); field.SetData(value);
case .UInt: case .UInt:
var value = field.GetData<uint32>(); var value = field.GetData<uint32>();
if (ImGui.DragScalar(name.CStr(), .U32, &value)) if (ImGui.DragScalar(fieldName.CStr(), .U32, &value))
field.SetData(value); field.SetData(value);
case .ULong: case .ULong:
var value = field.GetData<uint64>(); var value = field.GetData<uint64>();
if (ImGui.DragScalar(name.CStr(), .U64, &value)) if (ImGui.DragScalar(fieldName.CStr(), .U64, &value))
field.SetData(value); field.SetData(value);
case .Float: case .Float:
var value = field.GetData<float>(); var value = field.GetData<float>();
if (ImGui.DragScalar(name.CStr(), .Float, &value)) if (ImGui.DragScalar(fieldName.CStr(), .Float, &value))
field.SetData(value); field.SetData(value);
case .float2: case .float2:
var value = field.GetData<float2>(); var value = field.GetData<float2>();
if (ImGui.Editfloat2(name, ref value)) if (ImGui.Editfloat2(fieldName, ref value))
field.SetData(value); field.SetData(value);
case .float3: case .float3:
var value = field.GetData<float3>(); var value = field.GetData<float3>();
if (ImGui.Editfloat3(name, ref value)) if (ImGui.Editfloat3(fieldName, ref value))
field.SetData(value); field.SetData(value);
case .float4: case .float4:
var value = field.GetData<float4>(); var value = field.GetData<float4>();
if (ImGui.Editfloat4(name, ref value)) if (ImGui.Editfloat4(fieldName, ref value))
field.SetData(value); field.SetData(value);
case .Double: case .Double:
var value = field.GetData<double>(); var value = field.GetData<double>();
if (ImGui.DragScalar(name.CStr(), .Double, &value)) if (ImGui.DragScalar(fieldName.CStr(), .Double, &value))
field.SetData(value); field.SetData(value);
case .Double2: case .Double2:
var value = field.GetData<double2>(); var value = field.GetData<double2>();
if (ImGui.DragScalarN(name.CStr(), .Double, &value, 2)) if (ImGui.DragScalarN(fieldName.CStr(), .Double, &value, 2))
field.SetData(value); field.SetData(value);
case .Double3: case .Double3:
var value = field.GetData<double3>(); var value = field.GetData<double3>();
if (ImGui.DragScalarN(name.CStr(), .Double, &value, 3)) if (ImGui.DragScalarN(fieldName.CStr(), .Double, &value, 3))
field.SetData(value); field.SetData(value);
case .Double4: case .Double4:
var value = field.GetData<double4>(); var value = field.GetData<double4>();
if (ImGui.DragScalarN(name.CStr(), .Double, &value, 4)) if (ImGui.DragScalarN(fieldName.CStr(), .Double, &value, 4))
field.SetData(value); field.SetData(value);
case .Enum: case .Enum:
// TODO! ShowEnumSelector(field, fieldName, scriptClass);
//case .String: //case .String:
// TODO! // TODO!
case .Entity: case .Entity:
// TODO! ShowEntityReceiver(field, fieldName, scriptClass);
case .Component:
ShowComponentReceiver(field, fieldName, scriptClass);
case .Struct: case .Struct:
// TODO! // TODO!
case .Class:
// We don't support editing classes
default: default:
Log.EngineLogger.Error($"Unhandled field type {field.Type}"); Log.EngineLogger.Error($"Unhandled field type {field.Type}");
} }
@@ -709,6 +809,201 @@ namespace GlitchyEditor.EditWindows
} }
} }
private static void ShowEnumSelector(ScriptFieldInstance* field, StringView fieldName, ScriptClass scriptClass)
{
ScriptField scriptField = scriptClass.Fields[fieldName];
SharpEnum enumType = scriptField.SharpType as SharpEnum;
Log.EngineLogger.Assert(enumType != null, "Enum must have a SharpEnum!");
// Simply get Enum as a uint64
var fieldValue = field.GetData<uint64>();
StringView valueName = "<Invalid Value>";
if (enumType.Values.TryGetValue(fieldValue, let enumValue))
valueName = enumValue.Name;
if (ImGui.BeginCombo(fieldName.Ptr, valueName.Ptr))
{
for (let (entryValue, enumEntry) in enumType.Values)
{
if (ImGui.Selectable(enumEntry.Name.Ptr, fieldValue == entryValue))
field.SetData(entryValue);
}
ImGui.EndCombo();
}
}
private static Entity? ShowEntitySelector()
{
static char8[128] entitySearch = .();
Entity? result = null;
if (ImGui.BeginPopup("ENTITY_SELECTOR"))
{
ImGui.TextUnformatted("Search:");
ImGui.SameLine();
if (ImGui.InputText("##entitySearcher", &entitySearch, (uint64)entitySearch.Count))
{
}
ImGui.EndPopup();
}
return result;
}
private static void ShowEntityReceiver(ScriptFieldInstance* field, StringView fieldName, ScriptClass scriptClass)
{
var entityId = field.GetData<UUID>();
Result<Entity> fieldEntity = Editor.Instance.CurrentScene.GetEntityByID(entityId);
String entityName = scope .(32);
if (entityId == UUID(0))
entityName.Set("None");
else if (fieldEntity case .Ok(Entity e))
entityName.Set(e.Name);
else
entityName..Clear().AppendF($"Missing entity ({entityId})");
ImGui.Text($"{fieldName}: ");
ImGui.SameLine();
if (ImGui.Button(entityName))
{
if (fieldEntity case .Ok)
Editor.Instance.EntityHierarchyWindow.HighlightEntity(fieldEntity);
}
if (ImGui.BeginDragDropTarget())
{
ImGui.Payload* peekPayload = ImGui.AcceptDragDropPayload(.Entity, .AcceptPeekOnly);
bool allowDrop = false;
if (peekPayload != null)
{
Entity draggedEntity = *(Entity*)peekPayload.Data;
ScriptClass draggedScriptClass = ScriptEngine.[Friend]s_EntityRoot;
if (draggedEntity.TryGetComponent<ScriptComponent>(let draggedScript))
{
var draggedClassName = draggedScript.ScriptClassName;
draggedScriptClass = ScriptEngine.GetScriptClass(draggedClassName);
}
// TODO: I don't like the fact, that we are using mono directly
ScriptField scriptField = scriptClass.Fields[fieldName];
var fieldMonoClass = Mono.mono_type_get_class(scriptField.GetMonoType());
allowDrop = draggedScriptClass.[Friend]IsSubclass(fieldMonoClass);
}
if (allowDrop)
{
ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.Entity);
if (payload != null)
{
Log.EngineLogger.AssertDebug(payload.DataSize == sizeof(Entity));
Entity droppedEntity = *(Entity*)payload.Data;
if (droppedEntity.IsValid)
field.SetData<UUID>(droppedEntity.UUID);
}
}
ImGui.EndDragDropTarget();
}
}
//private static Entity?
private static void ShowComponentReceiver(ScriptFieldInstance* field, StringView fieldName, ScriptClass scriptClass)
{
var entityId = field.GetData<UUID>();
Result<Entity> fieldEntity = Editor.Instance.CurrentScene.GetEntityByID(entityId);
String entityName = scope .(32);
if (entityId == UUID(0))
entityName.Set("None");
else if (fieldEntity case .Ok(Entity e))
entityName.Set(e.Name);
else
entityName..Clear().AppendF($"Missing reference ({entityId})");
ImGui.Text($"{fieldName}: ");
ImGui.SameLine();
if (ImGui.Button(entityName))
{
if (fieldEntity case .Ok)
Editor.Instance.EntityHierarchyWindow.HighlightEntity(fieldEntity);
}
if (ImGui.BeginDragDropTarget())
{
ImGui.Payload* peekPayload = ImGui.AcceptDragDropPayload(.Entity, .AcceptPeekOnly);
bool allowDrop = false;
if (peekPayload != null)
{
Entity draggedEntity = *(Entity*)peekPayload.Data;
// TODO: I don't like the fact, that we are using mono directly
ScriptField scriptField = scriptClass.Fields[fieldName];
// For some reason we have to retrieve the MonoType like this. Using scriptField.GetMonoType() directly returns the wrong type...
MonoReflectionType* reflectionType = Mono.mono_type_get_object(ScriptEngine.[Friend]s_AppDomain, scriptField.GetMonoType());
MonoType* actualMonoType = Mono.mono_reflection_type_get_type(reflectionType);
// TODO: We shouldn't abuse the script glue like that.
// ScriptGlue should only be called by C#, not by Beef.
if (ScriptGlue.[Friend]s_HasComponentMethods.TryGetValue(actualMonoType, let has_component))
{
allowDrop = has_component(draggedEntity);
}
else
{
Log.EngineLogger.Warning($"No HasComponent-Function found for field {scriptField.Name}");
allowDrop = false;
}
}
if (allowDrop)
{
ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.Entity);
if (payload != null)
{
Log.EngineLogger.AssertDebug(payload.DataSize == sizeof(Entity));
Entity droppedEntity = *(Entity*)payload.Data;
if (droppedEntity.IsValid)
field.SetData<UUID>(droppedEntity.UUID);
}
}
ImGui.EndDragDropTarget();
}
}
private static void LabelColumn(StringView label) private static void LabelColumn(StringView label)
{ {
ImGui.TextUnformatted(label); ImGui.TextUnformatted(label);
@@ -773,7 +1068,7 @@ namespace GlitchyEditor.EditWindows
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -270,7 +270,7 @@ namespace GlitchyEditor.EditWindows
SubTexture2D image = s_FolderTexture; SubTexture2D image = s_FolderTexture;
ImGui.ImageButton(image, (.)(DirectoryItemSize - padding)); ImGui.ImageButton("", image, (.)(DirectoryItemSize - padding));
ImGui.PopStyleColor(); ImGui.PopStyleColor();
@@ -310,7 +310,7 @@ namespace GlitchyEditor.EditWindows
// TODO: preview images // TODO: preview images
SubTexture2D image = entry->IsDirectory ? s_FolderTexture : s_FileTexture; SubTexture2D image = entry->IsDirectory ? s_FolderTexture : s_FileTexture;
ImGui.ImageButton(image, (.)(DirectoryItemSize - padding)); ImGui.ImageButton("FileImage", image, (.)(DirectoryItemSize - padding));
ImGui.PopStyleColor(); ImGui.PopStyleColor();
@@ -324,7 +324,7 @@ namespace GlitchyEditor.EditWindows
Path.Fixup(fullpath); Path.Fixup(fullpath);
ImGui.SetDragDropPayload("CONTENT_BROWSER_ITEM", fullpath.CStr(), (.)fullpath.Length, .Once); ImGui.SetDragDropPayload(.ContentBrowserItem, fullpath.CStr(), (.)fullpath.Length, .Once);
ImGui.EndDragDropSource(); ImGui.EndDragDropSource();
} }
@@ -370,7 +370,7 @@ namespace GlitchyEditor.EditWindows
String fullpath = scope String(entry->Path); String fullpath = scope String(entry->Path);
fullpath.AppendF($"#{subAsset.Name}"); fullpath.AppendF($"#{subAsset.Name}");
ImGui.SetDragDropPayload("CONTENT_BROWSER_ITEM", fullpath.CStr(), (.)fullpath.Length, .Once); ImGui.SetDragDropPayload(.ContentBrowserItem, fullpath.CStr(), (.)fullpath.Length, .Once);
ImGui.EndDragDropSource(); ImGui.EndDragDropSource();
} }
@@ -137,7 +137,7 @@ namespace GlitchyEditor.EditWindows
{ {
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
@@ -21,8 +21,26 @@ namespace GlitchyEditor.EditWindows
private List<Entity> _selectedEntities = new .() ~ delete _; private List<Entity> _selectedEntities = new .() ~ delete _;
private Entity _entityToHighlight;
public List<Entity> SelectedEntities => _selectedEntities; public List<Entity> SelectedEntities => _selectedEntities;
private List<Entity> _entitiesToUnfold = new .() ~ delete _;
public void HighlightEntity(Entity e)
{
_entityToHighlight = e;
Entity walker = _entityToHighlight;
while (walker.Parent != null)
{
walker = walker.Parent.Value;
_entitiesToUnfold.Add(walker);
}
}
public this(Editor editor, Scene scene) public this(Editor editor, Scene scene)
{ {
_editor = editor; _editor = editor;
@@ -322,8 +340,21 @@ namespace GlitchyEditor.EditWindows
if(inSelectedList) if(inSelectedList)
flags |= .Selected; flags |= .Selected;
if (_entitiesToUnfold.Contains(tree.Value))
{
_entitiesToUnfold.Remove(tree.Value);
ImGui.SetNextItemOpen(true, .None);
}
bool isOpen = ImGui.TreeNodeEx((void*)(uint)tree.Value.Handle.[Friend]Index, flags, $"{name}"); bool isOpen = ImGui.TreeNodeEx((void*)(uint)tree.Value.Handle.[Friend]Index, flags, $"{name}");
if (_entityToHighlight == tree.Value)
{
ImGui.SetScrollHereY(0);
_entityToHighlight = .();
}
ImGui.PushID((void*)(uint)tree.Value.Handle.[Friend]Index); ImGui.PushID((void*)(uint)tree.Value.Handle.[Friend]Index);
bool deleted = false; bool deleted = false;
@@ -341,9 +372,13 @@ namespace GlitchyEditor.EditWindows
if (deleted) if (deleted)
return; return;
bool isDragged = false;
if(ImGui.BeginDragDropSource()) if(ImGui.BeginDragDropSource())
{ {
ImGui.SetDragDropPayload("DND_Entity", &tree.Value, sizeof(Entity)); isDragged = true;
ImGui.SetDragDropPayload(.Entity, &tree.Value, sizeof(Entity));
ImGui.Text(name); ImGui.Text(name);
@@ -352,7 +387,7 @@ namespace GlitchyEditor.EditWindows
if(ImGui.BeginDragDropTarget()) if(ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("DND_Entity"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.Entity);
if(payload != null) if(payload != null)
{ {
@@ -407,6 +442,12 @@ namespace GlitchyEditor.EditWindows
} }
if (clicked || clickedRight) if (clicked || clickedRight)
{
lastClickedEntity = tree.Value;
}
//if (!isDragged && (clicked || clickedRight))
if (!isDragged && (!ImGui.IsMouseDown(.Left) && !ImGui.IsMouseDown(.Right) && ImGui.IsItemHovered()) && tree.Value == lastClickedEntity)
{ {
if (inSelectedList && !clickedRight) if (inSelectedList && !clickedRight)
{ {
@@ -418,9 +459,13 @@ namespace GlitchyEditor.EditWindows
SelectEntity(tree.Value, !ImGui.GetIO().KeyCtrl && !clickedRight); SelectEntity(tree.Value, !ImGui.GetIO().KeyCtrl && !clickedRight);
inSelectedList = true; inSelectedList = true;
} }
lastClickedEntity = .();
} }
} }
private static Entity lastClickedEntity;
private void ShowEntityHierarchy() private void ShowEntityHierarchy()
{ {
StringView searchString = StringView(&_entitySearchChars); StringView searchString = StringView(&_entitySearchChars);
@@ -464,7 +509,7 @@ namespace GlitchyEditor.EditWindows
{ {
if(ImGui.BeginDragDropTarget()) if(ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("DND_Entity"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.Entity);
if(payload != null) if(payload != null)
{ {
@@ -527,6 +572,10 @@ namespace GlitchyEditor.EditWindows
ImGuiPrintEntityTree(scope .(entity)); ImGuiPrintEntityTree(scope .(entity));
} }
} }
// If the mouse was released and no entity took the chance to become selected we probably hovered the background while releasing -> select no entity
if (!ImGui.IsMouseDown(.Left) && !ImGui.IsMouseDown(.Right))
lastClickedEntity = .();
} }
} }
} }
@@ -91,7 +91,7 @@ namespace GlitchyEditor.EditWindows
{ {
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM"); ImGui.Payload* payload = ImGui.AcceptDragDropPayload(.ContentBrowserItem);
if (payload != null) if (payload != null)
{ {
+375
View File
@@ -0,0 +1,375 @@
using System;
using ImGui;
using System.Collections;
using GlitchyEngine.Core;
using GlitchyEngine.World;
using GlitchLog;
using GlitchyEngine.Scripting;
using GlitchyEngine.Renderer;
namespace GlitchyEditor.EditWindows;
enum MessageType
{
case None = 0;
case Trace = 1;
case Info = 2;
case Warning = 4;
case Error = 8;
public this(LogLevel level)
{
switch (level)
{
case .Error:
this = Error;
case .Warning:
this = Warning;
case .Info:
this = Info;
case .Trace:
this = Trace;
default:
this = None;
}
}
}
class MessageSource
{
public UUID? Entity = null;
public StringView? ScriptName = null;
public int? Line = null;
/// If true, the message is only meant for engine developers... so only me :(
public bool IsEngineMessage = false;
public MonoExceptionHelper Exception = null ~ _?.ReleaseRef();
public String AdditionalData = null ~ delete _;
}
class LogMessage
{
private String _message ~ delete _;
public MessageType MessageType { get; private set; }
public DateTime Timestamp { get; private set; }
public MessageSource Source { get; private set; } ~ delete _;
public StringView Message => _message;
public this(DateTime timestamp, StringView message, MessageType logLevel, MessageSource ownSource)
{
Timestamp = timestamp;
_message = new String(message);
MessageType = logLevel;
Source = ownSource;
}
}
class LogWindow : EditorWindow
{
public const String s_WindowTitle = "Log";
private append List<LogMessage> _messages = .() ~ ClearAndDeleteItems!(_);
public static SubTexture2D s_ErrorIcon;
public static SubTexture2D s_WarningIcon;
public static SubTexture2D s_InfoIcon;
public static SubTexture2D s_TraceIcon;
private bool _showGameMessages = true;
private bool _showEngineMessages = false;
private bool _autoScroll = true;
private bool _collapseMessages = true;
private MessageType _visibleMessageTypes = .Error | .Warning | .Info | .Trace;
protected override void InternalShow()
{
defer { ImGui.End(); }
if(!ImGui.Begin(s_WindowTitle, &_open, .MenuBar))
return;
ShowMenuBar();
ShowMessages();
}
private void ShowMenuBar()
{
if(ImGui.BeginMenuBar())
{
if (ImGui.MenuItem("Clear"))
{
ClearLog();
}
if (ImGui.BeginMenu("Filter"))
{
ImGui.Checkbox("Show game messages", &_showGameMessages);
ImGui.AttachTooltip("If checked, the log will show messages generated by the game (e.g. scripts).");
ImGui.Checkbox("Show engine messages", &_showEngineMessages);
ImGui.AttachTooltip("""
If checked, the log will show messages generated by the engine.
These messages are usually only necessary for engine debugging/development and don't provide practical information for game developers.
""");
ImGui.EndMenu();
}
ImGui.Checkbox("Collapse", &_collapseMessages);
ImGui.AttachTooltip("If checked, identical messages will be collapsed into one.");
var maxSpace = ImGui.GetFontSize();
ImGui.Vec2 buttonSize = .(maxSpace, maxSpace);
var col = ImGui.GetStyleColorVec4(.Button);
ImGui.PushStyleVar(.FramePadding, ImGui.Vec2(2, 2));
if (_visibleMessageTypes.HasFlag(.Trace))
ImGui.PushStyleColor(.Button, *col);
else
ImGui.PushStyleColor(.Button, .(0, 0, 0, 0));
if (ImGui.ImageButtonEx(1, s_TraceIcon, buttonSize, .Zero, .Ones))
_visibleMessageTypes ^= .Trace;
ImGui.PopStyleColor();
if (_visibleMessageTypes.HasFlag(.Info))
ImGui.PushStyleColor(.Button, *col);
else
ImGui.PushStyleColor(.Button, .(0, 0, 0, 0));
if (ImGui.ImageButtonEx(2, s_InfoIcon, buttonSize, .Zero, .Ones))
_visibleMessageTypes ^= .Info;
ImGui.PopStyleColor();
if (_visibleMessageTypes.HasFlag(.Warning))
ImGui.PushStyleColor(.Button, *col);
else
ImGui.PushStyleColor(.Button, .(0, 0, 0, 0));
if (ImGui.ImageButtonEx(3, s_WarningIcon, buttonSize, .Zero, .Ones))
_visibleMessageTypes ^= .Warning;
ImGui.PopStyleColor();
if (_visibleMessageTypes.HasFlag(.Error))
ImGui.PushStyleColor(.Button, *col);
else
ImGui.PushStyleColor(.Button, .(0, 0, 0, 0));
if (ImGui.ImageButtonEx(4, s_ErrorIcon, buttonSize, .Zero, .Ones))
_visibleMessageTypes ^= .Error;
ImGui.PopStyleColor();
ImGui.PopStyleVar();
ImGui.EndMenuBar();
}
}
private void ShowMessages()
{
if (ImGui.BeginTable("Messages", 3, .BordersInnerH | .SizingFixedFit))
{
ImGui.TableSetupColumn("", .WidthFixed);
ImGui.TableSetupColumn("", .WidthStretch);
ImGui.TableSetupColumn("", .WidthFixed);
//LogMessage lastMessage = null;
int count = 1;
// Message ID for ImGui
int imGuiMessageId = 0;
for (let message in _messages)
{
if (!_visibleMessageTypes.HasFlag(message.MessageType))
continue;
if ((message.Source.IsEngineMessage && !_showEngineMessages) || (!message.Source.IsEngineMessage && !_showGameMessages))
continue;
/*defer
{
lastMessage = message;
}*/
do
{
LogMessage lastMessage = (message != _messages.Back) ? _messages[@message.Index + 1] : null;
if (_collapseMessages && lastMessage != null)
{
if (message.MessageType != lastMessage.MessageType)
break;
if (message.Message != lastMessage.Message)
break;
if (message.Source.Entity != lastMessage.Source.Entity)
break;
// For exceptions the stack trace is basically the only relevant thing
if (message.Source.Exception?.StackTrace != lastMessage.Source.Exception?.StackTrace)
break;
// We collapse this message with the previous one:
// Increment counter and go to next message.
count++;
continue;
}
}
// Push current index as ID
ImGui.PushID((void*)++imGuiMessageId);
ImGui.TableNextRow();
ImGui.TableSetColumnIndex(0);
switch (message.MessageType)
{
case .Error:
ImGui.Image(s_ErrorIcon, ImGui.Vec2(32, 32));
ImGui.AttachTooltip("Error");
case .Warning:
ImGui.Image(s_WarningIcon, ImGui.Vec2(32, 32));
ImGui.AttachTooltip("Warning");
case .Info:
ImGui.Image(s_InfoIcon, ImGui.Vec2(32, 32));
ImGui.AttachTooltip("Info");
case .Trace:
ImGui.Image(s_TraceIcon, ImGui.Vec2(32, 32));
ImGui.AttachTooltip("Trace");
default:
ImGui.TextUnformatted("Unknown");
}
ImGui.TableNextColumn();
// Timestamp
ImGui.TextWrapped($"[{message.Timestamp:HH:mm:ss.fff}]");
if (message.Source.IsEngineMessage)
{
ImGui.SameLine();
ImGui.TextUnformatted("Engine");
}
// Show entity
if (message.Source?.Entity != null)
{
ImGui.SameLine();
Result<Entity> entity = Editor.Instance.CurrentScene.GetEntityByID(message.Source.Entity.Value);
if (entity case .Ok(let e))
{
ImGui.Text($"Entity: \"{e.Name}\" (ID: {message.Source.Entity})");
if (ImGui.IsItemClicked())
Editor.Instance.EntityHierarchyWindow.HighlightEntity(entity);
}
else
{
ImGui.Text($"Entity: (ID: {message.Source.Entity})");
}
}
if (message.Source.Exception != null)
{
if (ImGui.CollapsingHeader(message.Message.Ptr))
{
// Show the native to managed entry point only if we show engine messages
if (_showEngineMessages)
ImGui.TextUnformatted(message.Source.Exception.StackTrace);
else
ImGui.TextUnformatted(message.Source.Exception.CleanStackTrace);
ImGui.NewLine();
}
}
else
{
ImGui.TextUnformatted(message.Message);
}
// Dont show the counter if we only have one message.
if (count > 1)
{
// the message is not collapsible with the previous one.
// Print message count for last message and reset counter.
// This message will be printed normally.
ImGui.TableNextColumn();
ImGui.Text($"{count}");
}
count = 1;
ImGui.PopID();
}
if (_autoScroll)
{
if (ImGui.GetIO().MouseWheel > 0)
{
_autoScroll = false;
}
else
{
ImGui.SetScrollY(ImGui.GetScrollMaxY());
}
}
else
{
if (ImGui.GetScrollMaxY() == ImGui.GetScrollY())
{
_autoScroll = true;
}
}
ImGui.EndTable();
}
}
public void ClearLog()
{
ClearAndDeleteItems!(_messages);
}
public void Log(DateTime timestamp, LogLevel severity, StringView message, MessageSource source)
{
LogMessage logMessage = new LogMessage(timestamp, message, MessageType(severity), source);
_messages.Add(logMessage);
}
public void LogException(DateTime timestamp, MonoExceptionHelper exception)
{
StringView firstLine = exception.StackTrace;
int firstInIndex = exception.StackTrace.IndexOf("\n");
if (firstInIndex != -1)
firstLine = firstLine.Substring(0, firstInIndex);
String message = scope .(128);
message.AppendF($"Exception: \"{exception.FullName}\" | Message: \"{exception.Message}\" {firstLine}\0");
// TODO: are mono exceptions never engine only?
LogMessage logMessage = new LogMessage(timestamp, message, .Error, new MessageSource(){Entity = exception.Instance, Exception = exception..AddRef(), IsEngineMessage = false});
_messages.Add(logMessage);
}
}
+16
View File
@@ -22,6 +22,7 @@ namespace GlitchyEditor
private ContentBrowserWindow _contentBrowserWindow ~ delete _; private ContentBrowserWindow _contentBrowserWindow ~ delete _;
private PropertiesWindow _propertiesWindow ~ delete _; private PropertiesWindow _propertiesWindow ~ delete _;
private AssetViewer _assetViewer ~ delete _; private AssetViewer _assetViewer ~ delete _;
private LogWindow _logWindow ~ delete _;
public Scene CurrentScene public Scene CurrentScene
{ {
@@ -45,6 +46,7 @@ namespace GlitchyEditor
public ContentBrowserWindow ContentBrowserWindow => _contentBrowserWindow; public ContentBrowserWindow ContentBrowserWindow => _contentBrowserWindow;
public PropertiesWindow PropertiesWindow => _propertiesWindow; public PropertiesWindow PropertiesWindow => _propertiesWindow;
public AssetViewer AssetViewer => _assetViewer; public AssetViewer AssetViewer => _assetViewer;
public LogWindow LogWindow => _logWindow;
public EditorCamera* CurrentCamera { get; set; } public EditorCamera* CurrentCamera { get; set; }
@@ -53,15 +55,27 @@ namespace GlitchyEditor
public SceneRenderer GameSceneRenderer {get; set;} public SceneRenderer GameSceneRenderer {get; set;}
public SceneRenderer EditorSceneRenderer {get; set;} public SceneRenderer EditorSceneRenderer {get; set;}
private static Editor s_Instance;
public static Editor Instance => s_Instance;
/// Creates a new editor for the given world /// Creates a new editor for the given world
public this(Scene scene, EditorContentManager contentManager) public this(Scene scene, EditorContentManager contentManager)
{ {
Log.EngineLogger.AssertDebug(s_Instance == null, "Cannot create a second instance of a singleton.");
s_Instance = this;
_scene = scene; _scene = scene;
_contentManager = contentManager; _contentManager = contentManager;
InitWindows(); InitWindows();
} }
public ~this()
{
s_Instance = null;
}
private void InitWindows() private void InitWindows()
{ {
_sceneViewportWindow = new EditorViewportWindow(this); _sceneViewportWindow = new EditorViewportWindow(this);
@@ -71,6 +85,7 @@ namespace GlitchyEditor
_contentBrowserWindow = new ContentBrowserWindow((.)Application.Get().ContentManager); _contentBrowserWindow = new ContentBrowserWindow((.)Application.Get().ContentManager);
_propertiesWindow = new PropertiesWindow(this); _propertiesWindow = new PropertiesWindow(this);
_assetViewer = new AssetViewer((.)Application.Get().ContentManager); _assetViewer = new AssetViewer((.)Application.Get().ContentManager);
_logWindow = new LogWindow();
} }
public void Update() public void Update()
@@ -82,6 +97,7 @@ namespace GlitchyEditor
_contentBrowserWindow.Show(); _contentBrowserWindow.Show();
_propertiesWindow.Show(); _propertiesWindow.Show();
_assetViewer.Show(); _assetViewer.Show();
_logWindow.Show();
} }
} }
} }
+3
View File
@@ -12,6 +12,9 @@ namespace GlitchyEditor
public this(String[] args) public this(String[] args)
{ {
PushLayer(new EditorLayer(args, _contentManager)); PushLayer(new EditorLayer(args, _contentManager));
Log.ClientLogger = new EditorLogger();
Log.EngineLogger = new EditorLogger() { IsEngineLogger = true };
} }
protected override IContentManager InitContentManager() protected override IContentManager InitContentManager()
+8
View File
@@ -19,6 +19,10 @@ namespace GlitchyEditor
public SubTexture2D Simulate ~ _.ReleaseRef(); public SubTexture2D Simulate ~ _.ReleaseRef();
public SubTexture2D Pause ~ _.ReleaseRef(); public SubTexture2D Pause ~ _.ReleaseRef();
public SubTexture2D SingleStep ~ _.ReleaseRef(); public SubTexture2D SingleStep ~ _.ReleaseRef();
public SubTexture2D Error ~ _.ReleaseRef();
public SubTexture2D Warning ~ _.ReleaseRef();
public SubTexture2D Info ~ _.ReleaseRef();
public SubTexture2D Trace ~ _.ReleaseRef();
public SamplerState SamplerState public SamplerState SamplerState
{ {
@@ -41,6 +45,10 @@ namespace GlitchyEditor
Simulate = GetNextGridTexture(ref pen, iconSize); Simulate = GetNextGridTexture(ref pen, iconSize);
Pause = GetNextGridTexture(ref pen, iconSize); Pause = GetNextGridTexture(ref pen, iconSize);
SingleStep = GetNextGridTexture(ref pen, iconSize); SingleStep = GetNextGridTexture(ref pen, iconSize);
Error = GetNextGridTexture(ref pen, iconSize);
Warning = GetNextGridTexture(ref pen, iconSize);
Info = GetNextGridTexture(ref pen, iconSize);
Trace = GetNextGridTexture(ref pen, iconSize);
} }
private SubTexture2D GetNextGridTexture(ref float2 pen, float2 iconSize) private SubTexture2D GetNextGridTexture(ref float2 pen, float2 iconSize)
+18 -15
View File
@@ -171,6 +171,11 @@ namespace GlitchyEditor
ContentBrowserWindow.s_FolderTexture = _editorIcons.Folder; ContentBrowserWindow.s_FolderTexture = _editorIcons.Folder;
ContentBrowserWindow.s_FileTexture = _editorIcons.File; ContentBrowserWindow.s_FileTexture = _editorIcons.File;
LogWindow.s_ErrorIcon = _editorIcons.Error;
LogWindow.s_WarningIcon = _editorIcons.Warning;
LogWindow.s_InfoIcon = _editorIcons.Info;
LogWindow.s_TraceIcon = _editorIcons.Trace;
} }
private void InitEditor() private void InitEditor()
@@ -365,17 +370,8 @@ namespace GlitchyEditor
dispatcher.Dispatch<MouseScrolledEvent>(scope (e) => OnMouseScrolled(e)); dispatcher.Dispatch<MouseScrolledEvent>(scope (e) => OnMouseScrolled(e));
} }
ImGui.ID _mainDockspaceId;
TextureViewer viewer = new TextureViewer() ~ delete _;
private bool OnImGuiRender(ImGuiRenderEvent event) private bool OnImGuiRender(ImGuiRenderEvent event)
{ {
// TODO: make window
//Input.ImGuiDebugDraw();
//viewer.ViewTexture(Renderer.[Friend]_gBuffer.Target);
ImGui.Viewport* viewport = ImGui.GetMainViewport(); ImGui.Viewport* viewport = ImGui.GetMainViewport();
ImGui.DockSpaceOverViewport(viewport); ImGui.DockSpaceOverViewport(viewport);
@@ -428,16 +424,20 @@ namespace GlitchyEditor
ImGui.SameLine(); ImGui.SameLine();
ImGui.SetCursorPosX(centerX - totalWidth / 2); ImGui.SetCursorPosX(centerX - totalWidth / 2);
if (ImGui.ImageButton(_editorIcons.Play, .(size, size), .Zero, .Ones, 0)) ImGui.PushID(0);
if (ImGui.ImageButton("", _editorIcons.Play, .(size, size), .Zero, .Ones))
OnScenePlay(); OnScenePlay();
ImGui.PopID();
ImGui.AttachTooltip("Play the game."); ImGui.AttachTooltip("Play the game.");
ImGui.SameLine(); ImGui.SameLine();
ImGui.PushID(1); ImGui.PushID(1);
if (ImGui.ImageButton(_editorIcons.Simulate, .(size, size), .Zero, .Ones, 0)) if (ImGui.ImageButton("", _editorIcons.Simulate, .(size, size), .Zero, .Ones))
OnSceneSimulate(); OnSceneSimulate();
ImGui.PopID(); ImGui.PopID();
@@ -456,7 +456,7 @@ namespace GlitchyEditor
//ImGui.SameLine(penX += size + 2 * padding); //ImGui.SameLine(penX += size + 2 * padding);
ImGui.SameLine(); ImGui.SameLine();
if (ImGui.ImageButton(_editorIcons.Pause, .(size, size), .Zero, .Ones, 0)) if (ImGui.ImageButton("", _editorIcons.Pause, .(size, size), .Zero, .Ones))
_isPaused = !_isPaused; _isPaused = !_isPaused;
ImGui.PopID(); ImGui.PopID();
@@ -480,7 +480,7 @@ namespace GlitchyEditor
SubTexture2D pauseButtonIcon = _isPaused ? _editorIcons.Play : _editorIcons.Pause; SubTexture2D pauseButtonIcon = _isPaused ? _editorIcons.Play : _editorIcons.Pause;
if (ImGui.ImageButton(pauseButtonIcon, .(size, size), .Zero, .Ones, 0)) if (ImGui.ImageButton("PlayPause", pauseButtonIcon, .(size, size), .Zero, .Ones))
{ {
if (_isPaused) if (_isPaused)
OnSceneResume(); OnSceneResume();
@@ -498,7 +498,7 @@ namespace GlitchyEditor
SubTexture2D singleStepButtonIcon = _editorIcons.SingleStep; SubTexture2D singleStepButtonIcon = _editorIcons.SingleStep;
if (ImGui.ImageButton(singleStepButtonIcon, .(size, size), .Zero, .Ones, 0)) if (ImGui.ImageButton("Step", singleStepButtonIcon, .(size, size), .Zero, .Ones))
{ {
DoSingleStep(); DoSingleStep();
} }
@@ -529,7 +529,7 @@ namespace GlitchyEditor
ImGui.SameLine(); ImGui.SameLine();
ImGui.PushID(1); ImGui.PushID(1);
if (ImGui.ImageButton(_editorIcons.Stop, .(size, size), .Zero, .Ones, 0)) if (ImGui.ImageButton("Stop", _editorIcons.Stop, .(size, size), .Zero, .Ones))
OnSceneStop(); OnSceneStop();
ImGui.PopID(); ImGui.PopID();
@@ -808,6 +808,9 @@ namespace GlitchyEditor
if(ImGui.MenuItem(AssetViewer.s_WindowTitle)) if(ImGui.MenuItem(AssetViewer.s_WindowTitle))
_editor.AssetViewer.Open = true; _editor.AssetViewer.Open = true;
if(ImGui.MenuItem(LogWindow.s_WindowTitle))
_editor.LogWindow.Open = true;
ImGui.EndMenu(); ImGui.EndMenu();
} }
+128
View File
@@ -0,0 +1,128 @@
using GlitchLog;
using System;
using System.Diagnostics;
using GlitchyEngine.Scripting;
namespace GlitchyEditor;
public class EditorLogger : Logger
{
// {l} = log level (first parameter)
// {t} = current date time (second parameter)
// {n} = logger name (third parameter)
// {m} = message
private String _name;
public override String Name
{
get => _name;
set => _name = value;
}
public bool IsEngineLogger {get; set;}
public this()
{
//Debug.Assert(Debug.IsDebuggerPresent, "The DebugLogger requires a debugger to be present.");
}
#if GL_NOLOG || GL_LOG_NOTRACE
[SkipCall]
#endif
[Inline]
public override void Trace(StringView format, params Object[] args)
{
InternalLog(.Trace, format, params args);
}
#if GL_NOLOG || GL_LOG_NOINFO
[SkipCall]
#endif
[Inline]
public override void Info(StringView format, params Object[] args)
{
InternalLog(.Info, format, params args);
}
#if GL_NOLOG || GL_LOG_NOWARNING
[SkipCall]
#endif
[Inline]
public override void Warning(StringView format, params Object[] args)
{
InternalLog(.Warning, format, params args);
}
#if GL_NOLOG || GL_LOG_NOERROR
[SkipCall]
#endif
[Inline]
public override void Error(StringView format, params Object[] args)
{
InternalLog(.Error, format, params args);
}
#if GL_NOLOG || GL_LOG_NOCRITICAL
[SkipCall]
#endif
[Inline]
public override void Critical(StringView format, params Object[] args)
{
InternalLog(.Critical, format, params args);
}
#if GL_NOLOG
[SkipCall]
#endif
[Inline]
public override void Log(LogLevel level, StringView format, params Object[] args)
{
InternalLog(level, format, params args);
}
public override void Assert(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
{
if (!condition)
{
String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath);
InternalLog(.Critical, failStr);
Internal.FatalError(failStr, 1);
}
}
public override void AssertDebug(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
{
if (!condition)
{
String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath);
InternalLog(.Critical, failStr);
Internal.FatalError(failStr, 1);
}
}
private void InternalLog(LogLevel level, StringView format, params Object[] args)
{
if(_logLevel > level)
return;
DateTime timestamp = DateTime.Now;
String message = scope String(4096);
message.AppendF(format, params args);
Debug.Write($"[{timestamp:HH:mm:ss.fff}] ({_name})|{level.UpperString}: {message}");
if (Editor.Instance == null)
return;
if (args.Count > 0 && (var ex = args[^1] as MonoExceptionHelper))
{
Editor.Instance.LogWindow.LogException(timestamp, ex);
}
else
{
Editor.Instance.LogWindow.Log(timestamp, level, message, new .() {IsEngineMessage = IsEngineLogger});
}
}
}
+33
View File
@@ -0,0 +1,33 @@
using System;
namespace ImGui;
enum DragDropPayloadType
{
case ContentBrowserItem;
case Entity;
public String GetName()
{
switch (this)
{
case .ContentBrowserItem:
return "CONTENT_BROWSER_ITEM";
case .Entity:
return "ENTITY";
}
}
}
extension ImGui
{
public static Payload* AcceptDragDropPayload(DragDropPayloadType type, DragDropFlags flags = .None)
{
return AcceptDragDropPayload(type.GetName(), flags);
}
public static bool SetDragDropPayload(DragDropPayloadType type, void* data, size sz, Cond cond = .None)
{
return SetDragDropPayload(type.GetName(), data, sz, cond);
}
}
-247
View File
@@ -1,247 +0,0 @@
using GlitchyEngine.Renderer;
using GlitchyEngine;
using ImGui;
using GlitchyEngine.Math;
using System;
namespace GlitchyEditor
{
class TextureViewer
{
enum BackgroundMode : int32
{
White,
Black,
Checkerboard
}
enum SampleMode : int32
{
Point,
Linear
}
GraphicsContext _context ~ _.ReleaseRef();
Effect _effect ~ _.ReleaseRef();
float _zoom = 1.0f;
BackgroundMode _backgroundMode = .Checkerboard;
SampleMode _sampleMode = .Linear;
RenderTarget2D _target ~ _?.ReleaseRef();
// TODO: we don't need depth!
DepthStencilTarget _depth ~ _?.ReleaseRef();
SamplerState _samplerPoint ~ _.ReleaseRef();
SamplerState _samplerLinear ~ _.ReleaseRef();
public this()
{
_context = Application.Get().Window.Context..AddRef();
InitEffect();
InitState();
// TODO: rasterizerstate and depthstencilstate
}
private void InitEffect()
{
_effect = new Effect("content\\Shaders\\textureViewerShader.hlsl");
}
private void InitState()
{
SamplerStateDescription desc = .();
desc.MagFilter = .Linear;
desc.MinFilter = .Linear;
_samplerLinear = SamplerStateManager.GetSampler(desc);
desc.MagFilter = .Point;
desc.MinFilter = .Point;
_samplerPoint = SamplerStateManager.GetSampler(desc);
}
float2 _position;
bool _moving;
float _colorOffset = 0;
float _colorScale = 1;
float _alphaOffset = 0;
float _alphaScale = 1;
public void ViewTexture(Texture viewedTexture)
{
ImGui.Begin("Texture Viewer");
ImGui.SliderFloat("Zoom", &_zoom, 0.01f, 100.0f);
char8*[] items = scope .("White", "Black", "Checkerboard");
ImGui.Combo("Background", (.)&_backgroundMode, items.Ptr, (.)items.Count);
items = scope .("Point", "Linear");
ImGui.Combo("Sampler", (.)&_sampleMode, items.Ptr, (.)items.Count);
ImGui.SliderFloat2("Color offset and scale", *(float[2]*)&_colorOffset, -1.0f, 1.0f);
ImGui.SliderFloat2("Alpha offset and scale", *(float[2]*)&_alphaOffset, -1.0f, 1.0f);
ImGui.SliderFloat2("Position", *(float[2]*)&_position, 2 * -Math.Max(viewedTexture.Width, viewedTexture.Height) * _zoom, 2 * Math.Max(viewedTexture.Width, viewedTexture.Height) * _zoom);
ImGui.BeginChild("imageChild");
UpdateInput();
var viewportSize = ImGui.GetContentRegionAvail();
viewportSize.x = Math.Max(viewportSize.x, 1);
viewportSize.y = Math.Max(viewportSize.y, 1);
if(_target == null || viewportSize.x != _target.Width || viewportSize.y != _target.Height)
{
_target?.ReleaseRef();
_target = new RenderTarget2D(.(.R8G8B8A8_UNorm, (.)viewportSize.x, (.)viewportSize.y));
_target.SamplerState = SamplerStateManager.PointClamp;
_depth?.ReleaseRef();
_depth = new DepthStencilTarget((.)viewportSize.x, (.)viewportSize.y, .D16_UNorm);
}
RenderTexture(viewedTexture);
ImGui.Image(_target, viewportSize);
ImGui.EndChild();
ImGui.End();
}
float lastWheel;
private void UpdateInput()
{
var windowPos = ImGui.GetWindowPos();
var mousePos = ImGui.GetIO().MousePos;
float2 mouseInWindow = .(mousePos.x - windowPos.x, mousePos.y - windowPos.y);
bool windowHovered = ImGui.IsWindowHovered();
if(windowHovered && Input.IsMouseButtonPressing(.MiddleButton))
{
_moving = true;
}
else if(Input.IsMouseButtonReleased(.MiddleButton))
{
_moving = false;
}
if(windowHovered || _moving)
{
float mouseWheel = ImGui.GetIO().MouseWheel;
float delta = mouseWheel - lastWheel;
if(delta != 0)
{
_position -= mouseInWindow;
_position /= _zoom;
_zoom *= Math.Pow(1.1f, delta);
_position *= _zoom;
_position += mouseInWindow;
}
}
if(_moving)
{
int2 movement = Input.GetMouseMovement();
_position.X += movement.X;
_position.Y += movement.Y;
}
}
OrthographicCamera _camera = new OrthographicCamera() ~ delete _;
private void RenderTexture(Texture viewedTexture)
{
Viewport vp = .(0, 0, _target.Width, _target.Height);
RenderCommand.SetViewport(vp);
// TODO: don't clear pink!
RenderCommand.Clear(_target, .Pink);
RenderCommand.Clear(_depth, .Depth, 1.0f, 0);
//_target.Bind();
_context.SetRenderTarget(_target);
_context.SetDepthStencilTarget(_depth);
_context.BindRenderTargets();
float2 textureSize = float2(viewedTexture.Width, viewedTexture.Height);
float2 zoomedTextureSize = textureSize * _zoom;
float2 targetSize = float2(_target.Width, _target.Height);
_effect.Variables["ColorOffset"].SetData(_colorOffset);
_effect.Variables["ColorScale"].SetData(_colorScale);
_effect.Variables["AlphaOffset"].SetData(_alphaOffset);
_effect.Variables["AlphaScale"].SetData(_alphaScale);
_camera.Left = 0;
_camera.Top = 0;
_camera.Right = targetSize.X;
_camera.Bottom = -targetSize.Y;
_camera.NearPlane = -5;
_camera.FarPlane = 5;
_camera.Update();
Renderer2D.BeginScene(_camera);
switch(_backgroundMode)
{
case .Black:
Renderer2D.DrawQuadPivotCorner(float3(0, 0, 1), targetSize, 0, .Black);
case .White:
Renderer2D.DrawQuadPivotCorner(float3(0, 0, 1), targetSize, 0, .White);
case .Checkerboard:
float quadSize = 50.0f;
float2 numQuads = (targetSize / 500f) * 10f;
for(float x = 0; x < numQuads.X; x++)
{
for(float y = 0; y < numQuads.Y; y++)
{
Renderer2D.DrawQuadPivotCorner(float3(x * quadSize, -y * quadSize, 1), quadSize.XX, 0, ((x + y) % 2 == 0) ? .White : .Gray);
}
}
break;
}
Renderer2D.EndScene();
var sampler = viewedTexture.SamplerState;
switch(_sampleMode)
{
case .Point:
viewedTexture.SamplerState = _samplerPoint;
case .Linear:
viewedTexture.SamplerState = _samplerLinear;
}
Renderer2D.BeginScene(_camera, .SortByTexture, _effect);
Renderer2D.DrawQuad(float3(_position * .(1, -1), 0), zoomedTextureSize, 0, viewedTexture);
Renderer2D.EndScene();
viewedTexture.SamplerState = sampler;
}
}
}
+20
View File
@@ -70,5 +70,25 @@ namespace GlitchyEngine
delete dictionary; delete dictionary;
} }
} }
public static mixin ClearDictionaryAndReleaseKeys(var dictionary)
{
if (dictionary != null)
{
for (var value in dictionary)
value.key?.ReleaseRef();
dictionary.Clear();
}
}
public static mixin ClearDictionaryAndReleaseValues(var dictionary)
{
if (dictionary != null)
{
for (var value in dictionary)
value.value?.ReleaseRef();
dictionary.Clear();
}
}
} }
} }
+15 -3
View File
@@ -87,17 +87,29 @@ namespace ImGui
public static extern void Image(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero); public static extern void Image(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero);
public static bool ImageButton(SubTexture2D subTexture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, int32 frame_padding = -1, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones) public static bool ImageButton(char8* id, SubTexture2D subTexture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones)
{ {
if (uv0 != .Zero || uv1 != .Ones) if (uv0 != .Zero || uv1 != .Ones)
Runtime.NotImplemented(); Runtime.NotImplemented();
float2 v = (.)subTexture.TexCoords.XY + subTexture.TexCoords.ZW; float2 v = (.)subTexture.TexCoords.XY + subTexture.TexCoords.ZW;
return ImageButton(subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, frame_padding, bg_col, tint_col); return ImageButton(id, subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, bg_col, tint_col);
} }
public static extern bool ImageButton(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, int32 frame_padding = -1, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones); public static extern bool ImageButton(char8* id, TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones);
public static bool ImageButtonEx(uint32 id, SubTexture2D subTexture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones)
{
if (uv0 != .Zero || uv1 != .Ones)
Runtime.NotImplemented();
float2 v = (.)subTexture.TexCoords.XY + subTexture.TexCoords.ZW;
return ImageButtonEx(id, subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, bg_col, tint_col);
}
public static extern bool ImageButtonEx(uint32 id, TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones);
public static void TextUnformatted(StringView text) => TextUnformattedImpl(text.Ptr, text.Ptr + text.Length); public static void TextUnformatted(StringView text) => TextUnformattedImpl(text.Ptr, text.Ptr + text.Length);
+30 -17
View File
@@ -86,29 +86,42 @@ namespace GlitchyEngine.ImGui
ImGuizmo.BeginFrame(); ImGuizmo.BeginFrame();
} }
private void LoadFont()
{
var settings = Application.Instance.Settings.ImGuiSettings;
ImGui.GetIO().Fonts.Clear();
Stream fontFile = Application.Instance.ContentManager.GetStream(settings.FontName);
if (fontFile != null)
{
// We need to use ImGuis memory allocator because ImGui takes ownership
uint8* fontData = (uint8*)ImGui.MemAlloc((uint64)fontFile.Length);
var result = fontFile.TryRead(Span<uint8>(fontData, fontFile.Length));
if (result case .Err)
Log.EngineLogger.Error($"Failed to load font \"{settings.FontName}\" from stream.");
ImGui.GetIO().Fonts.AddFontFromMemoryTTF(fontData, (int32)fontFile.Length, settings.FontSize);
}
else
{
ImGui.GetIO().Fonts.AddFontDefault();
}
ImGui.GetIO().Fonts.AddFontDefault();
delete fontFile;
}
public void ImGuiRender() public void ImGuiRender()
{ {
Debug.Profiler.ProfileFunction!(); Debug.Profiler.ProfileFunction!();
if (SettingsInvalid) if (SettingsInvalid)
{ {
var settings = Application.Get().Settings.ImGuiSettings; LoadFont();
ImGui.GetIO().Fonts.Clear();
// TODO: Fix fonts
//String fullpath = scope String();
//Application.Get().ContentManager.GetFilePath(fullpath, settings.FontName);
/*Application.Get().ContentManager.GetStream(settings.FontName);
if (File.Exists(fullpath))
{
ImGui.GetIO().Fonts.AddFontFromMemoryTTF();
ImGui.GetIO().Fonts.AddFontFromFileTTF(fullpath, settings.FontSize);
}
else
{*/
ImGui.GetIO().Fonts.AddFontDefault();
//}
#if GE_GRAPHICS_DX11 #if GE_GRAPHICS_DX11
ImGuiImplDX11.CreateDeviceObjects(); ImGuiImplDX11.CreateDeviceObjects();
+25 -2
View File
@@ -8,10 +8,33 @@ namespace GlitchyEngine
static Logger _engineLogger ~ delete _; static Logger _engineLogger ~ delete _;
static Logger _clientLogger ~ delete _; static Logger _clientLogger ~ delete _;
public static Logger EngineLogger
{
[Inline] [Inline]
public static Logger EngineLogger => _engineLogger; get => _engineLogger;
set
{
if (_engineLogger == value)
return;
delete _engineLogger;
_engineLogger = value;
}
}
public static Logger ClientLogger
{
[Inline] [Inline]
public static Logger ClientLogger => _clientLogger; get => _clientLogger;
set
{
if (_clientLogger == value)
return;
delete _clientLogger;
_clientLogger = value;
}
}
static this() static this()
{ {
@@ -22,12 +22,24 @@ namespace ImGui
textureViewBinding.Release(); textureViewBinding.Release();
} }
public static override bool ImageButton(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, int32 frame_padding = -1, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones) public static override bool ImageButton(char8* id, TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones)
{ {
var view = textureViewBinding._nativeShaderResourceView..AddRef(); var view = textureViewBinding._nativeShaderResourceView..AddRef();
_resourceViews.Add(view); _resourceViews.Add(view);
bool pressed = ImGui.ImageButton(view, size, uv0, uv1, frame_padding, bg_col, tint_col); bool pressed = ImGui.ImageButton(id, view, size, uv0, uv1, bg_col, tint_col);
textureViewBinding.Release();
return pressed;
}
public static override bool ImageButtonEx(uint32 id, TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones)
{
var view = textureViewBinding._nativeShaderResourceView..AddRef();
_resourceViews.Add(view);
bool pressed = ImGui.ImageButtonEx(id, view, size, uv0, uv1, bg_col, tint_col);
textureViewBinding.Release(); textureViewBinding.Release();
@@ -0,0 +1,81 @@
using System;
using GlitchyEngine.Core;
using Mono;
namespace GlitchyEngine.Scripting;
public class MonoExceptionHelper : RefCounter
{
private String _fullName ~ delete _;
private String _message ~ delete _;
private String _stackTrace ~ delete _;
/// The clean stack trace only contains the Managed Stack (the full trace contains one line for the native-to-managed entry)
private StringView _cleanStackTrace;
private MonoExceptionHelper _innerException ~ _?.ReleaseRef();
public StringView FullName => _fullName;
public StringView Message => _message;
public StringView StackTrace => _stackTrace;
public StringView CleanStackTrace => _cleanStackTrace;
public MonoExceptionHelper InnerException => _innerException;
public UUID Instance { get; set; }
public this(MonoException* exception)
{
MonoObject* exObject = (MonoObject*)exception;
MonoClass* monoClass = Mono.mono_object_get_class(exObject);
StringView classNamespace = .(Mono.mono_class_get_namespace(monoClass));
StringView className = .(Mono.mono_class_get_name(monoClass));
_fullName = new $"{classNamespace}.{className}";
GetMessage(exObject, monoClass);
GetStackTrace(exception);
GetInnerException(exObject, monoClass);
}
private void GetMessage(MonoObject* exceptionObject, MonoClass* monoClass)
{
var messageProperty = Mono.mono_class_get_property_from_name(monoClass, "Message");
MonoObject* message = Mono.mono_property_get_value(messageProperty, exceptionObject, null, null);
char8* exMessage = Mono.mono_string_to_utf8((.)message);
_message = new String(exMessage);
Mono.mono_free(exMessage);
}
private void GetStackTrace(MonoException* exception)
{
char8* stacktracePtr = Mono.mono_exception_get_managed_backtrace(exception);
_stackTrace = new String(stacktracePtr);
int entryIndex = _stackTrace.IndexOf("at (wrapper native-to-managed)");
if (entryIndex != -1)
_cleanStackTrace = _stackTrace.Substring(0, entryIndex);
else
_cleanStackTrace = _stackTrace;
}
private void GetInnerException(MonoObject* exceptionObject, MonoClass* monoClass)
{
MonoProperty* innerExceptionProperty = Mono.mono_class_get_property_from_name(monoClass, "InnerException");
MonoObject* innerException = Mono.mono_property_get_value(innerExceptionProperty, exceptionObject, null, null);
if (innerException != null)
_innerException = new MonoExceptionHelper((MonoException*)innerException);
}
}
+160 -39
View File
@@ -13,13 +13,44 @@ public struct ScriptField
internal MonoClassField* _monoField; internal MonoClassField* _monoField;
public bool IsStatic; public bool IsStatic;
public ScriptFieldType FieldType; public ScriptFieldType FieldType;
public SharpType SharpType;
public int SizeInBytes;
internal this(StringView name, MonoClassField* monoField, bool isStatic, ScriptFieldType fieldType) internal this(StringView name, MonoClassField* monoField, bool isStatic, ScriptFieldType fieldType, int sizeInBytes, SharpType sharpType)
{ {
Name = name; Name = name;
_monoField = monoField; _monoField = monoField;
IsStatic = isStatic; IsStatic = isStatic;
FieldType = fieldType; FieldType = fieldType;
SharpType = sharpType;
SizeInBytes = sizeInBytes;
}
public bool IsType(SharpClass otherClass, bool checkIfSubtype)
{
return IsType(otherClass.GetMonoType(), checkIfSubtype);
}
public bool IsType(MonoType* otherType, bool checkIfSubtype)
{
MonoType* myType = GetMonoType();
if (checkIfSubtype)
{
MonoClass* myClass = Mono.mono_type_get_class(myType);
MonoClass* otherClass = Mono.mono_type_get_class(otherType);
return Mono.mono_class_is_subclass_of(myClass, otherClass, false);
}
else
{
return myType == otherType;
}
}
public MonoType* GetMonoType()
{
return Mono.mono_field_get_type(_monoField);
} }
} }
@@ -90,9 +121,19 @@ class SharpClass : SharpType
ExtractFields(); ExtractFields();
} }
internal MonoType* GetMonoType()
{
return Mono.mono_class_get_type(_monoClass);
}
internal bool IsType(MonoType* type) internal bool IsType(MonoType* type)
{ {
return Mono.mono_class_get_type(_monoClass) == type; return GetMonoType() == type;
}
internal bool IsSubclass(MonoClass* @class)
{
return Mono.mono_class_is_subclass_of(_monoClass, @class, false);
} }
private void ExtractFields() private void ExtractFields()
@@ -110,10 +151,12 @@ class SharpClass : SharpType
ScriptFieldType fieldType = ScriptEngineHelper.GetScriptFieldType(type); ScriptFieldType fieldType = ScriptEngineHelper.GetScriptFieldType(type);
SharpType sharpType = null;
// If field type is none the field might be a struct, class or enum // If field type is none the field might be a struct, class or enum
if (fieldType == .None) if (fieldType == .None)
{ {
SharpType sharpType = ScriptEngine.GetSharpType(type); sharpType = ScriptEngine.GetSharpType(type);
fieldType = sharpType?.ScriptType ?? .None; fieldType = sharpType?.ScriptType ?? .None;
if (sharpType == null) if (sharpType == null)
@@ -132,7 +175,79 @@ class SharpClass : SharpType
(attributes != null && (attributes != null &&
Mono.mono_custom_attrs_has_attr(attributes, ScriptEngine.Attributes.s_ShowInEditorAttribute))) Mono.mono_custom_attrs_has_attr(attributes, ScriptEngine.Attributes.s_ShowInEditorAttribute)))
{ {
_monoFields[name] = .(name, currentField, flags.HasFlag(.Static), fieldType); MonoClass* fieldClass = Mono.mono_type_get_class(type);
int sizeInBytes = 8;
if (fieldClass != null)
{
sizeInBytes = Mono.mono_class_instance_size(fieldClass);
}
else
{
}
_monoFields[name] = .(name, currentField, flags.HasFlag(.Static), fieldType, sizeInBytes, sharpType);
}
}
}
}
struct EnumValue
{
public StringView Name;
public uint64 Value;
public this(StringView name, uint64 value)
{
Name = name;
Value = value;
}
}
class SharpEnum : SharpClass
{
private append Dictionary<uint64, EnumValue> _values = .();
public Dictionary<uint64, EnumValue> Values => _values;
private int _underlyingSize = 0;
public this(StringView classNamespace, StringView className, MonoImage* image)
: base(classNamespace, className, image, .Enum)
{
ExtractEnumValues();
}
private void ExtractEnumValues()
{
_underlyingSize = Mono.mono_class_instance_size(_monoClass);
Log.EngineLogger.Assert(_underlyingSize != 0);
var vtable = Mono.mono_class_vtable(ScriptEngine.[Friend]s_AppDomain, _monoClass);
void* iterator = null;
MonoClassField* currentField = null;
while ((currentField = Mono.mono_class_get_fields(_monoClass, &iterator)) != null)
{
MonoType* fieldType = Mono.mono_field_get_type(currentField);
MonoClass* fieldClass = Mono.mono_type_get_class(fieldType);
FieldAttribute fieldFlags = (.)Mono.mono_field_get_flags(currentField);
if (fieldFlags.HasFlag(.Public) && fieldFlags.HasFlag(.Static) &&
fieldClass != null && Mono.mono_class_is_subclass_of(fieldClass, _monoClass, false))
{
StringView fieldName = StringView(Mono.mono_field_get_name(currentField));
uint64 value = 0;
Mono.mono_field_static_get_value(vtable, currentField, &value);
EnumValue enumValue = .(fieldName, value);
_values.Add(value, enumValue);
} }
} }
} }
@@ -180,8 +295,8 @@ class ScriptClass : SharpClass
public Dictionary<StringView, ScriptField> Fields => _monoFields;*/ public Dictionary<StringView, ScriptField> Fields => _monoFields;*/
[AllowAppend] [AllowAppend]
public this(StringView classNamespace, StringView className, MonoImage* image) : public this(StringView classNamespace, StringView className, MonoImage* image, ScriptFieldType scriptFieldType = .Class) :
base(classNamespace, className, image) base(classNamespace, className, image, scriptFieldType)
{ {
//_constructor = (ConstructorMethod)GetMethodThunk(".ctor", 1); // GetMethod(".ctor", 1);// //_constructor = (ConstructorMethod)GetMethodThunk(".ctor", 1); // GetMethod(".ctor", 1);//
_constructor = GetMethod(".ctor", 1); _constructor = GetMethod(".ctor", 1);
@@ -190,59 +305,50 @@ class ScriptClass : SharpClass
_onDestroy = (OnDestroyMethod)GetMethodThunk("OnDestroy"); _onDestroy = (OnDestroyMethod)GetMethodThunk("OnDestroy");
} }
public void OnCreate(MonoObject* instance) public void OnCreate(MonoObject* instance, out MonoException* exception)
{ {
MonoException* exception = null; exception = null;
if (_onCreate != null) if (_onCreate != null)
_onCreate(instance, &exception); _onCreate(instance, &exception);
} }
public void OnUpdate(MonoObject* instance, float deltaTime) public void OnUpdate(MonoObject* instance, float deltaTime, out MonoException* exception)
{ {
MonoException* exception = null; exception = null;
if (_onUpdate != null) if (_onUpdate != null)
_onUpdate(instance, deltaTime, &exception); _onUpdate(instance, deltaTime, &exception);
if (exception != null)
{
char8* str = Mono.mono_string_to_utf8(exception.Message);
Log.EngineLogger.Error($"Exception in \"{_fullName}.OnUpdate\". Message:\"{StringView(str)}\"");
Mono.mono_free(str);
}
} }
public void OnDestroy(MonoObject* instance) public void OnDestroy(MonoObject* instance, out MonoException* exception)
{ {
MonoException* exception; exception = null;
if (_onDestroy != null) if (_onDestroy != null)
_onDestroy(instance, &exception); _onDestroy(instance, &exception);
} }
public MonoObject* CreateInstance(UUID uuid) public MonoObject* CreateInstance(UUID uuid, out MonoException* exception)
{ {
MonoObject* instance = Mono.mono_object_new(ScriptEngine.[Friend]s_AppDomain, _monoClass); MonoObject* instance = Mono.mono_object_new(ScriptEngine.[Friend]s_AppDomain, _monoClass);
// TODO: I think this is a bit dirty
// Invoke empty constructor to fill fields // Invoke empty constructor to fill fields
Mono.mono_runtime_object_init(instance); Mono.mono_runtime_object_init(instance);
// Invoke constructor with UUID // Invoke constructor with UUID
#unwarn #unwarn
ScriptEngine.[Friend]s_EngineObject.Invoke(ScriptEngine.[Friend]s_EngineObject._constructor, instance, &uuid); ScriptEngine.[Friend]s_EngineObject.Invoke(ScriptEngine.[Friend]s_EngineObject._constructor, instance, out exception, &uuid);
//MonoException* exception = null; return instance;
//#unwarn }
//ScriptEngine.[Friend]s_EntityRoot._constructor(instance, uuid, &exception);
//ScriptEngine.[Friend]s_EntityRoot.Invoke(_constructor, instance, &uuid);
/*MonoObject* exception = null; public MonoObject* CreateInstance()
#unwarn*/ {
//Mono.mono_runtime_invoke(_constructor, instance, (.)&uuid, &exception); MonoObject* instance = Mono.mono_object_new(ScriptEngine.[Friend]s_AppDomain, _monoClass);
//Mono.mono_runtime_object_init(instance);
//MonoException* exception; // Invoke empty constructor to fill fields
//_constructor(instance, uuid, &exception); Mono.mono_runtime_object_init(instance);
return instance; return instance;
} }
@@ -265,12 +371,22 @@ class ScriptClass : SharpClass
public MonoObject* Invoke(MonoMethod* method, MonoObject* instance, void** args = null) public MonoObject* Invoke(MonoMethod* method, MonoObject* instance, void** args = null)
{ {
MonoObject* exception = null; MonoObject* exception = null;
return Mono.mono_runtime_invoke(method, instance, args, &exception);
MonoObject* result = Mono.mono_runtime_invoke(method, instance, args, &exception);
if (exception != null)
ScriptEngine.HandleMonoException((MonoException*)exception);
return result;
} }
public MonoObject* Invoke(MonoMethod* method, MonoObject* instance, params void*[] args) public MonoObject* Invoke(MonoMethod* method, MonoObject* instance, out MonoException* exception, params void*[] args)
{ {
return Mono.mono_runtime_invoke(method, instance, args.Ptr, null); exception = null;
MonoObject* result = Mono.mono_runtime_invoke(method, instance, args.Ptr, (.)&exception);
return result;
} }
public T Invoke<T>(MonoMethod* method, MonoObject* instance, params void*[] args) public T Invoke<T>(MonoMethod* method, MonoObject* instance, params void*[] args)
@@ -282,12 +398,17 @@ class ScriptClass : SharpClass
public T GetFieldValue<T>(MonoObject* instance, MonoClassField* field) public T GetFieldValue<T>(MonoObject* instance, MonoClassField* field)
{ {
T value = default; T value = default;
Mono.Mono.mono_field_get_value(instance, field, &value); Mono.mono_field_get_value(instance, field, &value);
return value; return value;
} }
public void SetFieldValue<T>(MonoObject* instance, MonoClassField* field, in T value) public void SetFieldValue<T>(MonoObject* instance, MonoClassField* field, in T value)
{ {
Mono.Mono.mono_field_set_value(instance, field, &value); Mono.mono_field_set_value(instance, field, &value);
}
public void SetFieldValue<T>(MonoObject* instance, MonoClassField* field, in T value) where T : struct*
{
Mono.mono_field_set_value(instance, field, value);
} }
} }
+152 -43
View File
@@ -58,12 +58,14 @@ static class ScriptEngine
private static Scene s_Context ~ _?.ReleaseRef(); private static Scene s_Context ~ _?.ReleaseRef();
private static ScriptClass s_ComponentRoot ~ _?.ReleaseRef();
private static ScriptClass s_EntityRoot ~ _?.ReleaseRef(); private static ScriptClass s_EntityRoot ~ _?.ReleaseRef();
private static ScriptClass s_EngineObject ~ _?.ReleaseRef(); private static ScriptClass s_EngineObject ~ _?.ReleaseRef();
private static Dictionary<StringView, SharpType> _sharpClasses = new .() ~ DeleteDictionaryAndReleaseValues!(_); private static Dictionary<StringView, SharpType> _sharpClasses = new .() ~ DeleteDictionaryAndReleaseValues!(_);
private static Dictionary<StringView, ScriptClass> _entityScripts = new .() ~ DeleteDictionaryAndReleaseValues!(_); private static Dictionary<StringView, ScriptClass> _entityScripts = new .() ~ DeleteDictionaryAndReleaseValues!(_);
private static Dictionary<StringView, ScriptClass> _componentClasses = new .() ~ DeleteDictionaryAndReleaseValues!(_);
private static Dictionary<UUID, ScriptInstance> _entityScriptInstances = new .() ~ { private static Dictionary<UUID, ScriptInstance> _entityScriptInstances = new .() ~ {
for (var entry in _) for (var entry in _)
@@ -74,6 +76,7 @@ static class ScriptEngine
} }
public static Dictionary<StringView, ScriptClass> EntityClasses => _entityScripts; public static Dictionary<StringView, ScriptClass> EntityClasses => _entityScripts;
public static Dictionary<StringView, ScriptClass> ComponentClasses => _componentClasses;
public static Scene Context => s_Context; public static Scene Context => s_Context;
@@ -171,6 +174,13 @@ static class ScriptEngine
(s_CoreAssembly, s_CoreAssemblyImage) = LoadAssembly("resources/scripts/ScriptCore.dll", _debuggingEnabled); (s_CoreAssembly, s_CoreAssemblyImage) = LoadAssembly("resources/scripts/ScriptCore.dll", _debuggingEnabled);
(s_AppAssembly, s_AppAssemblyImage) = LoadAssembly("SandboxProject/Assets/Scripts/bin/Sandbox.dll", _debuggingEnabled); (s_AppAssembly, s_AppAssemblyImage) = LoadAssembly("SandboxProject/Assets/Scripts/bin/Sandbox.dll", _debuggingEnabled);
ClearDictionaryAndReleaseValues!(_sharpClasses);
GetCoreAttributes();
GetCoreClasses();
GetComponentsFromAssemblies();
GetEntitiesFromAssemblies(); GetEntitiesFromAssemblies();
ScriptGlue.RegisterManagedComponents(); ScriptGlue.RegisterManagedComponents();
@@ -199,20 +209,22 @@ static class ScriptEngine
if (scriptClass == null) if (scriptClass == null)
return false; return false;
script.Instance = new ScriptInstance(scriptClass); UUID entityId = entity.UUID;
script.Instance = new ScriptInstance(entityId, scriptClass);
script.Instance..ReleaseRef(); script.Instance..ReleaseRef();
_entityScriptInstances[entity.UUID] = script.Instance..AddRef(); _entityScriptInstances[entityId] = script.Instance..AddRef();
script.Instance.Instantiate(entity.UUID); script.Instance.Instantiate(entityId);
CopyEditorFieldsToInstance(entity, script);
return true; return true;
} }
private static void CopyEditorFieldsToInstance(Entity entity, ScriptComponent* script) public static void CopyEditorFieldsToInstance(Entity entity, ScriptComponent* script)
{ {
Log.EngineLogger.AssertDebug(script.Instance != null);
// Technically the map is for a different entity (namely the editor-entity), // Technically the map is for a different entity (namely the editor-entity),
// however the UUID is the same, so we get the correct field map // however the UUID is the same, so we get the correct field map
let fields = GetScriptFieldMap(entity); let fields = GetScriptFieldMap(entity);
@@ -223,9 +235,33 @@ static class ScriptEngine
ScriptField scriptField = script.Instance.ScriptClass.Fields[fieldName]; ScriptField scriptField = script.Instance.ScriptClass.Fields[fieldName];
switch (scriptField.FieldType)
{
case .Entity:
// On the C# side we actually differentiate between an Entity and the Script
// in the sense that getting an entity and a script yields two different results (one creates a new Entity-Class instance, the other returns the actual instance).
// But here its just easier to always use the script instance.
// Obviously breaks once we support multiple scripts per entity.
UUID referencedId = field.GetData<UUID>();
MonoObject* referencedEntity = GetManagedInstance(referencedId);
script.Instance.SetFieldValue(scriptField, referencedEntity);
case .Component:
// We create a new instance of a component class
MonoType* type = scriptField.GetMonoType();
SharpType sharpType = ScriptEngine.GetSharpType(type);
var componentClass = ComponentClasses[sharpType.FullName];
MonoObject* componentInstance = script.Instance.CreateComponentInstance(componentClass);
script.Instance.SetFieldValue(scriptField, componentInstance);
sharpType.ReleaseRef();
default:
script.Instance.SetFieldValue(scriptField, field._data); script.Instance.SetFieldValue(scriptField, field._data);
} }
} }
}
private static MonoAssembly* LoadCSharpAssembly(StringView assemblyPath, bool loadPDB = false) private static MonoAssembly* LoadCSharpAssembly(StringView assemblyPath, bool loadPDB = false)
{ {
@@ -297,32 +333,27 @@ static class ScriptEngine
return (assembly, image); return (assembly, image);
} }
/// Retrieves the base classes from which every Component or Entity inherits
static void GetCoreClasses()
{
s_EngineObject?.ReleaseRef();
s_EntityRoot?.ReleaseRef();
s_ComponentRoot?.ReleaseRef();
s_EngineObject = new ScriptClass("GlitchyEngine.Core", "EngineObject", s_CoreAssemblyImage, .Class);
s_EntityRoot = new ScriptClass("GlitchyEngine", "Entity", s_CoreAssemblyImage, .Entity);
s_ComponentRoot = new ScriptClass("GlitchyEngine", "Component", s_CoreAssemblyImage, .Component);
}
/// Retrieves the classes for Attributes that are defined in the Core library
static void GetCoreAttributes()
{
Attributes.s_ShowInEditorAttribute = Mono.mono_class_from_name(s_CoreAssemblyImage, "GlitchyEngine.Editor", "ShowInEditorAttribute");
}
private static void GetEntitiesFromAssemblies() private static void GetEntitiesFromAssemblies()
{ {
for (var entry in _entityScripts) ClearDictionaryAndReleaseValues!(_entityScripts);
{
entry.value.ReleaseRef();
}
_entityScripts.Clear();
for (var sharpClass in _sharpClasses)
{
sharpClass.value.ReleaseRef();
}
_sharpClasses.Clear();
if (s_EngineObject != null)
{
s_EngineObject.ReleaseRef();
s_EntityRoot.ReleaseRef();
}
s_EngineObject = new ScriptClass("GlitchyEngine.Core", "EngineObject", s_CoreAssemblyImage);
s_EntityRoot = new ScriptClass("GlitchyEngine", "Entity", s_CoreAssemblyImage);
Log.EngineLogger.Assert(s_EntityRoot != null);
Attributes.s_ShowInEditorAttribute = Mono.mono_class_from_name(s_CoreAssemblyImage, "GlitchyEngine.Editor", "ShowInEditorAttribute");
MonoTableInfo* typeDefinitionsTable = Mono.mono_image_get_table_info(s_AppAssemblyImage, .MONO_TABLE_TYPEDEF); MonoTableInfo* typeDefinitionsTable = Mono.mono_image_get_table_info(s_AppAssemblyImage, .MONO_TABLE_TYPEDEF);
int32 numTypes = Mono.mono_table_info_get_rows(typeDefinitionsTable); int32 numTypes = Mono.mono_table_info_get_rows(typeDefinitionsTable);
@@ -337,15 +368,43 @@ static class ScriptEngine
MonoClass* monoClass = Mono.mono_class_from_name(s_AppAssemblyImage, nameSpace, name); MonoClass* monoClass = Mono.mono_class_from_name(s_AppAssemblyImage, nameSpace, name);
// Check if it is an entity
if (monoClass != null && Mono.mono_class_is_subclass_of(monoClass, s_EntityRoot.[Friend]_monoClass, false)) if (monoClass != null && Mono.mono_class_is_subclass_of(monoClass, s_EntityRoot.[Friend]_monoClass, false))
{ {
ScriptClass entityScript = new ScriptClass(StringView(nameSpace), StringView(name), s_AppAssemblyImage); ScriptClass entityScript = new ScriptClass(StringView(nameSpace), StringView(name), s_AppAssemblyImage, .Entity);
_entityScripts.Add(entityScript.FullName, entityScript); _entityScripts.Add(entityScript.FullName, entityScript);
Log.EngineLogger.Info($"Added entity \"{entityScript.FullName}\""); Log.EngineLogger.Info($"Added entity \"{entityScript.FullName}\"");
} }
} }
} }
private static void GetComponentsFromAssemblies()
{
ClearDictionaryAndReleaseValues!(_componentClasses);
MonoTableInfo* typeDefinitionsTable = Mono.mono_image_get_table_info(s_CoreAssemblyImage, .MONO_TABLE_TYPEDEF);
int32 numTypes = Mono.mono_table_info_get_rows(typeDefinitionsTable);
for (int32 i = 0; i < numTypes; i++)
{
int32[(.)SOME_RANDOM_ENUM.MONO_TYPEDEF_SIZE] cols = .();
Mono.mono_metadata_decode_row(typeDefinitionsTable, i, (.)&cols, (.)SOME_RANDOM_ENUM.MONO_TYPEDEF_SIZE);
char8* nameSpace = Mono.mono_metadata_string_heap(s_CoreAssemblyImage, (.)cols[(.)SOME_RANDOM_ENUM.MONO_TYPEDEF_NAMESPACE]);
char8* name = Mono.mono_metadata_string_heap(s_CoreAssemblyImage, (.)cols[(.)SOME_RANDOM_ENUM.MONO_TYPEDEF_NAME]);
MonoClass* monoClass = Mono.mono_class_from_name(s_CoreAssemblyImage, nameSpace, name);
// Check if it is a component but not the root Component class
if (monoClass != null && monoClass != s_ComponentRoot.[Friend]_monoClass && Mono.mono_class_is_subclass_of(monoClass, s_ComponentRoot.[Friend]_monoClass, false))
{
ScriptClass componentClass = new ScriptClass(StringView(nameSpace), StringView(name), s_CoreAssemblyImage, .Component);
_componentClasses.Add(componentClass.FullName, componentClass);
Log.EngineLogger.Info($"Added component \"{componentClass.FullName}\"");
}
}
}
public static void ReloadAssemblies() public static void ReloadAssemblies()
{ {
@@ -399,27 +458,40 @@ static class ScriptEngine
StringView classNamespace = StringView(Mono.mono_class_get_namespace(monoClass)); StringView classNamespace = StringView(Mono.mono_class_get_namespace(monoClass));
// TODO: at the moment only allow user-structs // TODO: at the moment only allow user-structs
if (classNamespace.StartsWith("GlitchyEngine")) //if (classNamespace.StartsWith("GlitchyEngine"))
return null; // return null;
switch (fieldType)
{
case .Class, .Valuetype, .Enum:
ScriptFieldType scriptType = .None; ScriptFieldType scriptType = .None;
if (fieldType == .Class) if (Mono.mono_class_is_enum(monoClass))
scriptType = .Class; {
else if (fieldType == .Enum)
scriptType = .Enum; scriptType = .Enum;
return new SharpEnum(classNamespace, className, Mono.mono_class_get_image(monoClass));
}
else if (fieldType == .Class)
{
if (Mono.mono_class_is_subclass_of(monoClass, s_EntityRoot._monoClass, false))
{
scriptType = .Entity;
}
else if (Mono.mono_class_is_subclass_of(monoClass, s_ComponentRoot._monoClass, false))
{
scriptType = .Component;
}
else
{
scriptType = .Class;
}
}
else if (fieldType == .Valuetype) else if (fieldType == .Valuetype)
{
scriptType = .Struct; scriptType = .Struct;
}
Log.EngineLogger.AssertDebug(scriptType != .None); Log.EngineLogger.AssertDebug(scriptType != .None);
return new SharpClass(classNamespace, className, Mono.mono_class_get_image(monoClass), scriptType); return new SharpClass(classNamespace, className, Mono.mono_class_get_image(monoClass), scriptType);
default:
return null;
}
} }
public static void CreateScriptFieldMap(Entity entity) public static void CreateScriptFieldMap(Entity entity)
@@ -442,12 +514,26 @@ static class ScriptEngine
Log.EngineLogger.AssertDebug(scriptClass != null); Log.EngineLogger.AssertDebug(scriptClass != null);
for (let (fieldName, field) in scriptClass.Fields) void AddFieldsToMap(Dictionary<StringView, ScriptField> classFields, StringView baseName)
{ {
for (let (fieldName, field) in classFields)
{
/*if (field.FieldType == .Struct && field.SharpType != null)
{
AddFieldsToMap(field.SharpType.Fields, scope $"{baseName}{fieldName}.");
}
else
{
entityFields.Add(new $"{baseName}{fieldName}", ScriptFieldInstance(field.FieldType));
}*/
entityFields.Add(new String(fieldName), ScriptFieldInstance(field.FieldType)); entityFields.Add(new String(fieldName), ScriptFieldInstance(field.FieldType));
} }
} }
AddFieldsToMap(scriptClass.Fields, "");
}
public static ScriptFieldMap GetScriptFieldMap(Entity entity) public static ScriptFieldMap GetScriptFieldMap(Entity entity)
{ {
Log.EngineLogger.AssertDebug(entity.IsValid); Log.EngineLogger.AssertDebug(entity.IsValid);
@@ -474,4 +560,27 @@ static class ScriptEngine
return scriptClass; return scriptClass;
} }
internal static void HandleMonoException(MonoException* exception, ScriptInstance sourceInstance = null)
{
MonoExceptionHelper wrappedException = new MonoExceptionHelper(exception);
String entityInfo = scope .();
if (sourceInstance != null)
{
wrappedException.Instance = sourceInstance.EntityId;
Result<Entity> sourceEntity = Context.GetEntityByID(sourceInstance.EntityId);
if (sourceEntity case .Ok(let e))
{
entityInfo.AppendF($" ({e.Name} | {sourceInstance.EntityId})");
}
}
Log.ClientLogger.Error($"Mono Exception \"{wrappedException.FullName}\": \"{wrappedException.Message}\"{entityInfo}\nStackTrace:\n{wrappedException.StackTrace}", wrappedException);
wrappedException.ReleaseRef();
}
} }
@@ -27,6 +27,7 @@ enum ScriptFieldType
case Double, Double2, Double3, Double4; case Double, Double2, Double3, Double4;
case Entity; case Entity;
case Component;
public Type GetBeefType() public Type GetBeefType()
{ {
@@ -79,6 +80,8 @@ enum ScriptFieldType
case .Entity: case .Entity:
return typeof(UUID); return typeof(UUID);
case .Component:
return typeof(UUID);
default: default:
return null; return null;
+46 -8
View File
@@ -4,6 +4,8 @@ using System;
namespace GlitchyEngine.Scripting; namespace GlitchyEngine.Scripting;
using internal GlitchyEngine.Scripting;
class ScriptInstance : RefCounter class ScriptInstance : RefCounter
{ {
private ScriptClass _scriptClass; private ScriptClass _scriptClass;
@@ -11,6 +13,8 @@ class ScriptInstance : RefCounter
private MonoObject* _instance; private MonoObject* _instance;
private uint32 _gcHandle; private uint32 _gcHandle;
private UUID _entityId;
public ScriptClass ScriptClass => _scriptClass; public ScriptClass ScriptClass => _scriptClass;
/// Gets whether or not the instance has ben initialized. /// Gets whether or not the instance has ben initialized.
@@ -21,9 +25,15 @@ class ScriptInstance : RefCounter
private bool _isCreated = false; private bool _isCreated = false;
public this(ScriptClass scriptClass) internal MonoObject* MonoInstance => _instance;
public UUID EntityId => _entityId;
public this(UUID entityId, ScriptClass scriptClass)
{ {
Log.EngineLogger.AssertDebug(scriptClass != null); Log.EngineLogger.AssertDebug(scriptClass != null);
_entityId = entityId;
_scriptClass = scriptClass..AddRef(); _scriptClass = scriptClass..AddRef();
} }
@@ -31,34 +41,44 @@ class ScriptInstance : RefCounter
{ {
if (_instance != null) if (_instance != null)
{ {
_scriptClass.OnDestroy(_instance); InvokeOnDestroy();
Mono.mono_gchandle_free(_gcHandle); Mono.mono_gchandle_free(_gcHandle);
} }
_scriptClass?.ReleaseRef(); _scriptClass?.ReleaseRef();
} }
internal MonoObject* MonoInstance => _instance;
public void Instantiate(UUID uuid) public void Instantiate(UUID uuid)
{ {
_instance = _scriptClass.CreateInstance(uuid); _instance = _scriptClass.CreateInstance(uuid, let exception);
_gcHandle = Mono.mono_gchandle_new(_instance, true); _gcHandle = Mono.mono_gchandle_new(_instance, true);
if (exception != null)
ScriptEngine.HandleMonoException(exception, this);
} }
public void InvokeOnCreate() public void InvokeOnCreate()
{ {
_scriptClass.OnCreate(_instance); _scriptClass.OnCreate(_instance, let exception);
_isCreated = true; _isCreated = true;
if (exception != null)
ScriptEngine.HandleMonoException(exception, this);
} }
public void InvokeOnUpdate(float deltaTime) public void InvokeOnUpdate(float deltaTime)
{ {
_scriptClass.OnUpdate(_instance, deltaTime); _scriptClass.OnUpdate(_instance, deltaTime, let exception);
if (exception != null)
ScriptEngine.HandleMonoException(exception, this);
} }
public void InvokeOnDestroy() public void InvokeOnDestroy()
{ {
_scriptClass.OnDestroy(_instance); _scriptClass.OnDestroy(_instance, let exception);
if (exception != null)
ScriptEngine.HandleMonoException(exception, this);
} }
public T GetFieldValue<T>(ScriptField field) public T GetFieldValue<T>(ScriptField field)
@@ -70,4 +90,22 @@ class ScriptInstance : RefCounter
{ {
_scriptClass.SetFieldValue<T>(_instance, field.[Friend]_monoField, value); _scriptClass.SetFieldValue<T>(_instance, field.[Friend]_monoField, value);
} }
/// Creates a new instance of the given component class and initializes it for the current entity.
public MonoObject* CreateComponentInstance(ScriptClass componentClassType)
{
MonoObject* componentInstance = componentClassType.CreateInstance();
// TODO: We could cache the property, but this might be fine
MonoProperty* entityProperty = Mono.mono_class_get_property_from_name(componentClassType.[Friend]_monoClass, "Entity");
MonoObject* exception = null;
Mono.mono_property_set_value(entityProperty, componentInstance, (void**)&_instance, &exception);
if (exception != null)
ScriptEngine.HandleMonoException((MonoException*)exception, this);
return componentInstance;
}
} }
+9
View File
@@ -100,6 +100,15 @@ namespace GlitchyEngine.World
ScriptEngine.InitializeInstance(targetEntity, targetComponent); ScriptEngine.InitializeInstance(targetEntity, targetComponent);
} }
// Copy values to entities.
// We do this in a separate loop because we might reference other entities.
// If we did it in a single loop these entities might not exist yet.
for (let (handle, script) in target._ecsWorld.Enumerate<ScriptComponent>())
{
Entity entity = .(handle, this);
ScriptEngine.CopyEditorFieldsToInstance(entity, script);
}
// Copy transforms... needs special handling for the Parent<->Child relations // Copy transforms... needs special handling for the Parent<->Child relations
for (let (sourceHandle, sourceTransform) in _ecsWorld.Enumerate<TransformComponent>()) for (let (sourceHandle, sourceTransform) in _ecsWorld.Enumerate<TransformComponent>())
{ {
+17 -8
View File
@@ -613,10 +613,6 @@ class SceneSerializer
// Allocate a string on the stack, because the dictionary uses a string as key // Allocate a string on the stack, because the dictionary uses a string as key
String fieldNameString = scope .(fieldName); String fieldNameString = scope .(fieldName);
if (fields.ContainsKey(fieldNameString))
{
var field = ref fields[fieldNameString];
Result<StringView> fieldTypeName = reader.Type(); Result<StringView> fieldTypeName = reader.Type();
if (fieldTypeName case .Err) if (fieldTypeName case .Err)
@@ -629,23 +625,36 @@ class SceneSerializer
Result<ScriptFieldType> fieldType = Enum.Parse<ScriptFieldType>(fieldTypeName, true); Result<ScriptFieldType> fieldType = Enum.Parse<ScriptFieldType>(fieldTypeName, true);
if ((fieldType case .Err) || (fieldType != field.Type)) if ((fieldType case .Err))
{ {
Log.EngineLogger.Error($"Unexpected field type (\"{fieldTypeName}\" instead of \"{field.Type}\" for field: \"{fieldName}\" in script \"{component.ScriptClassName}\" of entity {entity.UUID} (\"{entity.Name}\")"); Log.EngineLogger.Error($"Error deserializing field type (Raw string: \"{fieldTypeName}\" of field: \"{fieldName}\" in script \"{component.ScriptClassName}\" of entity {entity.UUID} (\"{entity.Name}\")");
reader.FileEntrySkip(1); reader.FileEntrySkip(1);
dontRemoveComma = true; dontRemoveComma = true;
continue; continue;
} }
void* data = &field.[Friend]_data; uint8[sizeof(Matrix)] data = .();
if (Deserialize.Value(reader, ValueView(field.Type.GetBeefType(), data), gBonEnv) case .Err) if (Deserialize.Value(reader, ValueView(fieldType.Value.GetBeefType(), &data), gBonEnv) case .Err)
{ {
Log.EngineLogger.Error($"Failed to deserialize data for field: \"{fieldName}\" in script \"{component.ScriptClassName}\" of entity {entity.UUID} (\"{entity.Name}\")"); Log.EngineLogger.Error($"Failed to deserialize data for field: \"{fieldName}\" in script \"{component.ScriptClassName}\" of entity {entity.UUID} (\"{entity.Name}\")");
reader.FileEntrySkip(1); reader.FileEntrySkip(1);
dontRemoveComma = true; dontRemoveComma = true;
continue; continue;
} }
if (fields.ContainsKey(fieldNameString))
{
var field = ref fields[fieldNameString];
// Make sure the type we deserialized actually is correct.
if (fieldType != field.Type)
{
Log.EngineLogger.Error($"Unexpected field type (\"{fieldTypeName}\" instead of \"{field.Type}\" for field: \"{fieldName}\" in script \"{component.ScriptClassName}\" of entity {entity.UUID} (\"{entity.Name}\")");
continue;
}
field.SetData(data);
} }
else else
{ {
+44
View File
@@ -92,6 +92,9 @@ static class Mono
[LinkName(.C)] [LinkName(.C)]
public static extern MonoType* mono_class_get_type(MonoClass* monoClass); public static extern MonoType* mono_class_get_type(MonoClass* monoClass);
[LinkName(.C)]
public static extern int32 mono_class_instance_size(MonoClass* @class);
[LinkName(.C)] [LinkName(.C)]
public static extern char8* mono_class_get_namespace(MonoClass* monoClass); public static extern char8* mono_class_get_namespace(MonoClass* monoClass);
@@ -158,6 +161,9 @@ static class Mono
[LinkName(.C)] [LinkName(.C)]
public static extern MonoType* mono_reflection_type_get_type(MonoReflectionType* reflectionType); public static extern MonoType* mono_reflection_type_get_type(MonoReflectionType* reflectionType);
[LinkName(.C)]
public static extern MonoReflectionType* mono_type_get_object(MonoDomain *domain, MonoType *type);
[LinkName(.C)] [LinkName(.C)]
public static extern MonoClassField* mono_class_get_fields(MonoClass* klass, gpointer* iter); public static extern MonoClassField* mono_class_get_fields(MonoClass* klass, gpointer* iter);
@@ -179,6 +185,9 @@ static class Mono
[LinkName(.C)] [LinkName(.C)]
public static extern void mono_field_get_value(MonoObject* object, MonoClassField* field, void* value); public static extern void mono_field_get_value(MonoObject* object, MonoClassField* field, void* value);
[LinkName(.C)]
public static extern void mono_field_static_get_value(MonoVTable* vt, MonoClassField* field, void* value);
/// Gets the field as object, boxes the value if it is a valuetype. /// Gets the field as object, boxes the value if it is a valuetype.
[LinkName(.C)] [LinkName(.C)]
public static extern MonoObject* mono_field_get_value_object(MonoDomain* domain, MonoClassField* field, MonoObject* obj); public static extern MonoObject* mono_field_get_value_object(MonoDomain* domain, MonoClassField* field, MonoObject* obj);
@@ -229,6 +238,37 @@ static class Mono
[LinkName(.C)] [LinkName(.C)]
public static extern MonoThread* mono_thread_current(); public static extern MonoThread* mono_thread_current();
#region Property
[LinkName(.C)]
public static extern MonoProperty* mono_class_get_property_from_name(MonoClass *klass, char8* name);
[LinkName(.C)]
public static extern void mono_property_set_value(MonoProperty *prop, void *obj, void **@params, MonoObject **exc);
[LinkName(.C)]
public static extern MonoObject* mono_property_get_value(MonoProperty *prop, void *obj, void** @params, MonoObject** exc);
#endregion
[LinkName(.C)]
public static extern char8* mono_exception_get_managed_backtrace(MonoException* exc);
[LinkName(.C)]
public static extern MonoClass* mono_object_get_class(MonoObject* obj);
[LinkName(.C)]
public static extern mono_bool mono_class_is_enum(MonoClass* @class);
[LinkName(.C)]
public static extern MonoVTable* mono_class_vtable(MonoDomain* domain, MonoClass* @class);
[LinkName(.C)]
public static extern MonoObject* mono_value_box(MonoDomain* domain, MonoClass* klass, gpointer value);
} }
struct MonoDomain; struct MonoDomain;
@@ -247,8 +287,12 @@ struct MonoObject;
struct MonoMethod; struct MonoMethod;
struct MonoProperty;
struct MonoThread; struct MonoThread;
struct MonoVTable;
struct MonoException struct MonoException
{ {
void* _bla; void* _bla;
+3 -3
View File
@@ -86,10 +86,10 @@ namespace Sandbox
ImGui.Combo("Sampler", (.)&_sampleMode, items.Ptr, (.)items.Count); ImGui.Combo("Sampler", (.)&_sampleMode, items.Ptr, (.)items.Count);
ImGui.SliderFloat2("Color offset and scale", *(float[2]*)&_colorOffset, -1.0f, 1.0f); ImGui.SliderFloat2("Color offset and scale", ref *(float[2]*)&_colorOffset, -1.0f, 1.0f);
ImGui.SliderFloat2("Alpha offset and scale", *(float[2]*)&_alphaOffset, -1.0f, 1.0f); ImGui.SliderFloat2("Alpha offset and scale", ref *(float[2]*)&_alphaOffset, -1.0f, 1.0f);
ImGui.SliderFloat2("Position", *(float[2]*)&_position, 2 * -Math.Max(viewedTexture.Width, viewedTexture.Height) * _zoom, 2 * Math.Max(viewedTexture.Width, viewedTexture.Height) * _zoom); ImGui.SliderFloat2("Position", ref *(float[2]*)&_position, 2 * -Math.Max(viewedTexture.Width, viewedTexture.Height) * _zoom, 2 * Math.Max(viewedTexture.Width, viewedTexture.Height) * _zoom);
ImGui.BeginChild("imageChild"); ImGui.BeginChild("imageChild");
@@ -2,6 +2,12 @@ using System;
namespace GlitchyEngine.Editor; namespace GlitchyEngine.Editor;
// TODO: Maybe rename, definitely move into different namespace
/* Why?
* - this attribute also means that the Field is being serialized
* - Editor-Namespace wont be available for distribution builds of the game
*/
[AttributeUsage(AttributeTargets.Field)]
public sealed class ShowInEditorAttribute : Attribute public sealed class ShowInEditorAttribute : Attribute
{ {
public string DisplayName { get; set; } = null; public string DisplayName { get; set; } = null;