+# 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