lib/gamnit: intro `UICamera`
authorAlexis Laferrière <alexis.laf@xymus.net>
Sat, 12 Dec 2015 00:25:28 +0000 (19:25 -0500)
committerAlexis Laferrière <alexis.laf@xymus.net>
Mon, 14 Dec 2015 16:00:01 +0000 (11:00 -0500)
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

lib/gamnit/cameras.nit

index fa23be8..43aae77 100644 (file)
@@ -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