Merge: gamnit: misc fixes
authorJean Privat <jean@pryen.org>
Wed, 2 Aug 2017 13:30:28 +0000 (09:30 -0400)
committerJean Privat <jean@pryen.org>
Wed, 2 Aug 2017 13:30:28 +0000 (09:30 -0400)
Fix various bugs and issues related to gamnit :

* Expose the previously private class `SpriteSet` for clients to access `time` and set `time_mod` (as intended).
* Fix two bugs with animations: a div by zero in the shader that hid non-animated sprites on Android (a div by zero never crashes, but the return value is unspecified in OpenGL ES 2.0), and an array out of bounds error when an animation has a single frame.
* Cache `GamnitDisplay::aspect_ratio` as it appears to be a performance bottleneck.
* Fix the virtual gamepad not being interactive in Asteronits.
* `UICamera::camera_to_ui` returns a `Point3d` that can be used directly as a `Sprite::center`.

Pull-Request: #2532
Reviewed-by: Jean Privat <jean@pryen.org>

contrib/asteronits/src/asteronits.nit
lib/a_star.nit
lib/gamnit/camera_control_linux.nit
lib/gamnit/cameras.nit
lib/gamnit/flat/flat_core.nit
lib/gamnit/gamnit_linux.nit

index 1c148db..d7621de 100644 (file)
@@ -89,6 +89,8 @@ redef class App
 
        redef fun accept_event(event)
        do
+               if super then return true
+
                if event isa QuitEvent then
                        exit 0
                else if event isa KeyEvent then
index cc0cba3..db80519 100644 (file)
@@ -90,7 +90,7 @@ class Node
        # lifetime limited to evocation of `path_to`
        private var open: Bool = false
 
-       # Main functionnality, returns path from `self` to `dest`
+       # Main functionality, returns path from `self` to `dest`
        fun path_to(dest: N, max_cost: Int, context: PathContext): nullable AStarPath[N]
        do
                return path_to_alts(dest, max_cost, context, null)
index 8c92e91..2aa5d48 100644 (file)
@@ -23,7 +23,7 @@ redef class EulerCamera
        # Zoom factor, default at 1.2, higher means more reactive zoom effect
        var camera_zoom_mod = 1.2 is writable
 
-       # Scoll trigger button mask from SDL2 (1: left, 2: middle, 4: right)
+       # Scroll trigger button mask from SDL2 (1: left, 2: middle, 4: right)
        #
        # Set to 0 to deactivate the scrolling feature.
        var camera_pan_mask = 2 is writable
index 688082b..c83ace3 100644 (file)
@@ -225,14 +225,14 @@ class UICamera
        end
 
        # Convert the position `x, y` on screen, to UI coordinates
-       fun camera_to_ui(x, y: Numeric): Point[Float]
+       fun camera_to_ui(x, y: Numeric): Point3d[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)
+               return new Point3d[Float](wx, -wy, 0.0)
        end
 
        # Center of the screen, from the point of view of the camera, at z = 0
index c8ffed4..dcb11f6 100644 (file)
@@ -378,10 +378,10 @@ redef class App
        var ui_camera = new UICamera(app.display.as(not null)) is lazy
 
        # World sprites drawn as seen by `world_camera`
-       var sprites: Set[Sprite] = new SpriteSet
+       var sprites = new SpriteSet
 
        # UI sprites drawn as seen by `ui_camera`, over world `sprites`
-       var ui_sprites: Set[Sprite] = new SpriteSet
+       var ui_sprites = new SpriteSet
 
        # Main method to refine in clients to update game logic and `sprites`
        fun update(dt: Float) do end
@@ -537,7 +537,7 @@ redef class App
        # Draw world sprites from `sprites`
        protected fun frame_core_world_sprites(display: GamnitDisplay)
        do
-               frame_core_sprites(display, sprites.as(SpriteSet), world_camera)
+               frame_core_sprites(display, sprites, world_camera)
        end
 
        # Draw UI sprites from `ui_sprites`
@@ -546,7 +546,7 @@ redef class App
                # Reset only the depth buffer
                glClear gl_DEPTH_BUFFER_BIT
 
-               frame_core_sprites(display, ui_sprites.as(SpriteSet), ui_camera)
+               frame_core_sprites(display, ui_sprites, ui_camera)
        end
 end
 
@@ -687,7 +687,7 @@ private class Simple2dProgram
                        vec3 c; // coords
 
                        float end = a_start + a_loops/a_fps*a_n_frames;
-                       if (a_loops == -1.0 || time < end) {
+                       if (a_fps != 0.0 && (a_loops == -1.0 || time < end)) {
                                // in animation
                                float frame = mod(floor((time-a_start)*a_fps), a_n_frames);
                                v_coord = a_tex_coord + a_tex_diff*frame;
@@ -875,26 +875,26 @@ redef class OffsetPoint3d
 end
 
 # Set of sprites sorting them into different `SpriteContext`
-private class SpriteSet
+class SpriteSet
        super HashSet[Sprite]
 
-       # Map texture then static vs dynamic to a `SpriteContext`
-       var contexts_map = new HashMap4[RootTexture, nullable RootTexture, Bool, Int, Array[SpriteContext]]
-
-       # Contexts in `contexts_map`, sorted by draw order
-       var contexts_items = new Array[SpriteContext]
-
-       # Sprites needing resorting in `contexts_map`
-       var sprites_to_remap = new Array[Sprite]
-
        # Animation speed multiplier (0.0 to pause, 1.0 for normal speed, etc.)
        var time_mod = 1.0 is writable
 
        # Seconds elapsed since the launch of the program, in world time responding to `time_mod`
        var time = 0.0
 
+       # Map texture then static vs dynamic to a `SpriteContext`
+       private var contexts_map = new HashMap4[RootTexture, nullable RootTexture, Bool, Int, Array[SpriteContext]]
+
+       # Contexts in `contexts_map`, sorted by draw order
+       private var contexts_items = new Array[SpriteContext]
+
+       # Sprites needing resorting in `contexts_map`
+       private var sprites_to_remap = new Array[Sprite]
+
        # Add a sprite to the appropriate context
-       fun map_sprite(sprite: Sprite)
+       private fun map_sprite(sprite: Sprite)
        do
                assert sprite.context == null else print_error "Sprite {sprite} belongs to another SpriteSet"
 
@@ -946,7 +946,7 @@ private class SpriteSet
        end
 
        # Remove a sprite from its context
-       fun unmap_sprite(sprite: Sprite)
+       private fun unmap_sprite(sprite: Sprite)
        do
                var context = sprite.context
                assert context != null
@@ -957,10 +957,14 @@ private class SpriteSet
        end
 
        # Draw all sprites by all contexts
-       fun draw
+       private fun draw
        do
                # Remap sprites that may need to change context
                for sprite in sprites_to_remap do
+
+                       # Skip if it was removed from this set after being modified
+                       if sprite.context != self then continue
+
                        unmap_sprite sprite
                        map_sprite sprite
                end
@@ -1211,8 +1215,12 @@ private class SpriteContext
                                data[o+36] = tc[v*2+1]
 
                                # a_tex_diff
-                               var dx = animation.frames[1].texture_coords[0] - animation.frames[0].texture_coords[0]
-                               var dy = animation.frames[1].texture_coords[1] - animation.frames[0].texture_coords[1]
+                               var dx = 0.0
+                               var dy = 0.0
+                               if animation.frames.length > 1 then
+                                       dx = animation.frames[1].texture_coords[0] - animation.frames[0].texture_coords[0]
+                                       dy = animation.frames[1].texture_coords[1] - animation.frames[0].texture_coords[1]
+                               end
                                data[o+37] = dx
                                data[o+38] = dy
 
index b0c4241..b86f8e5 100644 (file)
@@ -37,6 +37,7 @@ redef class App
                        if sdl_event isa SDLWindowEvent and sdl_event.is_resized then
                                display.width = sdl_event.data1
                                display.height = sdl_event.data2
+                               display.aspect_ratio = sdl_event.data1.to_f / sdl_event.data2.to_f
                                on_resize display
                        end
 
@@ -47,6 +48,10 @@ redef class App
        end
 end
 
+redef class GamnitDisplay
+       redef var aspect_ratio = super is lazy
+end
+
 # ---
 # Redef services from `sdl2::events`