From: Alexis Laferrière Date: Sun, 19 Apr 2015 14:03:25 +0000 (-0400) Subject: lib/gamnit: intro GNU/Linux support X-Git-Tag: v0.7.8~26^2~4 X-Git-Url: http://nitlanguage.org lib/gamnit: intro GNU/Linux support Signed-off-by: Alexis Laferrière --- diff --git a/lib/gamnit/display.nit b/lib/gamnit/display.nit index defd809..6f1fd53 100644 --- a/lib/gamnit/display.nit +++ b/lib/gamnit/display.nit @@ -17,6 +17,8 @@ module display import ::glesv2 +import display_linux is conditional(linux) + # Should Gamnit be more verbose? fun debug_gamnit: Bool do return false diff --git a/lib/gamnit/display_linux.nit b/lib/gamnit/display_linux.nit new file mode 100644 index 0000000..109ff51 --- /dev/null +++ b/lib/gamnit/display_linux.nit @@ -0,0 +1,91 @@ +# This file is part of NIT (http://www.nitlanguage.org). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Gamnit display implementation for GNU/Linux using `egl`, `sdl` and `x11` +module display_linux + +import sdl +import x11 + +import egl # local to gamnit +import display + +redef class GamnitDisplay + + # Actual width or desired width of the window, can be set before calling `setup` + fun width=(value: Int) do requested_width = value + private var requested_width = 1920 + + # Actual height or desired height of the window, can be set before calling `setup` + fun height=(value: Int) do requested_height = value + private var requested_height = 1080 + + # Setup SDL, X11, EGL in order + redef fun setup + do + if debug_gamnit then print "Setting up SDL" + self.sdl_display = 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 EGL context" + select_egl_config(8, 8, 8, 8, 8, 0, 0) + setup_egl_context window_handle + end + + # Close EGL and SDL in reverse order of `setup` (nothing to do for X11) + redef fun close + do + close_egl + close_sdl + end + + # --- + # SDL + + # The SDL display managing the window and events + var sdl_display: SDLDisplay is noautoinit + + # Setup the SDL display and lib + fun setup_sdl(window_width, window_height: Int): SDLDisplay + 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 + + # 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 + + # --- + # X11 + + # 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 + end +end diff --git a/lib/gamnit/egl.nit b/lib/gamnit/egl.nit new file mode 100644 index 0000000..3fcb8c8 --- /dev/null +++ b/lib/gamnit/egl.nit @@ -0,0 +1,115 @@ +# This file is part of NIT (http://www.nitlanguage.org). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Use of EGL to implement Gamnit on GNU/Linux and Android +module egl + +import ::egl + +import gamnit::display + +redef class GamnitDisplay + + # The EGL display + var egl_display: EGLDisplay is noautoinit + + # The EGL context + var egl_context: EGLContext is noautoinit + + # The EGL surface for the window + var window_surface: EGLSurface is noautoinit + + # The selected EGL configuration + var egl_config: EGLConfig is noautoinit + + # Setup the EGL display for the given `x11_display` + protected fun setup_egl_display(x11_display: Pointer) + do + var egl_display = new EGLDisplay(x11_display) + assert egl_display.is_valid else print "new EGL display is not valid" + + egl_display.initialize + assert egl_display.is_valid else print "EGL initialize error: {egl_display.error}" + + self.egl_display = egl_display + end + + # Select an EGL config + protected fun select_egl_config(blue, green, red, alpha, depth, stencil, sample: Int) + do + var config_chooser = new EGLConfigChooser + config_chooser.renderable_type_egl + config_chooser.surface_type_egl + config_chooser.blue_size = blue + config_chooser.green_size = green + config_chooser.red_size = red + if alpha > 0 then config_chooser.alpha_size = alpha + if depth > 0 then config_chooser.depth_size = depth + if stencil > 0 then config_chooser.stencil_size = stencil + if sample > 0 then config_chooser.sample_buffers = sample + config_chooser.close + + var configs = config_chooser.choose(egl_display) + assert configs != null else print "Choosing EGL config failed: {egl_display.error}" + assert not configs.is_empty else print "Found no EGL config" + + if debug_gamnit then + print "EGL available configurations:" + for config in configs do + var attribs = config.attribs(egl_display) + print "* Conformant to: {attribs.conformant}" + print " Caveats: {attribs.caveat}" + print " Size of RGBA: {attribs.red_size} {attribs.green_size} {attribs.blue_size} {attribs.alpha_size}" + print " Buffer, depth, stencil: {attribs.buffer_size} {attribs.depth_size} {attribs.stencil_size}" + end + end + + # We use the first one, it is recommended + self.egl_config = configs.first + end + + # Setup the EGL context for the given `window_handle` + protected fun setup_egl_context(window_handle: Pointer) + do + var window_surface = egl_display.create_window_surface(egl_config, window_handle, [0]) + assert window_surface.is_ok else print "Creating EGL window surface failed: {egl_display.error}" + self.window_surface = window_surface + + egl_context = egl_display.create_context(egl_config) + assert egl_context.is_ok else print "Creating EGL context failed: {egl_display.error}" + + var make_current_res = egl_display.make_current(window_surface, window_surface, egl_context) + assert make_current_res else print "Creating EGL make current failed: {egl_display.error}" + + # TODO make the API selection configurable per platform + assert egl_bind_opengl_es_api else print "EGL bind API failed: {egl_display.error}" + end + + redef fun width do return window_surface.attribs(egl_display).width + + redef fun height do return window_surface.attribs(egl_display).height + + # Close the EGL context + fun close_egl + do + egl_display.make_current(new EGLSurface.none, new EGLSurface.none, new EGLContext.none) + egl_display.destroy_context(egl_context) + egl_display.destroy_surface(window_surface) + end + + redef fun flip + do + egl_display.swap_buffers(window_surface) + end +end