diff --git a/GlitchyEditor/src/EditWindows/SceneViewportWindow.bf b/GlitchyEditor/src/EditWindows/SceneViewportWindow.bf index 6e59a63..df00ad7 100644 --- a/GlitchyEditor/src/EditWindows/SceneViewportWindow.bf +++ b/GlitchyEditor/src/EditWindows/SceneViewportWindow.bf @@ -10,7 +10,7 @@ namespace GlitchyEditor.EditWindows { class SceneViewportWindow : EditorWindow { - public Camera _camera; + public OldCamera _camera; public const String s_WindowTitle = "Scene"; diff --git a/GlitchyEditor/src/EditorLayer.bf b/GlitchyEditor/src/EditorLayer.bf index cea5f5f..f3da79a 100644 --- a/GlitchyEditor/src/EditorLayer.bf +++ b/GlitchyEditor/src/EditorLayer.bf @@ -28,6 +28,9 @@ namespace GlitchyEditor RenderTarget2D _viewportTarget ~ _?.ReleaseRef(); + Entity _cameraEntity; + Entity _otherCameraEntity; + public this() : base("Example") { Application.Get().Window.IsVSync = false; @@ -35,6 +38,26 @@ namespace GlitchyEditor InitGraphics(); //InitEcs(); InitEditor(); + + { + _cameraEntity = _scene.CreateEntity("Camera Entity"); + let camera = _cameraEntity.AddComponent(); + camera.Camera.SetPerspective(0.1f, 1000f, MathHelper.ToRadians(75)); + camera.Primary = true; + camera.FixedAspectRatio = false; + let transform = _cameraEntity.GetComponent(); + transform.Transform = Matrix.Translation(0, 0, -5); + } + + { + _otherCameraEntity = _scene.CreateEntity("Other Camera Entity"); + let camera = _otherCameraEntity.AddComponent(); + camera.Camera.SetPerspective(0.1f, 1000f, MathHelper.ToRadians(45)); + camera.Primary = false; + camera.FixedAspectRatio = false; + let transform = _otherCameraEntity.GetComponent(); + transform.Transform = Matrix.Translation(0, 0, -5); + } } private void InitGraphics() @@ -56,18 +79,6 @@ namespace GlitchyEditor _viewportTarget.SamplerState = SamplerStateManager.LinearClamp; } - /*private void InitEcs() - { - _world.Register(); - _world.Register(); - _world.Register(); - _world.Register(); - _world.Register(); - _world.Register(); - _world.Register(); - _world.Register(); - }*/ - private void InitEditor() { _editor = new Editor(_scene); @@ -104,12 +115,7 @@ namespace GlitchyEditor //Renderer.EndScene(); - Renderer2D.BeginScene(_cameraController.Camera); - _scene.Update(gameTime); - - Renderer2D.EndScene(); - RenderCommand.Clear(null, .Color | .Depth, .(0.2f, 0.2f, 0.2f), 1.0f, 0); @@ -133,6 +139,18 @@ namespace GlitchyEditor private bool OnImGuiRender(ImGuiRenderEvent event) { + ImGui.Begin("Test"); + + static bool cameraA = true; + + if (ImGui.Checkbox("Camera A", &cameraA)) + { + _cameraEntity.GetComponent().Primary = cameraA; + _otherCameraEntity.GetComponent().Primary = !cameraA; + } + + ImGui.End(); + ImGui.Viewport* viewport = ImGui.GetMainViewport(); ImGui.DockSpaceOverViewport(viewport); @@ -194,6 +212,8 @@ namespace GlitchyEditor _viewportTarget.Resize(sizeX, sizeY); _cameraController.AspectRatio = (float)sizeX / (float)sizeY; + + _scene.OnViewportResize(sizeX, sizeY); } } } diff --git a/GlitchyEngine/src/Renderer/Camera.bf b/GlitchyEngine/src/Renderer/Camera.bf index e2b9006..5024db1 100644 --- a/GlitchyEngine/src/Renderer/Camera.bf +++ b/GlitchyEngine/src/Renderer/Camera.bf @@ -3,7 +3,25 @@ using GlitchyEngine.Math; namespace GlitchyEngine.Renderer { - public abstract class Camera + struct Camera + { + protected Matrix _projection; + + public Matrix Projection => _projection; + + protected this() + { + _projection = .Identity; + } + + public this(Matrix projection) + { + _projection = projection; + } + } + + + public abstract class OldCamera { protected Matrix _view; protected Matrix _transform; diff --git a/GlitchyEngine/src/Renderer/CameraComponent.bf b/GlitchyEngine/src/Renderer/CameraComponent.bf index 2a9f379..599e989 100644 --- a/GlitchyEngine/src/Renderer/CameraComponent.bf +++ b/GlitchyEngine/src/Renderer/CameraComponent.bf @@ -2,7 +2,7 @@ using GlitchyEngine.Math; namespace GlitchyEngine.Renderer { - public struct CameraComponent + public struct OldCameraComponent { public enum Projection { @@ -29,10 +29,11 @@ namespace GlitchyEngine.Renderer */ Orthographic } - + float _nearPlane; float _farPlane; Projection _projectionType; + float _fovY; float _aspect; diff --git a/GlitchyEngine/src/Renderer/OrthographicCamera.bf b/GlitchyEngine/src/Renderer/OrthographicCamera.bf index fafdf53..db141a6 100644 --- a/GlitchyEngine/src/Renderer/OrthographicCamera.bf +++ b/GlitchyEngine/src/Renderer/OrthographicCamera.bf @@ -2,7 +2,7 @@ using GlitchyEngine.Math; namespace GlitchyEngine.Renderer { - public class OrthographicCamera : Camera + public class OrthographicCamera : OldCamera { protected float _bottom, _left, _right, _top; diff --git a/GlitchyEngine/src/Renderer/PerspectiveCamera.bf b/GlitchyEngine/src/Renderer/PerspectiveCamera.bf index 323e053..f440f21 100644 --- a/GlitchyEngine/src/Renderer/PerspectiveCamera.bf +++ b/GlitchyEngine/src/Renderer/PerspectiveCamera.bf @@ -6,7 +6,7 @@ namespace GlitchyEngine.Renderer /** * If FarPlane is float.PositiveInfinity the projection matrix will be an infinite projection (that means no far plane) */ - public class PerspectiveCamera : Camera + public class PerspectiveCamera : OldCamera { public enum ProjectionType { diff --git a/GlitchyEngine/src/Renderer/Renderer.bf b/GlitchyEngine/src/Renderer/Renderer.bf index 9230616..e3f462d 100644 --- a/GlitchyEngine/src/Renderer/Renderer.bf +++ b/GlitchyEngine/src/Renderer/Renderer.bf @@ -79,7 +79,8 @@ namespace GlitchyEngine.Renderer LineGeometry.SetVertexLayout(layout..ReleaseRefNoDelete()); } - public static void BeginScene(EcsWorld world, EcsEntity cameraEntity) + // TODO + /*public static void BeginScene(EcsWorld world, EcsEntity cameraEntity) { Debug.Profiler.ProfileRendererFunction!(); @@ -91,9 +92,9 @@ namespace GlitchyEngine.Renderer var proj = camera.Projection; _sceneConstants.ViewProjection = proj * view; - } + }*/ - public static void BeginScene(Camera camera) + public static void BeginScene(OldCamera camera) { Debug.Profiler.ProfileRendererFunction!(); diff --git a/GlitchyEngine/src/Renderer/Renderer2D.bf b/GlitchyEngine/src/Renderer/Renderer2D.bf index 1f5c2d8..989611d 100644 --- a/GlitchyEngine/src/Renderer/Renderer2D.bf +++ b/GlitchyEngine/src/Renderer/Renderer2D.bf @@ -3,6 +3,7 @@ using System.Collections; using System; using System.Diagnostics; using GlitchyEngine.Renderer.Text; +using GlitchyEngine.World; namespace GlitchyEngine.Renderer { @@ -362,7 +363,8 @@ namespace GlitchyEngine.Renderer #endif } - public static void BeginScene(Camera camera, DrawOrder drawOrder = .SortByTexture, Effect effect = null, Effect circleEffect = null) + // TODO: remove? + public static void BeginScene(OldCamera camera, DrawOrder drawOrder = .SortByTexture, Effect effect = null, Effect circleEffect = null) { Debug.Profiler.ProfileRendererFunction!(); #if DEBUG @@ -397,6 +399,48 @@ namespace GlitchyEngine.Renderer s_drawOrder = drawOrder; +#if DEBUG + s_sceneRunning = true; +#endif + } + + public static void BeginScene(Camera camera, Matrix transform, DrawOrder drawOrder = .SortByTexture, Effect effect = null, Effect circleEffect = null) + { + Debug.Profiler.ProfileRendererFunction!(); +#if DEBUG + Log.EngineLogger.AssertDebug(s_initialized, "Renderer2D was not initialized."); + Log.EngineLogger.AssertDebug(!s_sceneRunning, "You have to call EndScene before you can make another call to BeginScene."); +#endif + + //s_textureColorEffect.Bind(Renderer._context); + + s_currentEffect?.ReleaseRef(); + if(effect != null) + { + s_currentEffect = effect..AddRef(); + } + else + { + s_currentEffect = s_batchEffect..AddRef(); + } + + s_currentCircleEffect?.ReleaseRef(); + if(circleEffect != null) + { + s_currentCircleEffect = effect..AddRef(); + } + else + { + s_currentCircleEffect = s_circleBatchEffect..AddRef(); + } + + Matrix viewProjection = camera.Projection * Matrix.Invert(transform); + + s_currentEffect.Variables["ViewProjection"].SetData(viewProjection); + s_currentCircleEffect.Variables["ViewProjection"].SetData(viewProjection); + + s_drawOrder = drawOrder; + #if DEBUG s_sceneRunning = true; #endif diff --git a/GlitchyEngine/src/World/Components.bf b/GlitchyEngine/src/World/Components.bf index eae02b1..9cdf424 100644 --- a/GlitchyEngine/src/World/Components.bf +++ b/GlitchyEngine/src/World/Components.bf @@ -1,4 +1,6 @@ using GlitchyEngine.Math; +using GlitchyEngine.Renderer; +using System; namespace GlitchyEngine.World { @@ -31,4 +33,94 @@ namespace GlitchyEngine.World Color = color; } } + + struct SceneCamera : Camera + { + public enum ProjectionType + { + case Perspective(float FovY, float NearPlane, float FarPlane); + case InfinitePerspective(float FovY, float NearPlane); + case Orthographic(float Height, float NearPlane, float FarPlane); + } + + private float _aspectRatio = 16.0f / 9.0f; + + private ProjectionType _projectionType = .InfinitePerspective(MathHelper.ToRadians(75f), 0.1f); + + public ProjectionType ProjectionType + { + get => _projectionType; + set mut + { + _projectionType = value; + CalculateProjection(); + } + } + + private const Matrix mat = Matrix.InfinitePerspectiveProjection(MathHelper.ToRadians(75f), 1.0f, 0.1f); + + public this() + { + CalculateProjection(); + } + + public void SetOrthographic(float height, float nearPlane, float farPlane) mut + { + _projectionType = .Orthographic(height, nearPlane, farPlane); + + CalculateProjection(); + } + + public void SetPerspective(float fovY, float nearPlane, float farPlane) mut + { + _projectionType = .Perspective(fovY, nearPlane, farPlane); + + CalculateProjection(); + } + + public void SetInfinitePerspective(float fovY, float nearPlane) mut + { + _projectionType = .InfinitePerspective(fovY, nearPlane); + + CalculateProjection(); + } + + public void SetViewportSize(uint32 width, uint32 height) mut + { + _aspectRatio = (float)width / (float)height; + + CalculateProjection(); + } + + private void CalculateProjection() mut + { + if (_projectionType case .Orthographic(let nearPlane, let farPlane, let projectionHeight)) + { + float halfHeight = projectionHeight / 2.0f; + float halfWidth = halfHeight / _aspectRatio; + + _projection = Matrix.OrthographicProjectionOffCenter(-halfWidth, halfWidth, halfHeight, -halfHeight, nearPlane, farPlane); + } + else if (_projectionType case .Perspective(let nearPlane, let farPlane, let fovY)) + { + _projection = Matrix.PerspectiveProjection(fovY, _aspectRatio, nearPlane, farPlane); + } + else if (_projectionType case .InfinitePerspective(let nearPlane, let fovY)) + { + _projection = Matrix.InfinitePerspectiveProjection(fovY, _aspectRatio, nearPlane); + } + } + } + + struct CameraComponent + { + public SceneCamera Camera; + public bool Primary = true; // Todo: probably move into scene + public bool FixedAspectRatio = false; + + public this() + { + Camera = .(); + } + } } \ No newline at end of file diff --git a/GlitchyEngine/src/World/Scene.bf b/GlitchyEngine/src/World/Scene.bf index 7a2c9e1..2a4d641 100644 --- a/GlitchyEngine/src/World/Scene.bf +++ b/GlitchyEngine/src/World/Scene.bf @@ -22,11 +22,30 @@ namespace GlitchyEngine.World { //TransformSystem.Update(_ecsWorld); - for (var (entity, transform, sprite) in _ecsWorld.Enumerate()) - { - Renderer2D.DrawQuad(transform.Transform, sprite.Color); - } + Camera* primaryCamera = null; + Matrix* primaryCameraTransform = null; + for (var (entity, transform, camera) in _ecsWorld.Enumerate()) + { + if (camera.Primary) + { + primaryCamera = &camera.Camera; + primaryCameraTransform = &transform.Transform; + } + } + + // Sprite renderer + if (primaryCamera != null) + { + Renderer2D.BeginScene(*primaryCamera, *primaryCameraTransform); + + for (var (entity, transform, sprite) in _ecsWorld.Enumerate()) + { + Renderer2D.DrawQuad(transform.Transform, sprite.Color); + } + + Renderer2D.EndScene(); + } } public Entity CreateEntity(String name = "") @@ -44,5 +63,22 @@ namespace GlitchyEngine.World { _ecsWorld.RemoveEntity(entity.Handle); } + + private uint32 ViewportWidth, ViewportHeight; + + /// Sets the size of the viewport into which the scene will be rendered. + public void OnViewportResize(uint32 width, uint32 height) + { + ViewportWidth = width; + ViewportHeight = height; + + for (var (entity, cameraComponent) in _ecsWorld.Enumerate()) + { + if (!cameraComponent.FixedAspectRatio) + { + cameraComponent.Camera.SetViewportSize(width, height); + } + } + } } } \ No newline at end of file