gamnit: use SDL2
authorAlexis Laferrière <alexis.laf@xymus.net>
Thu, 23 Feb 2017 22:27:11 +0000 (17:27 -0500)
committerAlexis Laferrière <alexis.laf@xymus.net>
Mon, 27 Feb 2017 19:50:11 +0000 (14:50 -0500)
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

lib/gamnit/display_linux.nit
lib/gamnit/gamnit_linux.nit

index 1dbee21..231ee17 100644 (file)
@@ -15,8 +15,7 @@
 # Gamnit display implementation for GNU/Linux using `egl`, `sdl` and `x11`
 module display_linux
 
-import sdl
-import x11
+import sdl2::image
 
 import egl # local to gamnit
 intrude import display
@@ -32,24 +31,22 @@ redef class GamnitDisplay
        fun height=(value: Int) do requested_height = value
        private var requested_height = 1080
 
-       redef fun show_cursor do return sdl_display.show_cursor
+       redef fun show_cursor do return sdl.show_cursor
 
-       redef fun show_cursor=(val) do sdl_display.show_cursor = val
+       redef fun show_cursor=(val) do sdl.show_cursor = val
 
-       # Setup SDL, X11, EGL in order
+       # Setup SDL, wm, EGL in order
        redef fun setup
        do
                if debug_gamnit then print "Setting up SDL"
-               self.sdl_display = setup_sdl(requested_width, requested_height)
+               self.sdl_window = setup_sdl(requested_width, requested_height)
 
-               if debug_gamnit then print "Setting up X11"
-               var x11_display = setup_x11
-               var window_handle = window_handle
-               setup_egl_display x11_display
+               if debug_gamnit then print "Setting up window manager"
+               setup_egl_display sdl_window.wm_info.display_handle
 
                if debug_gamnit then print "Setting up EGL context"
                select_egl_config(red_bits, green_bits, blue_bits, 8, 8, 0, 0)
-               setup_egl_context window_handle
+               setup_egl_context sdl_window.wm_info.window_handle
        end
 
        # Close EGL and SDL in reverse order of `setup` (nothing to do for X11)
@@ -63,55 +60,52 @@ redef class GamnitDisplay
        # SDL
 
        # The SDL display managing the window and events
-       var sdl_display: SDLDisplay is noautoinit
+       var sdl_window: SDLWindow is noautoinit
+
+       # Title of the window, must be set before creating the window (or redef)
+       var window_title = "gamnit game" is lazy, writable
 
        # Setup the SDL display and lib
-       fun setup_sdl(window_width, window_height: Int): SDLDisplay
+       fun setup_sdl(window_width, window_height: Int): SDLWindow
        do
-               var sdl_display = new SDLDisplay(window_width, window_height)
-               assert not sdl_display.address_is_null else print "Opening SDL display failed"
-               return sdl_display
-       end
-
-       # Close the SDL display
-       fun close_sdl do sdl_display.destroy
+               assert sdl.initialize((new SDLInitFlags).video) else
+                       print_error "Failed to initialize SDL2: {sdl.error}"
+               end
 
-       # Get a native handle to the current SDL window
-       fun window_handle: Pointer
-       do
-               var sdl_wm_info = new SDLSystemWindowManagerInfo
-               return sdl_wm_info.x11_window_handle
-       end
+               var img_flags = (new SDLImgInitFlags).png.jpg
+               assert sdl.img.initialize(img_flags) == img_flags else
+                       print_error "Failed to initialize SDL2 IMG: {sdl.error}"
+               end
 
-       # ---
-       # X11
+               var sdl_window = new SDLWindow(window_title.to_cstring, window_width, window_height, (new SDLWindowFlags).opengl)
+               assert not sdl_window.address_is_null else
+                       print_error "Failed to create SDL2 window: {sdl.error}"
+               end
 
-       # Get a native handle to the current X11 display
-       fun setup_x11: Pointer
-       do
-               var x11_display = x_open_default_display
-               assert not x11_display.address_is_null else print "Opening X11 display failed"
-               return x11_display
+               return sdl_window
        end
+
+       # Close the SDL display
+       fun close_sdl do sdl_window.destroy
 end
 
 redef class TextureAsset
 
        redef fun load_from_platform
        do
-               var path = "assets" / path # TODO use app.assets_dir
-               var sdl_tex = new SDLImage.from_file(path)
+               var path = "assets" / path
 
-               if sdl_tex.address_is_null then
+               var surface = new SDLSurface.load(path.to_cstring)
+               if surface.address_is_null then
                        error = new Error("Failed to load texture at '{path}'")
                        return
                end
 
-               self.width = sdl_tex.width.to_f
-               self.height = sdl_tex.height.to_f
-               var format = if sdl_tex.amask > 0 then gl_RGBA else gl_RGB
-               var pixels = sdl_tex.pixels
+               self.width = surface.w.to_f
+               self.height = surface.h.to_f
+               var format = if surface.format.amask > 0u32 then gl_RGBA else gl_RGB
+               var pixels = surface.pixels
 
-               load_from_pixels(pixels, sdl_tex.width, sdl_tex.height, format)
+               load_from_pixels(pixels, surface.w, surface.h, format)
        end
 end
index 2aa1cae..fe6cdac 100644 (file)
 # Support services for Gamnit on GNU/Linux
 module gamnit_linux
 
+import sdl2::events
+
 intrude import gamnit
-import display_linux
 
 redef class App
+       private var sdl_event_buffer = new SDLEventBuffer.malloc
+
        redef fun feed_events
        do
                var display = display
                if display == null then return
 
-               var events = display.sdl_display.events
-               display.check_lock_cursor
-               for event in events do accept_event(event)
+               loop
+                       var avail = sdl_event_buffer.poll_event
+                       if not avail then break
+
+                       # Convert to an SDL event with data
+                       var sdl_event = sdl_event_buffer.to_event
+                       # Convert to `mnit::inputs` conforming objects
+                       var gamnit_event = sdl_event.to_gamnit_event(sdl_event_buffer)
+                       accept_event gamnit_event
+               end
        end
 end
 
-redef class GamnitDisplay
+# ---
+# Redef services from `sdl2::events`
+
+redef class SDLEvent
+       private fun to_gamnit_event(buffer: SDLEventBuffer): GamnitInputEvent
+       do return new GamnitOtherEvent(buffer, self)
+end
+
+redef class SDLQuitEvent
+       redef fun to_gamnit_event(buffer) do return new GamnitQuitEvent(buffer, self)
+end
+
+redef class SDLMouseEvent
+       redef fun to_gamnit_event(buffer) do return new GamnitPointerEvent(buffer, self)
+end
+
+redef class SDLKeyboardEvent
+       redef fun to_gamnit_event(buffer) do return new GamnitKeyEvent(buffer, self)
+end
+
+# ---
+# Implement `mnit::inputs` interfaces
+
+# SDL2 event wrapper implementing the `mnit::input` API
+#
+# There is two views to the underlying native object: `buffer` and `native`.
+class GamnitInputEvent
+       super InputEvent
+
+       # Native SDL 2 event buffer with the pseudo class hierarchy metadata
+       var buffer: SDLEventBuffer
+
+       # Native SDL 2 event
+       var native: NATIVE
+
+       # Type of the `native` underlying SDL 2 event
+       type NATIVE: SDLEvent
+end
+
+# Event on user requested quit
+class GamnitQuitEvent
+       super GamnitInputEvent
+       super QuitEvent
+
+       redef type NATIVE: SDLQuitEvent
+end
+
+# Event on keyboard input
+class GamnitKeyEvent
+       super GamnitInputEvent
+       super KeyEvent
+
+       redef type NATIVE: SDLKeyboardEvent
+
+       redef fun is_down do return buffer.is_keydown
+       redef fun is_up do return buffer.is_keyup
+       redef fun is_arrow_up do return native.keysym.is_up
+       redef fun is_arrow_left do return native.keysym.is_left
+       redef fun is_arrow_down do return native.keysym.is_down
+       redef fun is_arrow_right do return native.keysym.is_right
+       redef fun to_c do return native.to_s.chars.first
+       redef fun name do return native.to_s.to_lower
+end
+
+# Event on pointer, mouse and finger input
+class GamnitPointerEvent
+       super GamnitInputEvent
+       super PointerEvent
+
+       redef type NATIVE: SDLMouseEvent
 
-       # HACK to keep the cursor in the center of the screen without producing move events
-       private fun check_lock_cursor
+       redef fun x do return native.x.to_f
+       redef fun y do return native.y.to_f
+       redef fun is_move do return buffer.is_mouse_motion
+
+       redef fun pressed
        do
-               var sdl_display = sdl_display
-               if lock_cursor and sdl_display.input_focus then
-                       sdl_display.ignore_mouse_motion_events = true
-                       sdl_display.warp_mouse(width/2, height/2)
-                       sdl_display.ignore_mouse_motion_events = false
-               end
+               var native = native
+               if native isa SDLMouseButtonEvent then
+                       return native.pressed and native.button == 1
+               else if native isa SDLMouseMotionEvent then
+                       return native.state & 1 == 1
+               else abort
        end
 end
+
+# SDL2 event not handled by gamnit
+class GamnitOtherEvent
+       super GamnitInputEvent
+end