From ae0434f7b4ca01e35eba7be8a431981f73c50cb8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Alexis=20Laferri=C3=A8re?= Date: Fri, 11 Dec 2015 19:25:28 -0500 Subject: [PATCH] lib/gamnit: intro `UICamera` MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Alexis Laferrière --- lib/gamnit/cameras.nit | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/lib/gamnit/cameras.nit b/lib/gamnit/cameras.nit index fa23be8..43aae77 100644 --- a/lib/gamnit/cameras.nit +++ b/lib/gamnit/cameras.nit @@ -128,3 +128,75 @@ class EulerCamera return view * projection end end + +# Orthogonal camera to draw UI objects with services to work with screens of different sizes +# +# X axis: left to right of the screen, from `position.x` to `position.x + width` +# Y axis: top to bottom of the screen, from `position.y` to `position.y + height` +# Z axis: far to near the camera (usually when values are higher), from `far` to `near` +class UICamera + super Camera + + # Clipping wall near the camera, defaults to 100.0 + var near = 100.0 is writable + + # Clipping wall the farthest of the camera, defaults to -100.0 + var far: Float = -100.0 is writable + + # Width in world units, defaults to the width in pixels of the screen + var width: Float = display.width.to_f is lazy + + # Height in world units, defaults to the height in pixels of the screen + var height: Float = display.height.to_f is lazy + + # Reset the camera position so that `height` world units are visible on the Y axis + # + # By default, `height` is set to `display.height`. + # + # This can be used to set standardized UI units independently from the screen resolution. + fun reset_height(height: nullable Float) + do + if height == null then height = display.height.to_f + + self.height = height + self.width = height * display.aspect_ratio + end + + # Convert the position `x, y` on screen, to UI coordinates + fun camera_to_ui(x, y: Numeric): Point[Float] + do + # FIXME this kind of method should use something like a canvas + # instead of being hard coded on the display. + + var wx = x.to_f * width / display.width.to_f - position.x + var wy = y.to_f * height / display.height.to_f - position.y + return new Point[Float](wx, wy) + end + + # Anchor in the top left corner of the screen, at z = 0 + fun top_left: Point3d[Float] do return new Point3d[Float](position.x, position.y, 0.0) + + # Anchor in the top right corner of the screen, at z = 0 + fun top_right: Point3d[Float] do return new Point3d[Float](position.x + width, position.y, 0.0) + + # Anchor in the bottom left corner of the screen, at z = 0 + fun bottom_left: Point3d[Float] do return new Point3d[Float](position.x, position.y + height, 0.0) + + # Anchor in the bottom right corner of the screen, at z = 0 + fun bottom_right: Point3d[Float] do return new Point3d[Float](position.x + width, position.y + height, 0.0) + + # TODO cache the anchors and the matrix + + redef fun mvp_matrix + do + var view = new Matrix.identity(4) + + # Translate the world away from the camera + view.translate(-position.x/2.0, -position.y/2.0, -position.z/2.0) + + # Use a projection matrix with a depth + var projection = new Matrix.orthogonal(0.0, width, -height, 0.0, near, far) + + return view * projection + end +end -- 1.7.9.5