diff --git a/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf b/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf index 62769b3..5a7b2d4 100644 --- a/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf +++ b/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf @@ -7,16 +7,18 @@ namespace GlitchyEditor.EditWindows { class ComponentEditWindow { + public const String s_WindowTitle = "Components"; + private Editor _editor; - private bool _show = true; + private bool _open = true; public Editor Editor => _editor; - public bool Show + public bool Open { - get => _show; - set => _show = value; + get => _open; + set => _open = value; } public this(Editor editor) @@ -26,10 +28,10 @@ namespace GlitchyEditor.EditWindows public void Show() { - if(!_show) + if(!_open) return; - if(!ImGui.Begin("Components")) + if(!ImGui.Begin(s_WindowTitle, &_open, .None)) { ImGui.End(); return; diff --git a/GlitchyEditor/src/EditWindows/EntityHierarchyWindow.bf b/GlitchyEditor/src/EditWindows/EntityHierarchyWindow.bf index 8ea9422..b1e74ca 100644 --- a/GlitchyEditor/src/EditWindows/EntityHierarchyWindow.bf +++ b/GlitchyEditor/src/EditWindows/EntityHierarchyWindow.bf @@ -12,19 +12,21 @@ namespace GlitchyEditor.EditWindows /// A window for viewing and editing the scene hierarchy class EntityHierarchyWindow { + public const String s_WindowTitle = "Entity Hierarchy"; + private Editor _editor; /// Buffer for the entity search string. private char8[64] _entitySearchChars; - private bool _show = true; + private bool _open = true; public Editor Editor => _editor; - public bool Show + public bool Open { - get => _show; - set => _show = value; + get => _open; + set => _open = value; } public this(Editor editor) @@ -34,10 +36,10 @@ namespace GlitchyEditor.EditWindows public void Show() { - if(!_show) + if(!_open) return; - if(!ImGui.Begin("Entity Hierarchy", null, .MenuBar)) + if(!ImGui.Begin(s_WindowTitle, &_open, .MenuBar)) { ImGui.End(); return; diff --git a/GlitchyEditor/src/EditWindows/SceneViewportWindow.bf b/GlitchyEditor/src/EditWindows/SceneViewportWindow.bf new file mode 100644 index 0000000..3c0ddbf --- /dev/null +++ b/GlitchyEditor/src/EditWindows/SceneViewportWindow.bf @@ -0,0 +1,99 @@ +using System; +using ImGui; +using GlitchyEngine.Renderer; +using GlitchyEngine.Math; +using GlitchyEngine; + +namespace GlitchyEditor.EditWindows +{ + class SceneViewportWindow + { + public const String s_WindowTitle = "Scene"; + + private bool _open = true; + + private Texture2D _texture ~ _?.ReleaseRef(); + + private bool _hasFocus; + + public Event> ViewportSizeChangedEvent ~ _.Dispose(); + + public bool Open + { + get => _open; + set => _open = value; + } + + public bool HasFocus + { + get => _hasFocus; + } + + public Texture2D Texture + { + get => _texture; + set + { + if(_texture == value) + return; + + _texture?.ReleaseRef(); + _texture = value; + _texture?.AddRef(); + } + } + + public this() + { + } + + private ImGui.Vec2 oldViewportSize; + + Texture2D _lastTexture; + + public void Show() + { + // Hold a reference to the texture until the next frame. + // This is a workaround for the issue that changing the window size will release the texture + _lastTexture?.ReleaseRef(); + _lastTexture = _texture; + _lastTexture.AddRef(); + + if(!_open) + return; + + ImGui.PushStyleVar(.WindowPadding, ImGui.Vec2(1, 1)); + defer ImGui.PopStyleVar(); + + if(!ImGui.Begin(s_WindowTitle, &_open, .NoScrollbar)) + { + ImGui.End(); + return; + } + + if(ImGui.IsWindowHovered() && Input.IsMouseButtonPressing(.RightButton)) + { + var currentWindow = ImGui.GetCurrentWindow(); + ImGui.FocusWindow(currentWindow); + } + + _hasFocus = ImGui.IsWindowFocused(); + + var viewportSize = ImGui.GetContentRegionAvail(); + + if(_lastTexture != null) + { + ImGui.Image(_lastTexture, viewportSize); + } + + ImGui.End(); + + if(oldViewportSize != viewportSize) + { + ViewportSizeChangedEvent.Invoke(this, *(Vector2*)&viewportSize); + + oldViewportSize = viewportSize; + } + } + } +} diff --git a/GlitchyEditor/src/Editor.bf b/GlitchyEditor/src/Editor.bf index 6e8b9f9..5cd49d7 100644 --- a/GlitchyEditor/src/Editor.bf +++ b/GlitchyEditor/src/Editor.bf @@ -13,6 +13,7 @@ namespace GlitchyEditor private EntityHierarchyWindow _entityHierarchyWindow = new .(this) ~ delete _; private ComponentEditWindow _componentEditWindow = new .(this) ~ delete _; + private SceneViewportWindow _sceneViewportWindow = new .() ~ delete _; private List _selectedEntities = new .() ~ delete _; @@ -20,6 +21,10 @@ namespace GlitchyEditor public List SelectedEntities => _selectedEntities; + public EntityHierarchyWindow EntityHierarchyWindow => _entityHierarchyWindow; + public ComponentEditWindow ComponentEditWindow => _componentEditWindow; + public SceneViewportWindow SceneViewportWindow => _sceneViewportWindow; + /// Creates a new editor for the given world public this(EcsWorld world) { @@ -30,6 +35,7 @@ namespace GlitchyEditor { _entityHierarchyWindow.Show(); _componentEditWindow.Show(); + _sceneViewportWindow.Show(); } /// Creates a new entity with a transform component. diff --git a/GlitchyEditor/src/EditorLayer.bf b/GlitchyEditor/src/EditorLayer.bf index 8fa24f5..63cc603 100644 --- a/GlitchyEditor/src/EditorLayer.bf +++ b/GlitchyEditor/src/EditorLayer.bf @@ -2,9 +2,12 @@ using GlitchyEditor.EditWindows; using GlitchyEngine; using GlitchyEngine.Events; using GlitchyEngine.ImGui; +using GlitchyEngine.Math; using GlitchyEngine.Renderer; using GlitchyEngine.World; using ImGui; +using System; +using GlitchyEngine.Renderer.Text; namespace GlitchyEditor { @@ -14,28 +17,34 @@ namespace GlitchyEditor RasterizerState _rasterizerStateClockWise ~ _?.ReleaseRef(); GraphicsContext _context ~ _?.ReleaseRef(); - DepthStencilTarget _depthTarget ~ _?.ReleaseRef(); + DepthStencilTarget _swapchainDepthBuffer ~ _?.ReleaseRef(); BlendState _alphaBlendState ~ _?.ReleaseRef(); BlendState _opaqueBlendState ~ _?.ReleaseRef(); EcsWorld _world = new EcsWorld() ~ delete _; - Editor _editor = new Editor(_world) ~ delete _; + Editor _editor ~ delete _; + + PerspectiveCameraController _cameraController ~ delete _; + + RenderTarget2D _renderTarget2D ~ _?.ReleaseRef(); + DepthStencilTarget _depthTarget ~ _?.ReleaseRef(); public this() : base("Example") { Application.Get().Window.IsVSync = false; - + InitGraphics(); InitEcs(); + InitEditor(); } private void InitGraphics() { _context = Application.Get().Window.Context..AddRef(); - _depthTarget = new DepthStencilTarget(_context, _context.SwapChain.Width, _context.SwapChain.Height); + _swapchainDepthBuffer = new DepthStencilTarget(_context, _context.SwapChain.Width, _context.SwapChain.Height); RasterizerStateDescription rsDesc = .(.Solid, .Back, true); _rasterizerState = new RasterizerState(_context, rsDesc); @@ -47,6 +56,17 @@ namespace GlitchyEditor blendDesc.RenderTarget[0] = .(true, .SourceAlpha, .InvertedSourceAlpha, .Add, .SourceAlpha, .InvertedSourceAlpha, .Add, .All); _alphaBlendState = new BlendState(_context, blendDesc); _opaqueBlendState = new BlendState(_context, .Default); + + _renderTarget2D = new RenderTarget2D(_context, 100, 100, .R8G8B8A8_UNorm); + _depthTarget = new DepthStencilTarget(_context, 100, 100, .D32_Float); + + SamplerStateDescription desc = .(); + + SamplerState sampler = new SamplerState(_context, desc); + + _renderTarget2D.SamplerState = sampler; + + sampler.ReleaseRef(); } private void InitEcs() @@ -61,30 +81,143 @@ namespace GlitchyEditor _world.Register(); } + private void InitEditor() + { + _editor = new Editor(_world); + _editor.SceneViewportWindow.ViewportSizeChangedEvent.Add(new (s, e) => ViewportSizeChanged(s, e)); + + _cameraController = new .(Application.Get().Window.Context.SwapChain.BackbufferViewport.Width / + Application.Get().Window.Context.SwapChain.BackbufferViewport.Height); + _cameraController.CameraPosition = .(0, 0, -5); + _cameraController.TranslationSpeed = 10; + + + _editor.[Friend]CreateEntityWithTransform(); + } + public override void Update(GameTime gameTime) { - RenderCommand.Clear(null, .(0.2f, 0.2f, 0.2f)); + if(_editor.SceneViewportWindow.HasFocus && Input.IsMouseButtonPressed(.RightButton)) + _cameraController.Update(gameTime); + + TransformSystem.Update(_world); + + RenderCommand.Clear(_renderTarget2D, .(0.2f, 0.2f, 0.2f)); _depthTarget.Clear(1.0f, 0, .Depth); - _context.SetRenderTarget(null); + _context.SetRenderTarget(_renderTarget2D); _depthTarget.Bind(); _context.BindRenderTargets(); + + _context.SetViewport(Viewport(0, 0, _renderTarget2D.Width, _renderTarget2D.Height)); + + _opaqueBlendState.Bind(); + + Renderer.BeginScene(_cameraController.Camera); + + DebugRenderer.Render(_world); + Renderer.EndScene(); + + RenderCommand.Clear(null, .(0.2f, 0.2f, 0.2f)); + _swapchainDepthBuffer.Clear(1.0f, 0, .Depth); + + _context.SetRenderTarget(null); + _swapchainDepthBuffer.Bind(); + _context.BindRenderTargets(); + _context.SetViewport(_context.SwapChain.BackbufferViewport); } public override void OnEvent(Event event) { + _cameraController.OnEvent(event); + EventDispatcher dispatcher = EventDispatcher(event); dispatcher.Dispatch(scope (e) => OnImGuiRender(e)); + dispatcher.Dispatch(scope (e) => OnWindowResize(e)); } + ImGui.ID _mainDockspaceId; + private bool OnImGuiRender(ImGuiRenderEvent event) { + ImGui.Viewport* viewport = ImGui.GetMainViewport(); + ImGui.DockSpaceOverViewport(viewport); + + DrawMainMenuBar(); + + _editor.SceneViewportWindow.Texture = _renderTarget2D; + _editor.Update(); return false; } + + private void DrawMainMenuBar() + { + ImGui.BeginMainMenuBar(); + + if(ImGui.BeginMenu("File", false)) + { + ImGui.EndMenu(); + } + + if(ImGui.BeginMenu("View", true)) + { + if(ImGui.MenuItem(EntityHierarchyWindow.s_WindowTitle)) + { + _editor.EntityHierarchyWindow.Open = true; + } + + if(ImGui.MenuItem(ComponentEditWindow.s_WindowTitle)) + { + _editor.ComponentEditWindow.Open = true; + } + + if(ImGui.MenuItem(SceneViewportWindow.s_WindowTitle)) + { + _editor.SceneViewportWindow.Open = true; + } + + ImGui.EndMenu(); + } + + + ImGui.EndMainMenuBar(); + } + + private bool OnWindowResize(WindowResizeEvent e) + { + _swapchainDepthBuffer.ReleaseRef(); + _swapchainDepthBuffer = new DepthStencilTarget(_context, _context.SwapChain.Width, _context.SwapChain.Height); + + return false; + } + + private void ViewportSizeChanged(Object sender, Vector2 viewportSize) + { + uint32 sizeX = (uint32)viewportSize.X; + uint32 sizeY = (uint32)viewportSize.Y; + + if(sizeX == 0 || sizeY == 0) + return; + + var sampler = _renderTarget2D.SamplerState; + + _renderTarget2D.ReleaseRef(); + _depthTarget.ReleaseRef(); + + _renderTarget2D = new RenderTarget2D(_context, sizeX, sizeY, .R8G8B8A8_UNorm); + _editor.SceneViewportWindow.Texture = _renderTarget2D; + + _depthTarget = new DepthStencilTarget(_context, sizeX, sizeY, .D32_Float); + + _cameraController.AspectRatio = (float)sizeX / (float)sizeY; + + + _renderTarget2D.SamplerState = sampler; + } } }