mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Add / Remove Components
This commit is contained in:
@@ -2,6 +2,7 @@ using ImGui;
|
||||
using GlitchyEngine.World;
|
||||
using System;
|
||||
using GlitchyEngine.Math;
|
||||
using System.Collections;
|
||||
|
||||
namespace GlitchyEditor.EditWindows
|
||||
{
|
||||
@@ -13,9 +14,19 @@ namespace GlitchyEditor.EditWindows
|
||||
|
||||
private EntityHierarchyWindow _entityHierarchyWindow;
|
||||
|
||||
private List<(Type, ComponentAttribute attribute)> _componentTypes = new .() ~ delete _;
|
||||
|
||||
public this(EntityHierarchyWindow entityHierarchyWindow)
|
||||
{
|
||||
_entityHierarchyWindow = entityHierarchyWindow;
|
||||
|
||||
for (let type in Type.Types)
|
||||
{
|
||||
if (let componentAttribute = type.GetCustomAttribute<ComponentAttribute>())
|
||||
{
|
||||
_componentTypes.Add((type, componentAttribute));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void InternalShow()
|
||||
@@ -39,9 +50,56 @@ namespace GlitchyEditor.EditWindows
|
||||
private void ShowComponents(Entity entity)
|
||||
{
|
||||
ShowNameComponentEditor(entity);
|
||||
ShowTransformComponentEditor(entity);
|
||||
ShowCameraComponentEditor(entity);
|
||||
ShowSpriteRendererComponentEditor(entity);
|
||||
|
||||
ShowComponentEditor<TransformComponent>("Transform", entity, => ShowTransformComponentEditor);
|
||||
ShowComponentEditor<CameraComponent>("Camera", entity, => ShowCameraComponentEditor, => ShowComponentContextMenu<CameraComponent>);
|
||||
ShowComponentEditor<SpriterRendererComponent>("Sprite Renderer", entity, => ShowSpriteRendererComponentEditor, => ShowComponentContextMenu<SpriterRendererComponent>);
|
||||
|
||||
ShowAddComponentButton(entity);
|
||||
}
|
||||
|
||||
private static void ShowComponentContextMenu<TComponent>(Entity entity, TComponent* component) where TComponent: struct, new
|
||||
{
|
||||
if (ImGui.Selectable("Remove Component"))
|
||||
entity.RemoveComponent<TComponent>();
|
||||
}
|
||||
|
||||
private static void ShowComponentEditor<TComponent>(String header, Entity entity, function void(Entity, TComponent*) showComponentEditor, function void(Entity, TComponent*) showComponentContextMenu = null) where TComponent: struct, new
|
||||
{
|
||||
if (!entity.HasComponent<TComponent>())
|
||||
return;
|
||||
|
||||
TComponent* component = entity.GetComponent<TComponent>();
|
||||
|
||||
ImGui.PushID(header);
|
||||
|
||||
bool nodeOpen = ImGui.TreeNodeEx(header.CStr(), .DefaultOpen | .AllowItemOverlap | .Framed);
|
||||
|
||||
if (showComponentContextMenu != null)
|
||||
{
|
||||
ImGui.SameLine(ImGui.GetWindowContentRegionMax().x - ImGui.CalcTextSize("...").x);
|
||||
|
||||
if (ImGui.SmallButton("..."))
|
||||
{
|
||||
ImGui.OpenPopup("component_popup");
|
||||
}
|
||||
|
||||
if (ImGui.BeginPopup("component_popup"))
|
||||
{
|
||||
showComponentContextMenu(entity, component);
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
if (nodeOpen)
|
||||
{
|
||||
showComponentEditor(entity, component);
|
||||
|
||||
ImGui.TreePop();
|
||||
}
|
||||
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
private static void ShowNameComponentEditor(Entity entity)
|
||||
@@ -79,124 +137,25 @@ namespace GlitchyEditor.EditWindows
|
||||
}
|
||||
}
|
||||
|
||||
private static bool Vector3Control(StringView label, ref Vector3 value, Vector3 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
ImGui.PushID(label);
|
||||
defer ImGui.PopID();
|
||||
|
||||
ImGui.Columns(2);
|
||||
defer ImGui.Columns(1);
|
||||
ImGui.SetColumnWidth(0, columnWidth);
|
||||
|
||||
ImGui.TextUnformatted(label);
|
||||
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.PushMultiItemsWidths(3, ImGui.CalcItemWidth());
|
||||
ImGui.PushStyleVar(.ItemSpacing, ImGui.Vec2.Zero);
|
||||
defer ImGui.PopStyleVar();
|
||||
|
||||
float lineHeight = ImGui.GetFont().FontSize + ImGui.GetStyle().FramePadding.y * 2.0f;
|
||||
ImGui.Vec2 buttonSize = .(lineHeight + 3.0f, lineHeight);
|
||||
|
||||
ImGui.PushStyleColor(.Button, ImGui.Color(230, 25, 45).Value);
|
||||
ImGui.PushStyleColor(.ButtonHovered, ImGui.Color(150, 25, 45).Value);
|
||||
ImGui.PushStyleColor(.ButtonActive, ImGui.Color(230, 120, 130).Value);
|
||||
|
||||
if (ImGui.Button("X", buttonSize))
|
||||
{
|
||||
value.X = resetValues.X;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.DragFloat("##X", &value.X, dragSpeed))
|
||||
changed = true;
|
||||
|
||||
ImGui.PopItemWidth();
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.PopStyleColor(3);
|
||||
ImGui.PushStyleColor(.Button, ImGui.Color(50, 190, 15).Value);
|
||||
ImGui.PushStyleColor(.ButtonHovered, ImGui.Color(50, 120, 15).Value);
|
||||
ImGui.PushStyleColor(.ButtonActive, ImGui.Color(116, 190, 99).Value);
|
||||
|
||||
if (ImGui.Button("Y", buttonSize))
|
||||
{
|
||||
value.Y = resetValues.Y;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.DragFloat("##Y", &value.Y, dragSpeed))
|
||||
changed = true;
|
||||
|
||||
ImGui.PopItemWidth();
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.PopStyleColor(3);
|
||||
ImGui.PushStyleColor(.Button, ImGui.Color(55, 55, 230).Value);
|
||||
ImGui.PushStyleColor(.ButtonHovered, ImGui.Color(55, 55, 150).Value);
|
||||
ImGui.PushStyleColor(.ButtonActive, ImGui.Color(90, 90, 230).Value);
|
||||
|
||||
if (ImGui.Button("Z", buttonSize))
|
||||
{
|
||||
value.Z = resetValues.Z;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.DragFloat("##Z", &value.Z, dragSpeed))
|
||||
changed = true;
|
||||
|
||||
ImGui.PopItemWidth();
|
||||
|
||||
ImGui.PopStyleColor(3);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static void ShowTransformComponentEditor(Entity entity)
|
||||
{
|
||||
if (!entity.HasComponent<TransformComponent>())
|
||||
return;
|
||||
|
||||
var transform = entity.GetComponent<TransformComponent>();
|
||||
|
||||
if(ImGui.TreeNodeEx("Transform", .DefaultOpen))
|
||||
private static void ShowTransformComponentEditor(Entity entity, TransformComponent* transform)
|
||||
{
|
||||
Vector3 position = transform.Position;
|
||||
if (Vector3Control("Position", ref position))
|
||||
if (ImGui.EditVector3("Position", ref position))
|
||||
transform.Position = position;
|
||||
|
||||
Vector3 rotationEuler = MathHelper.ToDegrees(transform.EditorRotationEuler);
|
||||
if (Vector3Control("Rotation", ref rotationEuler))
|
||||
if (ImGui.EditVector3("Rotation", ref rotationEuler))
|
||||
transform.EditorRotationEuler = MathHelper.ToRadians(rotationEuler);
|
||||
|
||||
Vector3 scale = transform.Scale;
|
||||
if (Vector3Control("Scale", ref scale, .One))
|
||||
if (ImGui.EditVector3("Scale", ref scale, .One))
|
||||
transform.Scale = scale;
|
||||
|
||||
ImGui.TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
static String[] strings = new String[]("Orthographic", "Perspective", "Perspective (Infinite)") ~ delete _;
|
||||
|
||||
private static void ShowCameraComponentEditor(Entity entity)
|
||||
private static void ShowCameraComponentEditor(Entity entity, CameraComponent* cameraComponent)
|
||||
{
|
||||
if (!entity.HasComponent<CameraComponent>())
|
||||
return;
|
||||
|
||||
if(ImGui.TreeNodeEx("Camera", .DefaultOpen))
|
||||
{
|
||||
var cameraComponent = entity.GetComponent<CameraComponent>();
|
||||
|
||||
ImGui.Checkbox("Primary", &cameraComponent.Primary);
|
||||
|
||||
var camera = ref cameraComponent.Camera;
|
||||
@@ -270,24 +229,60 @@ namespace GlitchyEditor.EditWindows
|
||||
if (ImGui.DragFloat("Aspect Ratio", &aspect, 0.1f))
|
||||
camera.AspectRatio = aspect;
|
||||
}
|
||||
|
||||
ImGui.TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ShowSpriteRendererComponentEditor(Entity entity)
|
||||
private static void ShowSpriteRendererComponentEditor(Entity entity, SpriterRendererComponent* spriteRendererComponent)
|
||||
{
|
||||
if (!entity.HasComponent<SpriterRendererComponent>())
|
||||
return;
|
||||
ImGui.ColorEdit4("Color", ref spriteRendererComponent.Color);
|
||||
}
|
||||
|
||||
var spriterRendererComponent = entity.GetComponent<SpriterRendererComponent>();
|
||||
|
||||
if(ImGui.TreeNodeEx("Sprite Renderer", .DefaultOpen))
|
||||
private static void ShowAddComponentButton(Entity entity)
|
||||
{
|
||||
ImGui.ColorEdit4("Color", ref spriterRendererComponent.Color);
|
||||
static char8[128] searchBuffer = .();
|
||||
static StringView searchFilter = .();
|
||||
|
||||
ImGui.TreePop();
|
||||
static float buttonWidth = 100;
|
||||
|
||||
ImGui.NewLine();
|
||||
ImGui.Separator();
|
||||
ImGui.NewLine();
|
||||
|
||||
void ShowComponentButton<TComponent>(String name) where TComponent : struct, new
|
||||
{
|
||||
float textWidth = ImGui.CalcTextSize(name.CStr()).x;
|
||||
buttonWidth = Math.Max(buttonWidth, textWidth + ImGui.GetStyle().FramePadding.x * 2);
|
||||
|
||||
if (name.Contains(searchFilter, true) && ImGui.Selectable(name))
|
||||
{
|
||||
if (!entity.HasComponent<TComponent>())
|
||||
entity.AddComponent<TComponent>();
|
||||
}
|
||||
}
|
||||
|
||||
float textWidth = ImGui.CalcTextSize("Add Component...").x;
|
||||
buttonWidth = Math.Max(buttonWidth, textWidth + ImGui.GetStyle().FramePadding.x * 2);
|
||||
|
||||
ImGui.PushItemWidth(buttonWidth);
|
||||
|
||||
ImGui.NewLine();
|
||||
ImGui.SameLine(ImGui.GetContentRegionMax().x / 2 - buttonWidth / 2);
|
||||
|
||||
if (ImGui.BeginCombo("##add_component_combo", "Add Component...", .NoArrowButton))
|
||||
{
|
||||
if (ImGui.InputText("##search_component_name", &searchBuffer, (.)searchBuffer.Count))
|
||||
{
|
||||
searchFilter = .(&searchBuffer);
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
ShowComponentButton<CameraComponent>("Camera");
|
||||
ShowComponentButton<SpriterRendererComponent>("Sprite Renderer");
|
||||
|
||||
ImGui.EndCombo();
|
||||
}
|
||||
|
||||
ImGui.PopItemWidth();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace System
|
||||
{
|
||||
extension String
|
||||
{
|
||||
[Inline]
|
||||
public void CopyTo(Span<char8> target)
|
||||
{
|
||||
CopyTo(target.Ptr, target.Length);
|
||||
}
|
||||
|
||||
[Inline]
|
||||
public void CopyTo(char8* target, int targetLength)
|
||||
{
|
||||
int copiedChars = Math.Min(targetLength - 1, Length);
|
||||
|
||||
Internal.MemCpy(target, Ptr, copiedChars);
|
||||
|
||||
target[copiedChars] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,19 @@ namespace ImGui
|
||||
{
|
||||
extension ImGui
|
||||
{
|
||||
// TODO: Color-functions
|
||||
extension Vec2
|
||||
{
|
||||
public static explicit operator Vector2(Vec2 v) => .(v.x, v.y);
|
||||
public static explicit operator Vec2(Vector2 v) => .(v.X, v.Y);
|
||||
}
|
||||
|
||||
extension Vec4
|
||||
{
|
||||
public static explicit operator Vector4(Vec4 v) => .(v.x, v.y, v.z, v.w);
|
||||
public static explicit operator Vec4(Vector4 v) => .(v.X, v.Y, v.Z, v.W);
|
||||
}
|
||||
|
||||
// TODO: Color-functions
|
||||
public static bool ColorEdit3(char* label, ref ColorRGB col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit3Impl(label, *(float[3]*)&col, flags);
|
||||
public static bool ColorEdit3(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit3Impl(label, *(float[3]*)&col, flags);
|
||||
|
||||
@@ -29,16 +40,87 @@ namespace ImGui
|
||||
/// Releases references that accumulated calls like ImGui::Image
|
||||
protected internal static extern void CleanupFrame();
|
||||
|
||||
extension Vec2
|
||||
/// Control to edit a vector 3 with drag functionality and reset buttons
|
||||
public static bool EditVector3(StringView label, ref Vector3 value, Vector3 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f)
|
||||
{
|
||||
public static explicit operator Vector2(Vec2 v) => .(v.x, v.y);
|
||||
public static explicit operator Vec2(Vector2 v) => .(v.X, v.Y);
|
||||
bool changed = false;
|
||||
|
||||
PushID(label);
|
||||
defer PopID();
|
||||
|
||||
Columns(2);
|
||||
defer Columns(1);
|
||||
SetColumnWidth(0, columnWidth);
|
||||
|
||||
TextUnformatted(label);
|
||||
|
||||
NextColumn();
|
||||
|
||||
PushMultiItemsWidths(3, CalcItemWidth());
|
||||
PushStyleVar(.ItemSpacing, Vec2.Zero);
|
||||
defer PopStyleVar();
|
||||
|
||||
float lineHeight = GetFont().FontSize + GetStyle().FramePadding.y * 2.0f;
|
||||
ImGui.Vec2 buttonSize = .(lineHeight + 3.0f, lineHeight);
|
||||
|
||||
PushStyleColor(.Button, Color(230, 25, 45).Value);
|
||||
PushStyleColor(.ButtonHovered, Color(150, 25, 45).Value);
|
||||
PushStyleColor(.ButtonActive, Color(230, 120, 130).Value);
|
||||
|
||||
if (Button("X", buttonSize))
|
||||
{
|
||||
value.X = resetValues.X;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
extension Vec4
|
||||
SameLine();
|
||||
|
||||
if (DragFloat("##X", &value.X, dragSpeed))
|
||||
changed = true;
|
||||
|
||||
PopItemWidth();
|
||||
SameLine();
|
||||
|
||||
PopStyleColor(3);
|
||||
PushStyleColor(.Button, Color(50, 190, 15).Value);
|
||||
PushStyleColor(.ButtonHovered, Color(50, 120, 15).Value);
|
||||
PushStyleColor(.ButtonActive, Color(116, 190, 99).Value);
|
||||
|
||||
if (Button("Y", buttonSize))
|
||||
{
|
||||
public static explicit operator Vector4(Vec4 v) => .(v.x, v.y, v.z, v.w);
|
||||
public static explicit operator Vec4(Vector4 v) => .(v.X, v.Y, v.Z, v.W);
|
||||
value.Y = resetValues.Y;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
SameLine();
|
||||
|
||||
if (DragFloat("##Y", &value.Y, dragSpeed))
|
||||
changed = true;
|
||||
|
||||
PopItemWidth();
|
||||
SameLine();
|
||||
|
||||
PopStyleColor(3);
|
||||
PushStyleColor(.Button, Color(55, 55, 230).Value);
|
||||
PushStyleColor(.ButtonHovered, Color(55, 55, 150).Value);
|
||||
PushStyleColor(.ButtonActive, Color(90, 90, 230).Value);
|
||||
|
||||
if (Button("Z", buttonSize))
|
||||
{
|
||||
value.Z = resetValues.Z;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
SameLine();
|
||||
|
||||
if (DragFloat("##Z", &value.Z, dragSpeed))
|
||||
changed = true;
|
||||
|
||||
PopItemWidth();
|
||||
|
||||
PopStyleColor(3);
|
||||
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,17 @@ using System;
|
||||
|
||||
namespace GlitchyEngine.World
|
||||
{
|
||||
[AttributeUsage(.Struct, .ReflectAttribute, ReflectUser=.Methods | .NonStaticFields)]
|
||||
struct ComponentAttribute : Attribute
|
||||
{
|
||||
public String Name;
|
||||
|
||||
public this(String name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
/// If an entity has the EditorComponent it won't be displayed in the scene hierarchy.
|
||||
struct EditorComponent
|
||||
{
|
||||
@@ -14,6 +25,7 @@ namespace GlitchyEngine.World
|
||||
}
|
||||
}
|
||||
|
||||
[Component("Sprite Renderer")]
|
||||
struct SpriterRendererComponent : IDisposableComponent
|
||||
{
|
||||
public Texture2D Sprite = null;
|
||||
|
||||
Reference in New Issue
Block a user