mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Created editor project and moved Editor there
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
FileVersion = 1
|
||||
Dependencies = {corlib = "*", GlitchLog = "*", GlitchyEngine = "*"}
|
||||
|
||||
[Project]
|
||||
Name = "GlitchyEditor"
|
||||
TargetType = "BeefGUIApplication"
|
||||
StartupObject = "GlitchyEngine.Program"
|
||||
|
||||
[Configs.Debug.Win64]
|
||||
CLibType = "DynamicDebug"
|
||||
@@ -0,0 +1,31 @@
|
||||
cbuffer Constants : register(b0)
|
||||
{
|
||||
float4x4 ViewProjection;
|
||||
float4 Color;
|
||||
};
|
||||
|
||||
struct VS_Input
|
||||
{
|
||||
float4 Position : POSITION;
|
||||
};
|
||||
|
||||
struct PS_Input
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
};
|
||||
|
||||
PS_Input VS(VS_Input input)
|
||||
{
|
||||
PS_Input output;
|
||||
|
||||
output.Position = mul(ViewProjection, input.Position);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 PS(PS_Input input) : SV_Target0
|
||||
{
|
||||
return Color;
|
||||
}
|
||||
|
||||
#effect[VS=VS, PS=PS]
|
||||
@@ -0,0 +1,37 @@
|
||||
Texture2D Texture : register(t0);
|
||||
SamplerState Sampler : register(s0);
|
||||
|
||||
struct VS_Input
|
||||
{
|
||||
float2 Position : POSITION;
|
||||
float4x4 Tranform : TRANSFORM;
|
||||
float4 Color : COLOR;
|
||||
float4 UVTransform : TEXCOORD;
|
||||
};
|
||||
|
||||
struct PS_Input
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float2 TexCoord : TEXCOORD0;
|
||||
float4 Color : COLOR;
|
||||
};
|
||||
|
||||
PS_Input VS(VS_Input input)
|
||||
{
|
||||
PS_Input output;
|
||||
|
||||
output.Position = mul(float4(input.Position, 0.0f, 1.0f), input.Tranform);
|
||||
output.TexCoord = input.UVTransform.xy + input.UVTransform.zw * input.Position;
|
||||
output.Color = input.Color;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 PS(PS_Input input) : SV_Target0
|
||||
{
|
||||
float4 color = input.Color * Texture.Sample(Sampler, input.TexCoord);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
#effect[VS=VS, PS=PS]
|
||||
@@ -0,0 +1,84 @@
|
||||
cbuffer SceneConstants
|
||||
{
|
||||
float4x4 ViewProjection = float4x4(1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
cbuffer ObjectConstants
|
||||
{
|
||||
float4x4 Transform;
|
||||
}
|
||||
|
||||
cbuffer Constants
|
||||
{
|
||||
float4 BaseColor;
|
||||
float3 LightDir;
|
||||
}
|
||||
|
||||
cbuffer SkinningMatrices
|
||||
{
|
||||
matrix SkinningMatrices[255];
|
||||
float3x3 InvTransSkinningMatrices[255];
|
||||
}
|
||||
|
||||
struct VS_IN
|
||||
{
|
||||
float3 Position : POSITION;
|
||||
float3 Normal : NORMAL;
|
||||
uint4 JointIndices : JOINTS_0;
|
||||
float4 JointWeights : WEIGHTS_0;
|
||||
};
|
||||
|
||||
struct PS_IN
|
||||
{
|
||||
float4 Position : SV_POSITION;
|
||||
float3 Normal : NORMAL;
|
||||
};
|
||||
|
||||
PS_IN VS(VS_IN input)
|
||||
{
|
||||
PS_IN output;
|
||||
|
||||
// Unanimated position in modelspace
|
||||
float4 positionRaw = float4(input.Position, 1);
|
||||
|
||||
// Calculate animated position in modelspace
|
||||
|
||||
float4 position =
|
||||
mul(SkinningMatrices[input.JointIndices.x], positionRaw) * input.JointWeights.x +
|
||||
mul(SkinningMatrices[input.JointIndices.y], positionRaw) * input.JointWeights.y +
|
||||
mul(SkinningMatrices[input.JointIndices.z], positionRaw) * input.JointWeights.z +
|
||||
mul(SkinningMatrices[input.JointIndices.w], positionRaw) * input.JointWeights.w;
|
||||
|
||||
float3 normal =
|
||||
mul(InvTransSkinningMatrices[input.JointIndices.x], input.Normal) * input.JointWeights.x +
|
||||
mul(InvTransSkinningMatrices[input.JointIndices.y], input.Normal) * input.JointWeights.y +
|
||||
mul(InvTransSkinningMatrices[input.JointIndices.z], input.Normal) * input.JointWeights.z +
|
||||
mul(InvTransSkinningMatrices[input.JointIndices.w], input.Normal) * input.JointWeights.w;
|
||||
|
||||
//position = saturate(position - 1000) + positionRaw;
|
||||
|
||||
//float4 position = mul(SkinningMatrices[input.JointIndices.x], positionRaw);
|
||||
|
||||
float4 worldPosition = mul(Transform, position);
|
||||
|
||||
output.Position = mul(ViewProjection, worldPosition);
|
||||
output.Normal = mul((float3x3)Transform, normal);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 PS(PS_IN input) : SV_TARGET
|
||||
{
|
||||
input.Normal = normalize(input.Normal);
|
||||
|
||||
float shading = dot(LightDir, input.Normal);
|
||||
//float shading = dot(LightDir, LightDir) + 1;
|
||||
shading = clamp(shading, 0.0f, 1.0f);
|
||||
|
||||
return BaseColor * shading;
|
||||
}
|
||||
|
||||
#effect[VS=VS,PS=PS]
|
||||
@@ -0,0 +1,155 @@
|
||||
using ImGui;
|
||||
using GlitchyEngine.World;
|
||||
using System;
|
||||
using GlitchyEngine.Math;
|
||||
|
||||
namespace GlitchyEditor.EditWindows
|
||||
{
|
||||
class ComponentEditWindow
|
||||
{
|
||||
private Editor _editor;
|
||||
|
||||
private bool _show = true;
|
||||
|
||||
public Editor Editor => _editor;
|
||||
|
||||
public bool Show
|
||||
{
|
||||
get => _show;
|
||||
set => _show = value;
|
||||
}
|
||||
|
||||
public this(Editor editor)
|
||||
{
|
||||
_editor = editor;
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
if(!_show)
|
||||
return;
|
||||
|
||||
if(!ImGui.Begin("Components"))
|
||||
{
|
||||
ImGui.End();
|
||||
return;
|
||||
}
|
||||
|
||||
if(_editor.SelectedEntities.Count == 1)
|
||||
{
|
||||
Entity entity = _editor.SelectedEntities.Front;
|
||||
|
||||
ShowComponents(entity);
|
||||
}
|
||||
|
||||
ImGui.End();
|
||||
}
|
||||
|
||||
private void ShowComponents(Entity entity)
|
||||
{
|
||||
NameComponentEditor.Show(_editor.World, entity);
|
||||
TransformComponentEditor.Show(_editor.World, entity);
|
||||
}
|
||||
}
|
||||
|
||||
static class NameComponentEditor
|
||||
{
|
||||
public static void Show(EcsWorld world, Entity entity)
|
||||
{
|
||||
char8[128] nameBuffer = default;
|
||||
|
||||
DebugNameComponent* component = world.GetComponent<DebugNameComponent>(entity);
|
||||
|
||||
String name = null;
|
||||
|
||||
if(component != null)
|
||||
{
|
||||
name = component.DebugName;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = scope:: $"Entity {entity.[Friend]Index}";
|
||||
}
|
||||
|
||||
// Copy name to buffer
|
||||
Internal.MemCpy(&nameBuffer, name.Ptr, Math.Min(nameBuffer.Count, name.Length));
|
||||
|
||||
if(ImGui.InputText("Name", &nameBuffer, nameBuffer.Count))
|
||||
{
|
||||
if(component == null)
|
||||
{
|
||||
component = world.AssignComponent<DebugNameComponent>(entity);
|
||||
}
|
||||
|
||||
component.DebugName.Clear();
|
||||
component.DebugName.Append(&nameBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class TransformComponentEditor
|
||||
{
|
||||
public static void Show(EcsWorld world, Entity entity)
|
||||
{
|
||||
TransformComponent* component = world.GetComponent<TransformComponent>(entity);
|
||||
|
||||
if(component == null)
|
||||
return;
|
||||
|
||||
if(ImGui.TreeNodeEx("Transform", .DefaultOpen))
|
||||
{
|
||||
Vector3 position = component.Position;
|
||||
bool positionChanged = false;
|
||||
|
||||
Vector3 rotationEuler = MathHelper.ToDegrees(component.RotationEuler);
|
||||
bool rotationChanged = false;
|
||||
|
||||
Vector3 scale = component.Scale;
|
||||
bool scaleChanged = false;
|
||||
|
||||
void ShowValue(String text, ref float value, ref bool valueChanged, String id)
|
||||
{
|
||||
ImGui.Text(text);
|
||||
ImGui.SameLine();
|
||||
ImGui.PushID(id);
|
||||
valueChanged |= ImGui.DragFloat(String.Empty, &value, 0.1f);
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
void ShowTableRow(String name, ref Vector3 value, ref bool valueChanged)
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
|
||||
ImGui.Text(name);
|
||||
ImGui.TableNextColumn();
|
||||
ShowValue("X: ", ref value.X, ref valueChanged, scope $"{name}X");
|
||||
ImGui.TableNextColumn();
|
||||
ShowValue("Y: ", ref value.Y, ref valueChanged, scope $"{name}Y");
|
||||
ImGui.TableNextColumn();
|
||||
ShowValue("Z: ", ref value.Z, ref valueChanged, scope $"{name}Z");
|
||||
|
||||
ImGui.TableNextRow();
|
||||
}
|
||||
|
||||
ImGui.BeginTable("posRotScaleTable", 4);
|
||||
|
||||
ShowTableRow("Position", ref position, ref positionChanged);
|
||||
ShowTableRow("Rotation", ref rotationEuler, ref rotationChanged);
|
||||
ShowTableRow("Scale", ref scale, ref scaleChanged);
|
||||
|
||||
ImGui.EndTable();
|
||||
|
||||
if(positionChanged)
|
||||
component.Position = position;
|
||||
|
||||
if(rotationChanged)
|
||||
component.RotationEuler = MathHelper.ToRadians(rotationEuler);
|
||||
|
||||
if(scaleChanged)
|
||||
component.Scale = scale;
|
||||
|
||||
ImGui.TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,338 @@
|
||||
using GlitchyEngine.Collections;
|
||||
using GlitchyEngine.World;
|
||||
using ImGui;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using GlitchyEngine;
|
||||
|
||||
namespace GlitchyEditor.EditWindows
|
||||
{
|
||||
using internal GlitchyEditor;
|
||||
|
||||
/// A window for viewing and editing the scene hierarchy
|
||||
class EntityHierarchyWindow
|
||||
{
|
||||
private Editor _editor;
|
||||
|
||||
/// Buffer for the entity search string.
|
||||
private char8[64] _entitySearchChars;
|
||||
|
||||
private bool _show = true;
|
||||
|
||||
public Editor Editor => _editor;
|
||||
|
||||
public bool Show
|
||||
{
|
||||
get => _show;
|
||||
set => _show = value;
|
||||
}
|
||||
|
||||
public this(Editor editor)
|
||||
{
|
||||
_editor = editor;
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
if(!_show)
|
||||
return;
|
||||
|
||||
if(!ImGui.Begin("Entity Hierarchy", null, .MenuBar))
|
||||
{
|
||||
ImGui.End();
|
||||
return;
|
||||
}
|
||||
|
||||
ShowEntityHierarchyMenuBar();
|
||||
|
||||
ShowEntityHierarchy();
|
||||
|
||||
ImGui.End();
|
||||
}
|
||||
|
||||
private void ShowEntityHierarchyMenuBar()
|
||||
{
|
||||
if(ImGui.BeginMenuBar())
|
||||
{
|
||||
if(ImGui.BeginMenu("Create"))
|
||||
{
|
||||
if(ImGui.MenuItem("Empty Entity"))
|
||||
{
|
||||
_editor.CreateEntityWithTransform();
|
||||
}
|
||||
|
||||
if(ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Create a new Entity with a transform component.");
|
||||
|
||||
if(ImGui.MenuItem("Empty Child", null, false, !_editor.SelectedEntities.IsEmpty))
|
||||
{
|
||||
var newEntity = _editor.CreateEntityWithTransform();
|
||||
var parent = _editor.World.AssignComponent<ParentComponent>(newEntity);
|
||||
// Last entity in list is the entity that has been selected last.
|
||||
parent.Entity = _editor.SelectedEntities.Back;
|
||||
}
|
||||
|
||||
if(ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Create a new Entity that is a child of the currently selected entity.");
|
||||
|
||||
if(ImGui.MenuItem("Empty Parent", null, false, !_editor.SelectedEntities.IsEmpty && _editor.AllSelectionsOnSameLevel()))
|
||||
{
|
||||
var commonParent = _editor.World.GetComponent<ParentComponent>(_editor.SelectedEntities.Front);
|
||||
|
||||
var newEntity = _editor.CreateEntityWithTransform();
|
||||
|
||||
if(commonParent != null)
|
||||
{
|
||||
// parent of selected entities is parent of the new entity.
|
||||
// (which is why this doesn't work if the entities don't have the same parent)
|
||||
var newEntityParent = _editor.World.AssignComponent<ParentComponent>(newEntity);
|
||||
newEntityParent.Entity = commonParent.Entity;
|
||||
}
|
||||
|
||||
// new entity is parent of all selected entities.
|
||||
for(var selectedEntity in _editor.SelectedEntities)
|
||||
{
|
||||
var selectedEntityParent = _editor.World.AssignComponent<ParentComponent>(selectedEntity);
|
||||
selectedEntityParent.Entity = newEntity;
|
||||
}
|
||||
}
|
||||
|
||||
if(ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Create a new Entity that is the parent of the currently selected entities.");
|
||||
|
||||
ImGui.EndMenu();
|
||||
}
|
||||
|
||||
if(ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Create a new Entity.");
|
||||
|
||||
if(ImGui.MenuItem("Delete", null, false, !_editor.SelectedEntities.IsEmpty) || Input.IsKeyPressed(.Delete))
|
||||
{
|
||||
_editor.DeleteSelectedEntities();
|
||||
}
|
||||
|
||||
if(ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Deletes the selected Entities and their children.");
|
||||
|
||||
ImGui.Text("Search:");
|
||||
|
||||
ImGui.InputText(String.Empty, &_entitySearchChars, (.)_entitySearchChars.Count);
|
||||
|
||||
ImGui.EndMenuBar();
|
||||
}
|
||||
}
|
||||
|
||||
private void ImGuiPrintEntityTree(TreeNode<Entity> tree)
|
||||
{
|
||||
String name = null;
|
||||
|
||||
var nameComponent = _editor.World.GetComponent<DebugNameComponent>(tree.Value);
|
||||
|
||||
if(nameComponent != null)
|
||||
{
|
||||
name = nameComponent.DebugName;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = scope:: $"Entity {(tree.Value.[Friend]Index)}";
|
||||
}
|
||||
|
||||
ImGui.TreeNodeFlags flags = .OpenOnArrow;
|
||||
|
||||
if(tree.Children.Count == 0)
|
||||
flags |= .Leaf;
|
||||
|
||||
bool inSelectedList = _editor.SelectedEntities.Contains(tree.Value);
|
||||
|
||||
if(inSelectedList)
|
||||
flags |= .Selected;
|
||||
|
||||
bool isOpen = ImGui.TreeNodeEx(name, flags);
|
||||
|
||||
if(ImGui.BeginDragDropSource())
|
||||
{
|
||||
ImGui.SetDragDropPayload("DND_Entity", &tree.Value, sizeof(Entity));
|
||||
|
||||
ImGui.Text(name);
|
||||
|
||||
ImGui.EndDragDropSource();
|
||||
}
|
||||
|
||||
if(ImGui.BeginDragDropTarget())
|
||||
{
|
||||
ImGui.Payload* payload = &ImGui.AcceptDragDropPayload("DND_Entity");
|
||||
|
||||
if(payload != null)
|
||||
{
|
||||
Log.ClientLogger.AssertDebug(payload.DataSize == sizeof(Entity));
|
||||
|
||||
Entity movedEntity = *(Entity*)payload.Data;
|
||||
|
||||
bool dropLegal = true;
|
||||
|
||||
Entity walker = tree.Value;
|
||||
|
||||
// make sure the dropped entity is not a parent of the entity we dropped it on.
|
||||
while(true)
|
||||
{
|
||||
var walkerParent = _editor.World.GetComponent<ParentComponent>(walker);
|
||||
|
||||
if(walkerParent == null)
|
||||
{
|
||||
dropLegal = true;
|
||||
break;
|
||||
}
|
||||
else if(walkerParent.Entity == movedEntity)
|
||||
{
|
||||
dropLegal = false;
|
||||
break;
|
||||
}
|
||||
|
||||
walker = walkerParent.Entity;
|
||||
}
|
||||
|
||||
if(dropLegal)
|
||||
{
|
||||
var movedEntityParent = _editor.World.AssignComponent<ParentComponent>(movedEntity);
|
||||
movedEntityParent.Entity = tree.Value;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndDragDropTarget();
|
||||
}
|
||||
|
||||
bool clicked = ImGui.IsItemClicked();
|
||||
|
||||
if(isOpen)
|
||||
{
|
||||
for(var child in tree.Children)
|
||||
{
|
||||
ImGuiPrintEntityTree(child);
|
||||
}
|
||||
|
||||
ImGui.TreePop();
|
||||
}
|
||||
|
||||
if(clicked)
|
||||
{
|
||||
if(inSelectedList)
|
||||
{
|
||||
_editor.SelectedEntities.Remove(tree.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!ImGui.GetIO().KeyCtrl)
|
||||
{
|
||||
_editor.SelectedEntities.Clear();
|
||||
}
|
||||
|
||||
_editor.SelectedEntities.Add(tree.Value);
|
||||
}
|
||||
|
||||
inSelectedList = !inSelectedList;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowEntityHierarchy()
|
||||
{
|
||||
StringView searchString = StringView(&_entitySearchChars);
|
||||
|
||||
if(searchString.Length == 0)
|
||||
{
|
||||
// Show entity hierarchy as tree
|
||||
|
||||
TreeNode<Entity> root = scope .(.InvalidEntity);
|
||||
|
||||
TreeNode<Entity> AddEntity(Entity entity)
|
||||
{
|
||||
var parent = _editor.World.GetComponent<ParentComponent>(entity);
|
||||
|
||||
if(parent == null)
|
||||
{
|
||||
return root.AddChild(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
var parentNode = root.FindNode(parent.Entity);
|
||||
|
||||
if(parentNode == null)
|
||||
parentNode = AddEntity(parent.Entity);
|
||||
|
||||
return parentNode.AddChild(entity);
|
||||
}
|
||||
}
|
||||
|
||||
for(var entity in _editor.World.Enumerate())
|
||||
{
|
||||
AddEntity(entity);
|
||||
}
|
||||
|
||||
if(ImGui.TreeNodeEx("Scene", .DefaultOpen))
|
||||
{
|
||||
if(ImGui.BeginDragDropTarget())
|
||||
{
|
||||
ImGui.Payload* payload = &ImGui.AcceptDragDropPayload("DND_Entity");
|
||||
|
||||
if(payload != null)
|
||||
{
|
||||
Log.ClientLogger.AssertDebug(payload.DataSize == sizeof(Entity));
|
||||
|
||||
Entity movedEntity = *(Entity*)payload.Data;
|
||||
|
||||
_editor.World.RemoveComponent<ParentComponent>(movedEntity);
|
||||
|
||||
// Also mark transform as dirty
|
||||
var transformComponent = _editor.World.GetComponent<TransformComponent>(movedEntity);
|
||||
transformComponent?.IsDirty = true;
|
||||
}
|
||||
|
||||
ImGui.EndDragDropTarget();
|
||||
}
|
||||
|
||||
for(var child in root.Children)
|
||||
{
|
||||
ImGuiPrintEntityTree(child);
|
||||
}
|
||||
|
||||
ImGui.TreePop();
|
||||
}
|
||||
}
|
||||
// Otherwise
|
||||
else
|
||||
{
|
||||
// Show search results as flat list
|
||||
|
||||
List<StringView> searchTokens = new:ScopedAlloc! .(searchString.Split(' ', .RemoveEmptyEntries));
|
||||
|
||||
worldEnumeration:
|
||||
for(var entity in _editor.World.Enumerate())
|
||||
{
|
||||
String name = null;
|
||||
|
||||
var nameComponent = _editor.World.GetComponent<DebugNameComponent>(entity);
|
||||
|
||||
if(nameComponent != null)
|
||||
{
|
||||
name = nameComponent.DebugName;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = scope:worldEnumeration $"Entity {entity.[Friend]Index}";
|
||||
}
|
||||
|
||||
StringView nameView = StringView(name);
|
||||
|
||||
for(var token in searchTokens)
|
||||
{
|
||||
if(nameView.IndexOf(token, true) == -1)
|
||||
{
|
||||
continue worldEnumeration;
|
||||
}
|
||||
}
|
||||
|
||||
ImGuiPrintEntityTree(scope .(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using GlitchyEngine.World;
|
||||
using ImGui;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using GlitchyEngine.Collections;
|
||||
using GlitchyEditor.EditWindows;
|
||||
|
||||
namespace GlitchyEditor
|
||||
{
|
||||
class Editor
|
||||
{
|
||||
private EcsWorld _world;
|
||||
|
||||
private EntityHierarchyWindow _entityHierarchyWindow = new .(this) ~ delete _;
|
||||
private ComponentEditWindow _componentEditWindow = new .(this) ~ delete _;
|
||||
|
||||
private List<Entity> _selectedEntities = new .() ~ delete _;
|
||||
|
||||
public EcsWorld World => _world;
|
||||
|
||||
public List<Entity> SelectedEntities => _selectedEntities;
|
||||
|
||||
/// Creates a new editor for the given world
|
||||
public this(EcsWorld world)
|
||||
{
|
||||
_world = world;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
_entityHierarchyWindow.Show();
|
||||
_componentEditWindow.Show();
|
||||
}
|
||||
|
||||
/// Creates a new entity with a transform component.
|
||||
internal Entity CreateEntityWithTransform()
|
||||
{
|
||||
var entity = _world.NewEntity();
|
||||
|
||||
var transformComponent = ref *_world.AssignComponent<TransformComponent>(entity);
|
||||
transformComponent = TransformComponent();
|
||||
|
||||
var nameComponent = ref *_world.AssignComponent<DebugNameComponent>(entity);
|
||||
nameComponent.SetName("Entity");
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
/// Returns whether or not all selected entities have the same parent.
|
||||
internal bool AllSelectionsOnSameLevel()
|
||||
{
|
||||
Entity? parent = .InvalidEntity;
|
||||
|
||||
for(var selectedEntity in _selectedEntities)
|
||||
{
|
||||
var parentComponent = _world.GetComponent<ParentComponent>(selectedEntity);
|
||||
|
||||
if(parent == .InvalidEntity)
|
||||
{
|
||||
parent = parentComponent?.Entity;
|
||||
}
|
||||
else if(parentComponent?.Entity != parent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Finds all children of the given entity and stores their IDs in the given list.
|
||||
internal void FindChildren(Entity entity, List<Entity> entities)
|
||||
{
|
||||
for(var (child, childParent) in _world.Enumerate<ParentComponent>())
|
||||
{
|
||||
if(childParent.Entity == entity)
|
||||
{
|
||||
if(!entities.Contains(child))
|
||||
entities.Add(child);
|
||||
|
||||
FindChildren(child, entities);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Deletes all selected entities and their children.
|
||||
internal void DeleteSelectedEntities()
|
||||
{
|
||||
List<Entity> entities = scope .();
|
||||
|
||||
for(var entity in _selectedEntities)
|
||||
{
|
||||
entities.Add(entity);
|
||||
|
||||
FindChildren(entity, entities);
|
||||
}
|
||||
|
||||
for(var entity in entities)
|
||||
{
|
||||
_world.RemoveEntity(entity);
|
||||
}
|
||||
|
||||
_selectedEntities.Clear();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using GlitchyEngine;
|
||||
|
||||
namespace GlitchyEditor
|
||||
{
|
||||
class SandboxApp : Application
|
||||
{
|
||||
public this()
|
||||
{
|
||||
PushLayer(new EditorLayer());
|
||||
}
|
||||
|
||||
[Export, LinkName("CreateApplication")]
|
||||
public static Application CreateApplication()
|
||||
{
|
||||
return new SandboxApp();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using GlitchyEditor.EditWindows;
|
||||
using GlitchyEngine;
|
||||
using GlitchyEngine.Events;
|
||||
using GlitchyEngine.ImGui;
|
||||
using GlitchyEngine.Renderer;
|
||||
using GlitchyEngine.World;
|
||||
using ImGui;
|
||||
|
||||
namespace GlitchyEditor
|
||||
{
|
||||
class EditorLayer : Layer
|
||||
{
|
||||
RasterizerState _rasterizerState ~ _?.ReleaseRef();
|
||||
RasterizerState _rasterizerStateClockWise ~ _?.ReleaseRef();
|
||||
|
||||
GraphicsContext _context ~ _?.ReleaseRef();
|
||||
DepthStencilTarget _depthTarget ~ _?.ReleaseRef();
|
||||
|
||||
BlendState _alphaBlendState ~ _?.ReleaseRef();
|
||||
BlendState _opaqueBlendState ~ _?.ReleaseRef();
|
||||
|
||||
EcsWorld _world = new EcsWorld() ~ delete _;
|
||||
|
||||
Editor _editor = new Editor(_world) ~ delete _;
|
||||
|
||||
public this() : base("Example")
|
||||
{
|
||||
Application.Get().Window.IsVSync = false;
|
||||
|
||||
InitGraphics();
|
||||
InitEcs();
|
||||
}
|
||||
|
||||
private void InitGraphics()
|
||||
{
|
||||
_context = Application.Get().Window.Context..AddRef();
|
||||
|
||||
_depthTarget = new DepthStencilTarget(_context, _context.SwapChain.Width, _context.SwapChain.Height);
|
||||
|
||||
RasterizerStateDescription rsDesc = .(.Solid, .Back, true);
|
||||
_rasterizerState = new RasterizerState(_context, rsDesc);
|
||||
|
||||
rsDesc.FrontCounterClockwise = false;
|
||||
_rasterizerStateClockWise = new RasterizerState(_context, rsDesc);
|
||||
|
||||
BlendStateDescription blendDesc = .();
|
||||
blendDesc.RenderTarget[0] = .(true, .SourceAlpha, .InvertedSourceAlpha, .Add, .SourceAlpha, .InvertedSourceAlpha, .Add, .All);
|
||||
_alphaBlendState = new BlendState(_context, blendDesc);
|
||||
_opaqueBlendState = new BlendState(_context, .Default);
|
||||
}
|
||||
|
||||
private void InitEcs()
|
||||
{
|
||||
_world.Register<DebugNameComponent>();
|
||||
_world.Register<TransformComponent>();
|
||||
_world.Register<ParentComponent>();
|
||||
_world.Register<MeshComponent>();
|
||||
_world.Register<MeshRendererComponent>();
|
||||
_world.Register<SkinnedMeshRendererComponent>();
|
||||
_world.Register<CameraComponent>();
|
||||
_world.Register<AnimationComponent>();
|
||||
}
|
||||
|
||||
public override void Update(GameTime gameTime)
|
||||
{
|
||||
RenderCommand.Clear(null, .(0.2f, 0.2f, 0.2f));
|
||||
_depthTarget.Clear(1.0f, 0, .Depth);
|
||||
|
||||
_context.SetRenderTarget(null);
|
||||
_depthTarget.Bind();
|
||||
_context.BindRenderTargets();
|
||||
|
||||
_context.SetViewport(_context.SwapChain.BackbufferViewport);
|
||||
}
|
||||
|
||||
public override void OnEvent(Event event)
|
||||
{
|
||||
EventDispatcher dispatcher = EventDispatcher(event);
|
||||
|
||||
dispatcher.Dispatch<ImGuiRenderEvent>(scope (e) => OnImGuiRender(e));
|
||||
}
|
||||
|
||||
private bool OnImGuiRender(ImGuiRenderEvent event)
|
||||
{
|
||||
_editor.Update();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user