# devices. It is used to position the sprites in `App::ui_sprites`.
#
# See the sample game at `contrib/asteronits/` and the basic project template
-# at `lib/gamnit/examples/template_flat/`.
+# at `lib/gamnit/examples/template/`.
module flat
import glesv2
intrude import geometry::points_and_lines # For _x, _y and _z
+intrude import matrix
import matrix::projection
import more_collections
import performance_analysis
import gamnit
-import gamnit::cameras
+import gamnit::cameras_cache
+import gamnit::dynamic_resolution
import gamnit::limit_fps
import gamnit::camera_control
-# Draw a `texture` at `center`
+# Visible 2D entity in the game world or UI
#
-# An instance of `Sprite` can only belong to a single `SpriteSet` at
-# a time. The on screen position depends on the camera associated
+# Similar to `gamnit::Actor` which is in 3D.
+#
+# Each sprite associates a `texture` to the position `center`.
+# The appearance is modified by `rotation`, `invert_x`,
+# `scale`, `red`, `green`, `blue` and `alpha`.
+# These values can be changed at any time and will trigger an update
+# of the data on the GPU side, having a small performance cost.
+#
+# For a sprite to be visible, it must be added to either the world `sprites`
+# or the `ui_sprites`.
+# However, an instance of `Sprite` can only belong to a single `SpriteSet`
+# at a time. The final on-screen position depends on the camera associated
# to the `SpriteSet`.
+#
+# ~~~
+# # Load texture and create sprite
+# var texture = new Texture("path/in/assets.png")
+# var sprite = new Sprite(texture, new Point3d[Float](0.0, 0.0, 0.0))
+#
+# # Add sprite to the visible game world
+# app.sprites.add sprite
+#
+# # Extra configuration of the sprite
+# sprite.rotation = pi/2.0
+# sprite.scale = 2.0
+#
+# # Show only the blue colors
+# sprite.red = 0.0
+# sprite.green = 0.0
+# ~~~
+#
+# To add a sprite to the UI it can be anchored to screen borders
+# with `ui_camera.top_left` and the likes.
+#
+# ~~~nitish
+# # Place it a bit off the top left of the screen
+# var pos = app.ui_camera.top_left.offset(128.0, -128.0, 0)
+#
+# # Load texture and create sprite
+# var texture = new Texture("path/in/assets.png")
+# var sprite = new Sprite(texture, pos)
+#
+# # Add it to the UI (above world sprites)
+# app.ui_sprites.add sprite
+# ~~~
class Sprite
# Texture drawn to screen
center_direct = value
end
- # Rotation on the Z axis, positive values go counterclockwise
+ # Rotation on the Z axis, positive values turn counterclockwise
var rotation = 0.0 is writable(rotation_direct=)
- # Rotation on the Z axis, positive values go counterclockwise
+ # Rotation on the Z axis, positive values turn counterclockwise
fun rotation=(value: Float)
do
if isset _rotation and value != rotation then needs_update
# Scale applied to this sprite
#
- # The default size of `self` depends on the size in pixels of `texture`.
+ # The basic size of `self` depends on the size in pixels of `texture`.
var scale = 1.0 is writable(scale_direct=)
- # Scale applied to this sprite, see `scale`
+ # Scale applied to this sprite
+ #
+ # The basic size of `self` depends on the size in pixels of `texture`.
fun scale=(value: Float)
do
if isset _scale and value != scale then needs_update
# Camera for world `sprites` and `depth::actors` with perspective
#
- # By default, the camera is configured to respect the resolution
- # of the screen in world coordinates at `z == 0.0`.
+ # By default, the camera is configured to a height of 1080 units
+ # of world coordinates at `z == 0.0`.
var world_camera: EulerCamera is lazy do
var camera = new EulerCamera(app.display.as(not null))
- # Aim for pixel resolution at level 0
- camera.reset_height
- camera.near = 100.0
+ # Aim for full HD pixel resolution at level 0
+ camera.reset_height 1080.0
+ camera.near = 10.0
return camera
end
# Camera for `ui_sprites` using an orthogonal view
- var ui_camera: UICamera = new UICamera(app.display.as(not null)) is lazy
+ var ui_camera = new UICamera(app.display.as(not null)) is lazy
- # World sprites to draw as seen by `world_camera`
+ # World sprites drawn as seen by `world_camera`
var sprites: Set[Sprite] = new SpriteSet
- # UI sprites to draw as seen by `ui_camera`, drawn over world `sprites`
+ # UI sprites drawn as seen by `ui_camera`, over world `sprites`
var ui_sprites: Set[Sprite] = new SpriteSet
# Main method to refine in clients to update game logic and `sprites`
# Draw the whole screen, all `glDraw...` calls should be executed here
protected fun frame_core_draw(display: GamnitDisplay)
do
- perf_clock_main.lapse
+ frame_core_dynamic_resolution_before display
+ perf_clock_main.lapse
frame_core_world_sprites display
perfs["gamnit flat world_sprites"].add perf_clock_main.lapse
frame_core_ui_sprites display
perfs["gamnit flat ui_sprites"].add perf_clock_main.lapse
+
+ frame_core_dynamic_resolution_after display
end
private fun frame_core_sprites(display: GamnitDisplay, sprite_set: SpriteSet, camera: Camera)
{
if(use_texture) {
gl_FragColor = v_color * texture2D(texture0, v_coord);
- if (gl_FragColor.a <= 0.1) discard;
+ if (gl_FragColor.a <= 0.01) discard;
} else {
gl_FragColor = v_color;
}
super HashSet[Sprite]
# Map texture then static vs dynamic to a `SpriteContext`
- var contexts_map = new HashMap2[GamnitRootTexture, Bool, SpriteContext]
+ var contexts_map = new HashMap2[RootTexture, Bool, SpriteContext]
# Contexts in `contexts_map`
var contexts_items = new Array[SpriteContext]
redef fun clear
do
+ for sprite in self do
+ sprite.context = null
+ sprite.sprite_set = null
+ end
super
for c in contexts_items do c.destroy
contexts_map.clear
# Context config and state
# Only root texture drawn by this context
- var texture: nullable GamnitRootTexture
+ var texture: nullable RootTexture
# OpenGL ES usage of `buffer_array` and `buffer_element`
var usage: GLBufferUsage
else
rot = new Matrix.rotation(sprite.rotation, 0.0, 0.0, 1.0)
end
- data.fill_from(rot.items, o+15)
+ data.fill_from_matrix(rot, o+15)
o += float_per_vertex
end
# The data can be compressed by a call to `defragment`.
#
# ~~~
+# intrude import gamnit::flat
+#
# var array = new GroupedArray[String]
# assert array.to_s == ""
#
#
# array.add "E"
# assert array.to_s == "[A,B,c,D,E]"
-# assert array.capacity == 5
+# assert array.capacity == 6
# assert array.length == 5
#
# array.remove "A"
# Returns the elements that moved as a list.
#
# ~~~
+ # intrude import gamnit::flat
+ #
# var array = new GroupedArray[String]
# array.add "a"
# array.add "b"
return ss.join
end
end
+
+redef class GLfloatArray
+ private fun fill_from_matrix(matrix: Matrix, dst_offset: nullable Int)
+ do
+ dst_offset = dst_offset or else 0
+ var mat_len = matrix.width*matrix.height
+ assert length >= mat_len + dst_offset
+ native_array.fill_from_matrix_native(matrix.items, dst_offset, mat_len)
+ end
+end
+
+redef class NativeGLfloatArray
+ private fun fill_from_matrix_native(matrix: matrix::NativeDoubleArray, dst_offset, len: Int) `{
+ int i;
+ for (i = 0; i < len; i ++)
+ self[i+dst_offset] = (GLfloat)matrix[i];
+ `}
+end