summaryrefslogtreecommitdiff
path: root/source/graphics/Camera2D.cs
blob: 1bae764d58a914ef2b2c4b12ff77e811add4e5d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
using System;
using Celesteia.Resources;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Celesteia.Graphics {
    public class Camera2D {
        private GraphicsDevice _graphicsDevice;
        
        // Viewport macros.
        private int ViewportX => _graphicsDevice.Viewport.X;
        private int ViewportY => _graphicsDevice.Viewport.Y;
        private int ViewportWidth => _graphicsDevice.Viewport.Width;
        private int ViewportHeight => _graphicsDevice.Viewport.Height;

        private int _zoom = 0;
        public int ScaledZoom { get; private set; } = 0;
        // The zoom value of the camera.
        public int Zoom {
            get { return _zoom; }
            set {
                _zoom = MathHelper.Clamp(value, 1, 8);
                ScaledZoom = _zoom * ResourceManager.INVERSE_SPRITE_SCALING;
            }
        }

        public Camera2D(GraphicsDevice graphicsDevice) {
            _graphicsDevice = graphicsDevice;
            Zoom = 2;
        }

        // The camera's center.
        public Vector2 Center = Vector2.Zero;

        private float _rotation;
        // The rotation applied to the camera.
        public float Rotation {
            get { return _rotation; }
            set { _rotation = value % 360f; }
        }

        /*
            Creates a matrix with the following steps:
                - Create a translation to match (0, 0) to the center point of the camera.
                - Apply Z rotation.
                - Scale according to zoom value and inverse sprite scaling.
                - Always round the viewport width and height to prevent half-pixel rounding issues.
        */
        private float maxScale = 0f;
        public Matrix GetViewMatrix() {
            maxScale = MathF.Max(MathF.Ceiling(ViewportWidth / 1920f), MathF.Ceiling(ViewportHeight / 1080f));
            return Matrix.CreateTranslation(-Center.X, -Center.Y, 0f) * 
                Matrix.CreateRotationZ(Rotation) *
                Matrix.CreateScale(ScaledZoom, ScaledZoom, 1f) * 
                Matrix.CreateScale(maxScale, maxScale, 1f) *
                Matrix.CreateTranslation(ViewportWidth / 2f, ViewportHeight / 2f, 0f);
        }

        // Transform the viewport relative mouse position to the inverse view matrix to get the pointer's position in the world.
        public Vector2 ScreenToWorld(Point point)
        => Vector2.Transform(new Vector2(point.X - ViewportX, point.Y - ViewportY), Matrix.Invert(GetViewMatrix()));
    }
}