using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Engine.Core; namespace Engine.Integration.MonoGame; public class MonoGameCamera2D : Behaviour, ICamera2D, IFirstFrameUpdate, ILastFrameUpdate, IPreDraw { public Event OnViewMatrixChanged { get; } = new(); public Event OnProjectionMatrixChanged { get; } = new(); public Event OnViewportChanged { get; } = new(); public Event OnZoomChanged { get; } = new(); public GraphicsDeviceManager Graphics { get; private set; } = null!; public ITransform2D Transform { get; private set; } = null!; public Matrix4x4 ProjectionMatrix { get; private set { if (field == value) return; field = value; OnProjectionMatrixChanged.Invoke(this); } } = Matrix4x4.Identity; public Matrix4x4 ViewMatrix { get; private set { if (field == value) return; field = value; OnViewMatrixChanged.Invoke(this); } } = Matrix4x4.Identity; public Viewport Viewport { get; set { if (field.Equals(value)) return; field = value; OnViewportChanged.Invoke(this); } } = default; public float Zoom { get; set { float newValue = Math.Max(0.1f, value); if (field == newValue) return; field = newValue; OnZoomChanged.Invoke(this); } } = 1f; // TODO This causes delay since OnPreDraw calls assuming this is called in in Update public Vector2D ScreenToWorldPosition(Vector2D screenPosition) { Vector2D worldPosition = Vector2.Transform(screenPosition.ToVector2(), ViewMatrix.Inverse.ToXnaMatrix()).ToVector2D(); return worldPosition.Scale(EngineConverterExtensions.screenScale); } public Vector2D WorldToScreenPosition(Vector2D worldPosition) { Vector2D screenPosition = Vector2.Transform(worldPosition.ToVector2(), ViewMatrix.ToXnaMatrix()).ToVector2D(); return screenPosition.Scale(EngineConverterExtensions.screenScale); } public void LastActiveFrame() => Transform = null!; public void FirstActiveFrame() { Graphics = BehaviourController.UniverseObject.Universe.FindRequiredBehaviour().Window.Graphics; Viewport = Graphics.GraphicsDevice.Viewport; Transform = BehaviourController.GetRequiredBehaviour(); } public void PreDraw() { ProjectionMatrix = Matrix.CreateOrthographicOffCenter(Viewport.X, Viewport.Width, Viewport.Height, Viewport.Y, 0, 1).FromXnaMatrix(); ViewMatrix = Matrix4x4.CreateTranslation(new Vector3D(-Transform.Position.X, Transform.Position.Y, 0f)) * Matrix4x4.CreateRotationZ(Transform.Rotation * Math.DegreeToRadian) * Matrix4x4.CreateScale(Transform.Scale.X.Max(Transform.Scale.Y)) * Matrix4x4.CreateScale(Zoom) * Matrix4x4.CreateTranslation(new Vector3D(Viewport.Width * .5f, Viewport.Height * .5f, 0f)); } }