mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-06 05:01:53 +00:00
301 lines
7.7 KiB
Beef
301 lines
7.7 KiB
Beef
using System;
|
|
using ImGui;
|
|
using GlitchyEngine.Renderer;
|
|
using GlitchyEngine.Math;
|
|
using GlitchyEngine;
|
|
using GlitchyEngine.World;
|
|
using ImGuizmo;
|
|
using GlitchyEngine.Events;
|
|
|
|
namespace GlitchyEditor.EditWindows
|
|
{
|
|
class SceneViewportWindow : EditorWindow
|
|
{
|
|
public const String s_WindowTitle = "Scene";
|
|
|
|
private RenderTargetGroup _renderTarget ~ _?.ReleaseRef();
|
|
|
|
public Event<EventHandler<Vector2>> ViewportSizeChangedEvent ~ _.Dispose();
|
|
public Event<EventHandler<uint32>> EntityClickedEvent ~ _.Dispose();
|
|
|
|
public RenderTargetGroup RenderTarget
|
|
{
|
|
get => _renderTarget;
|
|
set
|
|
{
|
|
if(_renderTarget == value)
|
|
return;
|
|
|
|
SetReference!(_renderTarget, value);
|
|
}
|
|
}
|
|
|
|
public this(Editor editor)
|
|
{
|
|
_editor = editor;
|
|
}
|
|
|
|
private ImGui.Vec2 oldViewportSize = .(100, 100);
|
|
private bool viewPortChanged;
|
|
|
|
public uint32 SelectedEntityId;
|
|
public bool SelectionChanged;
|
|
|
|
public Vector2 ViewportSize => (Vector2)oldViewportSize;
|
|
|
|
protected override void InternalShow()
|
|
{
|
|
ImGui.PushStyleVar(.WindowPadding, ImGui.Vec2(1, 1));
|
|
defer ImGui.PopStyleVar();
|
|
|
|
if(!ImGui.Begin(s_WindowTitle, &_open, .NoScrollbar | .MenuBar))
|
|
{
|
|
ImGui.End();
|
|
return;
|
|
}
|
|
|
|
ShowMenuBar();
|
|
|
|
if(ImGui.IsWindowHovered() && Input.IsMouseButtonPressing(.RightButton))
|
|
{
|
|
var currentWindow = ImGui.GetCurrentWindow();
|
|
ImGui.FocusWindow(currentWindow);
|
|
}
|
|
|
|
_hasFocus = ImGui.IsWindowFocused();
|
|
|
|
if (_hasFocus && !_editor.CurrentCamera.InUse)
|
|
{
|
|
if (Input.IsKeyPressing(.Q))
|
|
_gizmoType = .TRANSLATE;
|
|
if (Input.IsKeyPressing(.W))
|
|
_gizmoType = .ROTATE;
|
|
if (Input.IsKeyPressing(.E))
|
|
_gizmoType = .SCALE;
|
|
|
|
if (Input.IsKeyPressing(.G))
|
|
_gizmoMode = .WORLD;
|
|
if (Input.IsKeyPressing(.L))
|
|
_gizmoMode = .LOCAL;
|
|
}
|
|
|
|
var viewportSize = ImGui.GetContentRegionAvail();
|
|
|
|
if (_editor.CurrentCamera.[Friend]BindMouse)
|
|
WrapMouseInViewport();
|
|
|
|
if(_renderTarget != null)
|
|
{
|
|
ImGui.Image(_renderTarget.GetViewBinding(0), viewportSize);
|
|
//ImGui.Image(_editor.CurrentCamera.RenderTarget.GetViewBinding(0), viewportSize);
|
|
//ImGui.Image(_editor.CurrentScene.[Friend]_compositeTarget.GetViewBinding(0), viewportSize);
|
|
}
|
|
|
|
if (ImGui.BeginDragDropTarget())
|
|
{
|
|
ImGui.Payload* payload = ImGui.AcceptDragDropPayload("CONTENT_BROWSER_ITEM");
|
|
|
|
if (payload != null)
|
|
{
|
|
Log.EngineLogger.Warning("");
|
|
|
|
StringView path = .((char8*)payload.Data, (int)payload.DataSize);
|
|
_editor.RequestOpenScene(this, path);
|
|
}
|
|
|
|
ImGui.EndDragDropTarget();
|
|
}
|
|
|
|
bool gizmoUsed = DrawImGuizmo(viewportSize);
|
|
|
|
MousePicking(viewportSize, gizmoUsed);
|
|
|
|
ImGui.End();
|
|
|
|
if(oldViewportSize != viewportSize)
|
|
{
|
|
ViewportSizeChangedEvent.Invoke(this, (Vector2)viewportSize);
|
|
viewPortChanged = true;
|
|
oldViewportSize = viewportSize;
|
|
}
|
|
}
|
|
|
|
/// Wraps the mouse, so that it always stays in the viewport.
|
|
private void WrapMouseInViewport()
|
|
{
|
|
var mousePos = (Vector2)ImGui.GetMousePos();
|
|
var winPos = (Vector2)ImGui.GetWindowPos();
|
|
var winSize = (Vector2)ImGui.GetWindowSize();
|
|
|
|
Vector2 newMousePos = mousePos;
|
|
|
|
if (mousePos.X < winPos.X)
|
|
{
|
|
newMousePos.X = winPos.X + winSize.X - 1;
|
|
}
|
|
else if (mousePos.X > winPos.X + winSize.X)
|
|
{
|
|
newMousePos.X = winPos.X + 1;
|
|
}
|
|
|
|
if (mousePos.Y < winPos.Y)
|
|
{
|
|
newMousePos.Y = winPos.Y + winSize.Y - 1;
|
|
}
|
|
else if (mousePos.Y > winPos.Y + winSize.Y)
|
|
{
|
|
newMousePos.Y = winPos.Y + 1;
|
|
}
|
|
|
|
if (newMousePos != mousePos)
|
|
{
|
|
Input.SetMousePosition((Int2)newMousePos);
|
|
_editor.CurrentCamera.[Friend]MouseCooldown = 2;
|
|
}
|
|
}
|
|
|
|
private void MousePicking(ImGui.Vec2 viewportSize, bool gizmoUsed)
|
|
{
|
|
Vector2 relativeMouse = (Vector2)ImGui.GetMousePos() - (Vector2)ImGui.GetItemRectMin();
|
|
|
|
int rtWidth = _editor.CurrentScene.[Friend]_compositeTarget.Width;
|
|
int rtHeight = _editor.CurrentScene.[Friend]_compositeTarget.Height;
|
|
|
|
if (Input.IsMouseButtonPressing(.LeftButton) &&
|
|
ImGui.IsWindowHovered() && !gizmoUsed && !_editor.CurrentCamera.InUse &&
|
|
relativeMouse.X >= 0 && relativeMouse.Y >= 0 &&
|
|
relativeMouse.X < viewportSize.x && relativeMouse.Y < viewportSize.y &&
|
|
relativeMouse.X < rtWidth && relativeMouse.Y < rtHeight)
|
|
{
|
|
uint32 id = uint32.MaxValue;
|
|
|
|
_editor.CurrentScene.[Friend]_compositeTarget.GetData<uint32>(&id, 1, (.)relativeMouse.X, (.)relativeMouse.Y, 1, 1);
|
|
|
|
SelectionChanged = true;
|
|
SelectedEntityId = id;
|
|
|
|
EntityClickedEvent(this, id);
|
|
}
|
|
else
|
|
{
|
|
SelectionChanged = false;
|
|
}
|
|
}
|
|
|
|
private ImGuizmo.OPERATION _gizmoType = .TRANSLATE;
|
|
private ImGuizmo.MODE _gizmoMode = .LOCAL;
|
|
private float _snap = 0.5f;
|
|
private float _angleSnap = 45.0f;
|
|
private bool _doSnap = false;
|
|
|
|
private void ShowMenuBar()
|
|
{
|
|
if(ImGui.BeginMenuBar())
|
|
{
|
|
if (ImGui.RadioButton("Position", _gizmoType.HasFlag(.TRANSLATE)))
|
|
{
|
|
if (Input.IsKeyPressed(Key.Control))
|
|
_gizmoType ^= .TRANSLATE;
|
|
else
|
|
_gizmoType = .TRANSLATE;
|
|
}
|
|
|
|
if (ImGui.RadioButton("Rotation", _gizmoType.HasFlag(.ROTATE)))
|
|
{
|
|
if (Input.IsKeyPressed(Key.Control))
|
|
_gizmoType ^= .ROTATE;
|
|
else
|
|
_gizmoType = .ROTATE;
|
|
}
|
|
|
|
if (ImGui.RadioButton("Scale", _gizmoType.HasFlag(.SCALE)))
|
|
{
|
|
if (Input.IsKeyPressed(Key.Control))
|
|
_gizmoType ^= .SCALE;
|
|
else
|
|
_gizmoType = .SCALE;
|
|
}
|
|
|
|
if (ImGui.RadioButton("All", _gizmoType == .TRANSLATE | .ROTATE | .SCALE))
|
|
_gizmoType = .TRANSLATE | .ROTATE | .SCALE;
|
|
|
|
// If we scale, the mode must be local otherwise we could skew the matrix.
|
|
if (_gizmoType.HasFlag(.SCALE))
|
|
_gizmoMode = .LOCAL;
|
|
|
|
if (ImGui.MenuItem(_gizmoMode == .WORLD ? "Global" : "Local", null, true, !_gizmoType.HasFlag(.SCALE)))
|
|
{
|
|
if (_gizmoMode == .WORLD)
|
|
_gizmoMode = .LOCAL;
|
|
else
|
|
_gizmoMode = .WORLD;
|
|
}
|
|
|
|
_doSnap = Input.IsKeyPressed(.Shift);
|
|
|
|
ImGui.PushItemWidth(100);
|
|
|
|
if (_gizmoType.HasFlag(.ROTATE))
|
|
{
|
|
ImGui.DragFloat("Angle Snap", &_angleSnap, 1.0f, 0.0f, 180.0f);
|
|
}
|
|
|
|
if (_gizmoType.HasFlag(.TRANSLATE) || _gizmoType.HasFlag(.SCALE))
|
|
{
|
|
ImGui.DragFloat("Snap", &_snap, 0.1f, 0.0f, float.MaxValue);
|
|
}
|
|
|
|
ImGui.PopItemWidth();
|
|
|
|
ImGui.EndMenuBar();
|
|
}
|
|
}
|
|
|
|
private bool DrawImGuizmo(ImGui.Vec2 viewportSize)
|
|
{
|
|
ImGuizmo.SetOrthographic(false);
|
|
ImGuizmo.SetDrawlist();
|
|
|
|
var topLeft = ImGui.GetWindowPos();
|
|
var cntMin = ImGui.GetWindowContentRegionMin();
|
|
|
|
topLeft.x += cntMin.x;
|
|
topLeft.y += cntMin.y;
|
|
ImGuizmo.SetRect(topLeft.x, topLeft.y, viewportSize.x, viewportSize.y);
|
|
|
|
var view = _editor.CurrentCamera.View;
|
|
var projection = _editor.CurrentCamera.Projection;
|
|
|
|
if(_editor.EntityHierarchyWindow.SelectedEntities.Count == 0)
|
|
return false;
|
|
|
|
var entity = _editor.EntityHierarchyWindow.SelectedEntities.Back;
|
|
|
|
var transformCmp = entity.GetComponent<TransformComponent>();
|
|
|
|
var worldTransform = transformCmp.WorldTransform;
|
|
|
|
Matrix parentView = .Identity;
|
|
if (transformCmp.Parent != .InvalidEntity)
|
|
{
|
|
var parentTransformCmp = Entity(transformCmp.Parent, entity.Scene).GetComponent<TransformComponent>();
|
|
parentView = parentTransformCmp.WorldTransform.Invert();
|
|
}
|
|
|
|
Vector3 snap = .(_snap);
|
|
if (_gizmoType.HasFlag(.ROTATE))
|
|
snap = .(_angleSnap);
|
|
|
|
if (ImGuizmo.Manipulate((.)&view, (.)&projection, _gizmoType, _gizmoMode, (.)&worldTransform, null, _doSnap ? (.)&snap : null))
|
|
{
|
|
// TODO: Fix when parent is scaled
|
|
// Seems to work fine for parent rotation and translation but scaled parent ruins everything
|
|
// (probably because scaling a rotated matrix results in a skewed matrix, but unity can do it, so should we)
|
|
transformCmp.LocalTransform = parentView * worldTransform;
|
|
}
|
|
|
|
return ImGuizmo.IsUsing();
|
|
}
|
|
}
|
|
}
|