#region usings using System; using OpenTK; using SM.Base; using SM.Base.Scene; using SM.Base.Types; using SM.Base.Window; #endregion namespace SM2D.Scene { /// public class Camera : GenericCamera { internal static int ResizeCounter = 0; internal static float Distance = 2F; private int _resizeCounter = 0; private bool _updateWorldScale = false; private Vector2? _requestedWorldScale = null; /// /// This vector allows to request a world scale. /// Following cases are possible. ("not set" means 0) /// None is set: It takes the window size. /// X is set: Y get calculated by the aspect ratio of the window. /// Y is set: X get calculated by the aspect ratio of the window. /// Both are set: Now the system try to keep a (invisible) rectangle in view, by increasing the width or height of the view, if needed. /// public Vector2? RequestedWorldScale { get => _requestedWorldScale; set { _requestedWorldScale = value; _updateWorldScale = true; } } /// /// Will always return a updated version of the world scale. /// public Vector2 CalculatedWorldScale { get { if (ResizeCounter != _resizeCounter || _updateWorldScale) { CalculateWorldScale(SMRenderer.CurrentWindow); } return WorldScale; } } /// /// The world scale that got calculated. /// public Vector2 WorldScale { get; private set; } = Vector2.Zero; /// /// A event that gets triggered, when the world scale changed. /// Possible causes: Window resizes, changed /// public event Action WorldScaleChanged; /// /// The position of the camera. /// public CVector2 Position = new CVector2(0); /// public override bool Orthographic { get; } = true; /// protected override Matrix4 ViewCalculation(IGenericWindow window) { return Matrix4.LookAt(Position.X, Position.Y, Distance, Position.X, Position.Y, 0f, 0, 1, 0); } /// protected override bool WorldCalculation(IGenericWindow window, out Matrix4 world) { world = Matrix4.Identity; if (ResizeCounter != _resizeCounter || _updateWorldScale) { _updateWorldScale = false; _resizeCounter = ResizeCounter; CalculateWorldScale(window); world = Matrix4.CreateOrthographic(WorldScale.X, WorldScale.Y, .001f, 3.2f); return true; } return false; } /// /// This calculates the world scale. /// Usually gets called, by the camera itself, but if you need the world scale for additional calculations, you can execute it by yourself. /// /// public void CalculateWorldScale(IGenericWindow window) { if (RequestedWorldScale.HasValue) { float aspect = window.AspectRatio; Vector2 requested = RequestedWorldScale.Value; if (requested.X > 0 && requested.Y > 0) { float requestRatio = requested.X / requested.Y; if (requestRatio > aspect) WorldScale = new Vector2(requested.X, requested.X / aspect); else WorldScale = new Vector2(aspect * requested.Y, requested.Y); } else if (requested.X > 0) WorldScale = new Vector2(requested.X, requested.X / aspect); else if (requested.Y > 0) WorldScale = new Vector2(aspect * requested.Y, requested.Y); } else { WorldScale = window.WindowSize; } WorldScaleChanged?.Invoke(this); } } }