From: Jean Privat Date: Tue, 15 Sep 2015 07:37:01 +0000 (-0400) Subject: Merge: nitc: fix --typing-test-metrics by using correct tags in FFI X-Git-Tag: v0.7.8~25 X-Git-Url: http://nitlanguage.org?hp=6ee8d66422b1d25e6a05339541fbad77611ad1fd Merge: nitc: fix --typing-test-metrics by using correct tags in FFI Just fix `--typing-test-metrics` that was broken. A future PR (still wip) will ensure that the option will be no more broken Pull-Request: #1713 Reviewed-by: Lucas Bajolet Reviewed-by: Alexis Laferrière --- diff --git a/lib/gamnit/display.nit b/lib/gamnit/display.nit new file mode 100644 index 0000000..94ece8a --- /dev/null +++ b/lib/gamnit/display.nit @@ -0,0 +1,49 @@ +# 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. + +# Abstract display services +module display + +import ::glesv2 + +import display_linux is conditional(linux) +import display_android is conditional(android) + +# Should Gamnit be more verbose? +fun debug_gamnit: Bool do return false + +# General display class, is sized and drawable +class GamnitDisplay + + # Width of the display, in pixels + fun width: Int is abstract + + # Height of the display, in pixels + fun height: Int is abstract + + # Prepare this display + # + # The implementation varies per platform. + fun setup is abstract + + # Close this display and free underlying resources + # + # The implementation varies per platform. + fun close do end + + # Flip the display buffers + # + # The implementation varies per platform. + fun flip do end +end diff --git a/lib/gamnit/display_android.nit b/lib/gamnit/display_android.nit new file mode 100644 index 0000000..d0e5235 --- /dev/null +++ b/lib/gamnit/display_android.nit @@ -0,0 +1,47 @@ +# 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 Android +# +# Generated APK files require OpenGL ES 2.0. +# +# This modules uses `android::native_app_glue` and the Android NDK. +module display_android is + android_manifest """""" +end + +import ::android + +private import gamnit::egl + +redef class GamnitDisplay + + redef fun setup + do + var native_display = egl_default_display + var native_window = app.native_app_glue.window + + setup_egl_display native_display + + # We need 8 bits per color for selection by color + select_egl_config(8, 8, 8, 0, 8, 0, 0) + + var format = egl_config.attribs(egl_display).native_visual_id + native_window.set_buffers_geometry(0, 0, format) + + setup_egl_context native_window + end + + redef fun close do close_egl +end 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 diff --git a/lib/gamnit/examples/triangle/Makefile b/lib/gamnit/examples/triangle/Makefile new file mode 100644 index 0000000..22172de --- /dev/null +++ b/lib/gamnit/examples/triangle/Makefile @@ -0,0 +1,21 @@ +NITC=../../../../bin/nitc +NITLS=../../../../bin/nitls + +all: bin/standalone_triangle bin/triangle bin/triangle.apk + +bin/standalone_triangle: $(shell ${NITLS} -M src/standalone_triangle.nit linux) ${NITC} + ${NITC} src/standalone_triangle.nit -m linux -o $@ + +bin/triangle: $(shell ${NITLS} -M src/portable_triangle.nit linux) ${NITC} + ${NITC} src/portable_triangle.nit -m linux -o $@ + +check: bin/standalone_triangle bin/triangle + bin/standalone_triangle + bin/triangle + +android: bin/triangle.apk +bin/triangle.apk: $(shell ${NITLS} -M src/portable_triangle.nit android) ${NITC} res/drawable-hdpi/icon.png + ${NITC} src/portable_triangle.nit -m android -o $@ + +res/drawable-hdpi/icon.png: art/icon.svg + ../../../../contrib/inkscape_tools/bin/svg_to_icons --out res --android art/icon.svg diff --git a/lib/gamnit/examples/triangle/art/icon.svg b/lib/gamnit/examples/triangle/art/icon.svg new file mode 100644 index 0000000..26f7c04 --- /dev/null +++ b/lib/gamnit/examples/triangle/art/icon.svg @@ -0,0 +1,82 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/lib/gamnit/examples/triangle/bin/.gitignore b/lib/gamnit/examples/triangle/bin/.gitignore new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/lib/gamnit/examples/triangle/bin/.gitignore @@ -0,0 +1 @@ +* diff --git a/lib/gamnit/examples/triangle/package.ini b/lib/gamnit/examples/triangle/package.ini new file mode 100644 index 0000000..f673878 --- /dev/null +++ b/lib/gamnit/examples/triangle/package.ini @@ -0,0 +1,11 @@ +[package] +name=triangle +tags=example +maintainer=Alexis Laferrière +license=Apache-2.0 +[upstream] +browse=https://github.com/nitlang/nit/tree/master/lib/gamnit/examples/triangle/ +git=https://github.com/nitlang/nit.git +git.directory=lib/gamnit/examples/triangle/ +homepage=http://nitlanguage.org +issues=https://github.com/nitlang/nit/issues diff --git a/lib/gamnit/examples/triangle/res/.gitignore b/lib/gamnit/examples/triangle/res/.gitignore new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/lib/gamnit/examples/triangle/res/.gitignore @@ -0,0 +1 @@ +* diff --git a/lib/gamnit/examples/triangle/src/portable_triangle.nit b/lib/gamnit/examples/triangle/src/portable_triangle.nit new file mode 100644 index 0000000..ac8e0e6 --- /dev/null +++ b/lib/gamnit/examples/triangle/src/portable_triangle.nit @@ -0,0 +1,138 @@ +# 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. + +# Portable example of using Gamnit with custom calls to OpenGL ES 2.0 +# +# References: +# * The book OpenGL ES 2.0 Programming Guide +# * https://code.google.com/p/opengles-book-samples/source/browse/trunk/LinuxX11/Chapter_2/Hello_Triangle/Hello_Triangle.c +module portable_triangle is + app_name "gamnit Triangle" + app_namespace "org.nitlanguage.triangle" + app_version(1, 0, git_revision) +end + +import gamnit + +redef class App + + # Our only program for the graphic card + var program: GLProgram is noautoinit + + # The only vertex sharder + var vertex_shader: GLVertexShader is noautoinit + + # The only fragment sharder + var fragment_shader: GLFragmentShader is noautoinit + + # Vertex data for the triangle + var vertex_array: VertexArray is noautoinit + + redef fun on_create + do + super + + var display = display + assert display != null + + print "Width: {display.width}" + print "Height: {display.height}" + + assert_no_gl_error + assert gl.shader_compiler else print "Cannot compile shaders" + + # GL program + program = new GLProgram + if not program.is_ok then + print "Program is not ok: {gl.error.to_s}\nLog:" + print program.info_log + abort + end + assert_no_gl_error + + # Vertex shader + vertex_shader = new GLVertexShader + assert vertex_shader.is_ok else print "Vertex shader is not ok: {gl.error}" + vertex_shader.source = """ + attribute vec4 vPosition; + void main() + { + gl_Position = vPosition; + } + """@glsl_vertex_shader.to_cstring + vertex_shader.compile + assert vertex_shader.is_compiled else print "Vertex shader compilation failed with: {vertex_shader.info_log} {program.info_log}" + assert_no_gl_error + + # Fragment shader + fragment_shader = new GLFragmentShader + assert fragment_shader.is_ok else print "Fragment shader is not ok: {gl.error}" + fragment_shader.source = """ + precision mediump float; + void main() + { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + } + """@glsl_fragment_shader.to_cstring + fragment_shader.compile + assert fragment_shader.is_compiled else print "Fragment shader compilation failed with: {fragment_shader.info_log}" + assert_no_gl_error + + # Attach to program + program.attach_shader vertex_shader + program.attach_shader fragment_shader + program.bind_attrib_location(0, "vPosition") + program.link + assert program.is_linked else print "Linking failed: {program.info_log}" + assert_no_gl_error + + # Draw! + var vertices = [0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0] + vertex_array = new VertexArray(0, 3, vertices) + vertex_array.attrib_pointer + end + + redef fun frame_core + do + var display = display + if display != null then + gl.clear_color(0.5, 0.0, 0.5, 1.0) + + assert_no_gl_error + gl.viewport(0, 0, display.width, display.height) + gl.clear((new GLBuffer).color) + program.use + vertex_array.enable + + glDrawArrays(new GLDrawMode.triangles, 0, 3) + + display.flip + end + end + + redef fun on_stop + do + # Clean up + program.delete + vertex_shader.delete + fragment_shader.delete + + # Close gamnit + var display = display + if display != null then display.close + end +end + +if "NIT_TESTING".environ == "true" then exit(0) +super diff --git a/lib/gamnit/examples/triangle/src/standalone_triangle.nit b/lib/gamnit/examples/triangle/src/standalone_triangle.nit new file mode 100644 index 0000000..04e14db --- /dev/null +++ b/lib/gamnit/examples/triangle/src/standalone_triangle.nit @@ -0,0 +1,112 @@ +# 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. + +# Example of using `GamnitDisplay` to setup a screen for custom calls to OpenGL ES 2.0 +# +# This example does not support the lifecycle of mobile platforms, as such it only works on desktop computers. +# +# References: +# * The book OpenGL ES 2.0 Programming Guide +# * https://code.google.com/p/opengles-book-samples/source/browse/trunk/LinuxX11/Chapter_2/Hello_Triangle/Hello_Triangle.c +module standalone_triangle + +import app +import gamnit::display + +if "NIT_TESTING".environ == "true" then exit(0) + +# Setup gamnit +var display = new GamnitDisplay +display.setup + +var width = display.width +var height = display.height +print "Width: {width}" +print "Height: {height}" + +# Custom calls to OpenGL ES 2.0 +assert_no_gl_error +assert gl.shader_compiler else print "Cannot compile shaders" + +# GL program +print gl.error.to_s +var program = new GLProgram +if not program.is_ok then + print "Program is not ok: {gl.error.to_s}\nLog:" + print program.info_log + abort +end +assert_no_gl_error + +# Vertex shader +var vertex_shader = new GLVertexShader +assert vertex_shader.is_ok else print "Vertex shader is not ok: {gl.error}" +vertex_shader.source = """ +attribute vec4 vPosition; +void main() +{ + gl_Position = vPosition; +} +"""@glsl_vertex_shader.to_cstring +vertex_shader.compile +assert vertex_shader.is_compiled else print "Vertex shader compilation failed with: {vertex_shader.info_log} {program.info_log}" +assert_no_gl_error + +# Fragment shader +var fragment_shader = new GLFragmentShader +assert fragment_shader.is_ok else print "Fragment shader is not ok: {gl.error}" +fragment_shader.source = """ +precision mediump float; +void main() +{ + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); +} +"""@glsl_fragment_shader.to_cstring +fragment_shader.compile +assert fragment_shader.is_compiled else print "Fragment shader compilation failed with: {fragment_shader.info_log}" +assert_no_gl_error + +# Attach to program +program.attach_shader vertex_shader +program.attach_shader fragment_shader +program.bind_attrib_location(0, "vPosition") +program.link +assert program.is_linked else print "Linking failed: {program.info_log}" +assert_no_gl_error + +# Draw! +var vertices = [0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0] +var vertex_array = new VertexArray(0, 3, vertices) +vertex_array.attrib_pointer +gl.clear_color(0.5, 0.0, 0.5, 1.0) +for i in [0..1000[ do + printn "." + assert_no_gl_error + gl.viewport(0, 0, width, height) + gl.clear((new GLBuffer).color) + program.use + vertex_array.enable + + glDrawArrays(new GLDrawMode.triangles, 0, 3) + + display.flip +end + +# Clean up +program.delete +vertex_shader.delete +fragment_shader.delete + +# Close gamnit +display.close diff --git a/lib/gamnit/gamnit.nit b/lib/gamnit/gamnit.nit index 2fa5b8e..43ec95c 100644 --- a/lib/gamnit/gamnit.nit +++ b/lib/gamnit/gamnit.nit @@ -14,3 +14,54 @@ # Game and multimedia framework for Nit module gamnit + +import app + +import display + +import gamnit_android is conditional(android) + +redef class App + + # Main `GamnitDisplay` initialized by `on_create` + var display: nullable GamnitDisplay = null + + redef fun on_create + do + super + + var display = new GamnitDisplay + display.setup + self.display = display + end + + # Core of the frame logic, executed only when the display is visible + # + # This method should be redefined by user modules to customize the behavior of the game. + protected fun frame_core do end + + # Full frame logic, executed even if the display is not visible + # + # This method wraps `frame_core` and other services to be executed in the main app loop. + # + # To customize the behavior on each turn, it is preferable to redefined `frame_core`. + # Still, `frame_full` can be redefined with care for more control. + protected fun frame_full + do + var display = display + if display != null then frame_core + + feed_events + end + + redef fun run + do + # TODO manage exit condition + loop frame_full + end + + # Loop on available events and feed them back to the app + # + # The implementation varies per platform. + private fun feed_events do end +end diff --git a/lib/gamnit/gamnit_android.nit b/lib/gamnit/gamnit_android.nit new file mode 100644 index 0000000..647c741 --- /dev/null +++ b/lib/gamnit/gamnit_android.nit @@ -0,0 +1,24 @@ +# 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. + +# Support services for Gamnit on Android +module gamnit_android + +import android + +intrude import gamnit + +redef class App + redef fun feed_events do app.poll_looper 0 +end diff --git a/lib/linux/linux.nit b/lib/linux/linux.nit index 8b90102..04a0c5d 100644 --- a/lib/linux/linux.nit +++ b/lib/linux/linux.nit @@ -18,3 +18,25 @@ module linux import app + +redef class App + redef fun setup + do + super + + on_create + on_restore_state + on_start + on_resume + end + + redef fun run + do + super + + on_pause + on_save_state + on_stop + on_destroy + end +end diff --git a/lib/mnit/linux/linux_app.nit b/lib/mnit/linux/linux_app.nit index 938bfd8..7bc03a0 100644 --- a/lib/mnit/linux/linux_app.nit +++ b/lib/mnit/linux/linux_app.nit @@ -35,21 +35,6 @@ redef class App display = new Opengles1Display super - - on_create - on_restore_state - on_start - on_resume - end - - redef fun run - do - super - - on_pause - on_save_state - on_stop - on_destroy end redef fun generate_input