Files
Syntriax.Engine/Engine.Integration/Engine.Integration.MonoGame/Behaviours/MonoGameCamera2D.cs

103 lines
3.2 KiB
C#

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<MonoGameCamera2D> OnViewMatrixChanged { get; } = new();
public Event<MonoGameCamera2D> OnProjectionMatrixChanged { get; } = new();
public Event<MonoGameCamera2D> OnViewportChanged { get; } = new();
public Event<MonoGameCamera2D> 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<MonoGameWindowContainer>().Window.Graphics;
Viewport = Graphics.GraphicsDevice.Viewport;
Transform = BehaviourController.GetRequiredBehaviour<ITransform2D>();
}
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));
}
}