lib: intro abstract mnit lib
authorAlexis Laferrière <alexis.laf@xymus.net>
Sun, 25 Aug 2013 02:11:19 +0000 (22:11 -0400)
committerAlexis Laferrière <alexis.laf@xymus.net>
Sun, 25 Aug 2013 03:27:26 +0000 (23:27 -0400)
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

lib/mnit/app.nit [new file with mode: 0644]
lib/mnit/assets.nit [new file with mode: 0644]
lib/mnit/display.nit [new file with mode: 0644]
lib/mnit/input_events.nit [new file with mode: 0644]
lib/mnit/mnit.nit [new file with mode: 0644]
lib/mnit/opengles1.nit [new file with mode: 0644]

diff --git a/lib/mnit/app.nit b/lib/mnit/app.nit
new file mode 100644 (file)
index 0000000..1e8ac63
--- /dev/null
@@ -0,0 +1,113 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2011-2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# General Mnit application structure
+module app
+
+import display
+
+# An App instance serves as base to every Mnit projects.
+#
+# This class is redefed by plateforme modules and so
+# App can be specialized directly in the user app.
+abstract class App
+       type IE: InputEvent
+       type D: Display
+       type I: Image
+
+       # Display to use by apps
+       # Is null if the display is not available or not yet ready
+       var display: nullable D protected writable = null
+
+       # Received quit order
+       var quit: Bool writable = false
+
+       init do end
+
+       # App is visible? (vs minimized or in background)
+       fun visible: Bool is abstract
+
+       # Invoqued at each frame
+       # Usually you want to redef frame_core instead of this
+       fun full_frame
+       do
+               var display = self.display
+               if display != null then
+                       display.begin
+                       frame_core( display )
+                       display.finish
+               end
+       end
+
+       # Main frame method to redef
+       # Is called between readying display and flipping it
+       fun frame_core( display: D ) is abstract
+
+       #fun start do end
+       #fun stop do end
+       #fun destroy do end
+
+       # Called when asked by the system (mainly for Android)
+       fun save do end
+
+       # Called when asked by the system (mainly for Android)
+       fun pause do end
+
+       # Called when asked by the system (mainly for Android)
+       fun resume do end
+
+       # System notification
+       fun gained_focus do end
+
+       # System notification
+       fun lost_focus do end
+
+       # Main init method for graphical stuff
+       # Is called when display is ready so graphical assets
+       # can be loaded at this time.
+       fun init_window do end
+
+       # Called before destroying the window
+       fun term_window do end
+
+       # Helper function for logging
+       fun log_error( msg: String ) do print "#nit error: {msg}"
+
+       # Helper function for logging
+       fun log_warning( msg: String ) do print "#nit warn: {msg}"
+
+       # Helper function for logging
+       fun log_info( msg: String ) do print "#nit info: {msg}"
+
+       # Receive and deal with all inputs
+       fun input( event: InputEvent ): Bool
+       do
+               return false
+       end
+
+       # Internal method to generate inputs
+       protected fun generate_input is abstract
+
+       # Main app loop
+       # Usually you want to redef framw_core instead of this
+       fun main_loop
+       do
+               while not quit do
+                       generate_input
+                       full_frame
+               end
+       end
+end
diff --git a/lib/mnit/assets.nit b/lib/mnit/assets.nit
new file mode 100644 (file)
index 0000000..bd23f0a
--- /dev/null
@@ -0,0 +1,67 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2011-2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Manages all assets usable by an Mnit app
+module assets
+
+import app
+import display
+
+# General asset
+interface Asset
+end
+
+# An String is an asset, returned from a text file
+redef class String
+       super Asset
+end
+
+# An Image is an asset
+redef interface Image
+       super Asset
+end
+
+redef class App
+       # Load a genereal asset from file name
+       # Will find the file within the assets/ directory
+       # Crashes if file not found
+       fun load_asset( id: String ): Asset
+       do
+               var asset = try_loading_asset( id )
+               if asset == null then # error
+                       log_error( "asset <{id}> could not be loaded." )
+                       abort
+               else
+                       return asset
+               end
+       end
+
+       # Load an Image assets
+       # Crashes if file not found or not an image
+       fun load_image( id: String ): Image
+       do
+               var asset = load_asset( id )
+               if asset isa Image then
+                       return asset
+               else
+                       log_error( "asset <{id}> is not an image." )
+                       abort
+               end
+       end
+
+       # Load an assets without error if not found
+       fun try_loading_asset( id: String ): nullable Asset is abstract
+end
diff --git a/lib/mnit/display.nit b/lib/mnit/display.nit
new file mode 100644 (file)
index 0000000..06a7572
--- /dev/null
@@ -0,0 +1,96 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2011-2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Defines abstract display classes
+module display
+
+import input_events
+
+# Any class with a size
+interface Sized
+       fun width: Int is abstract
+       fun height: Int is abstract
+end
+
+# General image class, will be specialized for each classes
+interface Image
+       super Sized
+       fun destroy is abstract
+
+       #var scale: Float is abstract
+       # Scale this image when blit
+       fun scale: Float is abstract
+       fun scale=( v: Float ) is abstract
+
+       #var blended: Bool is abstract
+       # Use blending on this image?
+       fun blended: Bool is abstract
+       fun blended=( v: Bool ) is abstract
+
+       # Get another image from this one
+       fun subimage( x, y, w, h: Int ): Image is abstract
+end
+
+# General class for everything drawable to
+# Is used by drawable images and display
+interface Drawable
+       type I: Image
+
+       # Call to prepare for drawing
+       fun begin is abstract
+
+       # Call when drawing is finished
+       fun finish is abstract
+
+       # Set viewport for drawing
+       fun set_viewport( x, y, w, h: Int ) is abstract
+
+       # Draw image on self, for top left position
+       fun blit( image: I, x, y: Int ) is abstract
+
+       # Draw image, centered at position
+       fun blit_centered( image: I, x, y: Int ) is abstract
+
+       # Draw image, centered at position but rotated
+       fun blit_rotated( image: I, x, y, angle: Float ) is abstract
+
+       # Draw image, centered, rotated and scaled
+       fun blit_rotated_scaled( image: I, x, y, angle, scale: Float ) is abstract
+
+       # Draw image by specifying the positon of each image corners
+       # Corners are in clockwise order stating top right
+       # a is top right, b is bottom right, c is bottom left and d is top left
+       fun blit_stretched( image: I, ax, ay, bx, by, cx, cy, dx, dy: Float )
+               is abstract
+
+       # Clear entire window with given color
+       fun clear( r, g, b: Float ) is abstract
+end
+
+# General display class, is sized and drawable
+interface Display
+       super Sized
+       super Drawable
+
+       # InputEvent type associated to this display type
+       type IE: InputEvent
+end
+
+# General drawable display image
+interface DrawableImage
+       super Drawable
+       super Image
+end
diff --git a/lib/mnit/input_events.nit b/lib/mnit/input_events.nit
new file mode 100644 (file)
index 0000000..93e8a95
--- /dev/null
@@ -0,0 +1,107 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2011-2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Defines abstract classes for user inputs
+module input_events
+
+# General type of inputs
+interface InputEvent
+end
+
+# Mouse and touch input events
+interface PointerEvent
+       super InputEvent
+
+       # X position on screen (in pixels)
+       fun x: Float is abstract
+
+       # Y position on screen (in pixels)
+       fun y: Float is abstract
+
+       # Is down? either going down or already down
+       fun pressed: Bool is abstract
+       fun depressed: Bool is abstract
+end
+
+# Pointer motion event, mais concern many events
+interface MotionEvent
+       super InputEvent
+
+       # A pointer just went down?
+       fun just_went_down: Bool is abstract
+
+       # Which pointer is down, if any
+       fun down_pointer: nullable PointerEvent is abstract
+end
+
+# Specific touch event
+interface TouchEvent
+       super PointerEvent
+
+       # Pressure level of input
+       fun pressure: Float is abstract
+end
+
+# Keyboard or other keys event
+interface KeyEvent
+       super InputEvent
+
+       # Key is currently down?
+       fun is_down: Bool is abstract
+
+       # Key is currently up?
+       fun is_up: Bool is abstract
+
+       # Key is the up arrow key?
+       fun is_arrow_up: Bool is abstract
+
+       # Key is the left arrow key?
+       fun is_arrow_left: Bool is abstract
+
+       # Key is the down arrow key?
+       fun is_arrow_down: Bool is abstract
+
+       # Key is the right arrow key?
+       fun is_arrow_right: Bool is abstract
+
+       # Key code, is plateform specific
+       fun code: Int is abstract
+
+       # Get Char value of key, if any
+       fun to_c: nullable Char is abstract
+end
+
+# Mobile hardware (or pseudo hardware) event
+interface MobileKeyEvent
+       super KeyEvent
+
+       # Key is back button? (mostly for Android)
+       fun is_back_key: Bool is abstract
+
+       # Key is menu button? (mostly for Android)
+       fun is_menu_key: Bool is abstract
+
+       # Key is search button? (mostly for Android)
+       fun is_search_key: Bool is abstract
+
+       # Key is home button? (mostly for Android)
+       fun is_home_key: Bool is abstract
+end
+
+# Quit event, used for window close button
+interface QuitEvent
+       super InputEvent
+end
diff --git a/lib/mnit/mnit.nit b/lib/mnit/mnit.nit
new file mode 100644 (file)
index 0000000..e3d1102
--- /dev/null
@@ -0,0 +1,22 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2011-2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# General module for cross-compatibility between multiple platforms
+module mnit
+
+import app
+import opengles1
+import assets
diff --git a/lib/mnit/opengles1.nit b/lib/mnit/opengles1.nit
new file mode 100644 (file)
index 0000000..182d9d0
--- /dev/null
@@ -0,0 +1,619 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2011-2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# OpenGL ES1 general support (most of it)
+module opengles1
+
+import display
+
+in "C header" `{
+       #include <EGL/egl.h>
+       #include <GLES/gl.h>
+       #define GL_GLEXT_PROTOTYPES 1
+       #include <GLES/glext.h>
+       #include <errno.h>
+
+       #define LOGW(...) ((void)fprintf(stderr, "# warn: %s", __VA_ARGS__))
+       #ifdef DEBUG
+               #define LOGI(...) ((void)fprintf(stderr, "# info: %s", __VA_ARGS__))
+       #else
+               #define LOGI(...) (void)0
+       #endif
+
+       EGLDisplay mnit_display;
+       EGLSurface mnit_surface;
+       EGLContext mnit_context;
+       EGLConfig mnit_config;
+       int32_t mnit_width;
+       int32_t mnit_height;
+       float mnit_zoom;
+
+       struct mnit_opengles_Texture {
+               GLuint texture;
+
+               /* offsets on source texture */
+               float src_xo, src_yo, src_xi, src_yi;
+
+               /* destination width and height */
+               int width, height;
+
+               /* may vary depending on scaling */
+               int center_x, center_y;
+
+               float scale;
+               int blended;
+       };
+
+       struct mnit_opengles_DrawableTexture {
+               struct mnit_opengles_Texture super;
+               GLuint fbo;
+               GLuint depth;
+               GLuint color;
+               /*
+               EGLSurface surface;
+               int width, height;
+               */
+       };
+
+       GLenum mnit_opengles_error_code;
+
+       struct mnit_opengles_Texture *mnit_opengles_load_image( const uint_least32_t *pixels, int width, int height, int has_alpha );
+`}
+
+in "C" `{
+       extern NativeWindowType mnit_window;
+       extern EGLNativeDisplayType mnit_native_display;
+
+       GLfloat mnit_opengles_vertices[6][3] =
+       {
+               {0.0f, 0.0f, 0.0f},
+               {0.0f, 1.0f, 0.0f},
+               {1.0f, 1.0f, 0.0f},
+               {0.0f, 0.0f, 0.0f},
+               {1.0f, 1.0f, 0.0f},
+               {1.0f, 0.0f, 0.0f},
+       };
+       GLfloat mnit_opengles_texture[6][2] =
+       {
+               {0.0f, 0.0f},
+               {0.0f, 1.0f},
+               {1.0f, 1.0f},
+               {0.0f, 0.0f},
+               {1.0f, 1.0f},
+               {1.0f, 0.0f}
+       };
+
+       struct mnit_opengles_Texture *mnit_opengles_load_image( const uint_least32_t *pixels, int width, int height, int has_alpha )
+       {
+               struct mnit_opengles_Texture *image = malloc(sizeof(struct mnit_opengles_Texture));
+               int format = has_alpha? GL_RGBA: GL_RGB;
+
+               image->width = width;
+               image->height = height;
+               image->center_x = width/2;
+               image->center_y = height/2;
+               image->scale = 1.0f;
+               image->blended = has_alpha;
+
+               image->src_xo = 0;
+               image->src_yo = 0;
+               image->src_xi = 1.0;
+               image->src_yi = 1.0;
+
+
+               if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
+                       LOGW ("a error loading image: %i\n", mnit_opengles_error_code);
+                       printf( "%i\n", mnit_opengles_error_code );
+               }
+               glGenTextures(1, &image->texture);
+
+               if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
+                       LOGW ("b error loading image: %i\n", mnit_opengles_error_code);
+                       printf( "%i\n", mnit_opengles_error_code );
+               }
+               glBindTexture(GL_TEXTURE_2D, image->texture);
+
+               if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
+                       LOGW ("c error loading image: %i\n", mnit_opengles_error_code);
+                       printf( "%i\n", mnit_opengles_error_code );
+               }
+               glTexImage2D(   GL_TEXTURE_2D, 0, format, width, height,
+                                               0, format, GL_UNSIGNED_BYTE, (GLvoid*)pixels);
+
+               if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
+                       LOGW ("d error loading image: %i\n", mnit_opengles_error_code);
+                       printf( "%i\n", mnit_opengles_error_code );
+               }
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+               if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
+                       LOGW ("e error loading image: %i\n", mnit_opengles_error_code);
+                       printf( "%i\n", mnit_opengles_error_code );
+               }
+
+               return image;
+       }
+`}
+
+# OpenGL ES1 display
+# Uses 3d hardware optimization
+class Opengles1Display
+       super Display
+
+       redef type I: Opengles1Image
+
+       init do extern_init
+       fun midway_init( format: Int ) do end
+       fun extern_init: Bool is extern import midway_init `{
+               /* initialize OpenGL ES and EGL */
+               const EGLint attribs[] = {
+                               EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+                               EGL_BLUE_SIZE, 8,
+                               EGL_GREEN_SIZE, 8,
+                               EGL_RED_SIZE, 8,
+                               EGL_NONE
+               };
+               EGLint w, h, dummy, format;
+               EGLint numConfigs;
+               EGLConfig config;
+               EGLSurface surface;
+               EGLContext context;
+
+               EGLDisplay display = eglGetDisplay(mnit_native_display);
+               if ( display == EGL_NO_DISPLAY) {
+                       LOGW("Unable to eglGetDisplay");
+                       return -1;
+               }
+
+               if ( eglInitialize(display, 0, 0) == EGL_FALSE) {
+                       LOGW("Unable to eglInitialize");
+                       return -1;
+               }
+
+               if ( eglChooseConfig(display, attribs, &config, 1, &numConfigs) == EGL_FALSE) {
+                       LOGW("Unable to eglChooseConfig");
+                       return -1;
+               }
+
+               if ( numConfigs == 0 ) {
+                       LOGW("No configs available for egl");
+                       return -1;
+               }
+
+               if ( eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format) == EGL_FALSE) {
+                       LOGW("Unable to eglGetConfigAttrib");
+                       return -1;
+               }
+
+               /* Used by Android to set buffer geometry */
+               Opengles1Display_midway_init(recv, format);
+
+               surface = eglCreateWindowSurface(display, config, mnit_window, NULL);
+               context = eglCreateContext(display, config, NULL, NULL);
+
+               if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
+                       LOGW("Unable to eglMakeCurrent");
+                       return -1;
+               }
+
+               eglQuerySurface(display, surface, EGL_WIDTH, &w);
+               eglQuerySurface(display, surface, EGL_HEIGHT, &h);
+
+               mnit_display = display;
+               mnit_context = context;
+               mnit_surface = surface;
+               mnit_config = config;
+               mnit_width = w;
+               mnit_height = h;
+               mnit_zoom = 1.0f;
+
+               LOGI( "surface: %i, display: %i, w %i, h %i", (int)surface, (int)display, w, h );
+
+               glViewport(0, 0, mnit_width, mnit_height);
+               glMatrixMode(GL_PROJECTION);
+               glLoadIdentity();
+               glOrthof(0.0f, w, h, 0.0f, 0.0f, 1.0f);
+               glMatrixMode(GL_MODELVIEW);
+
+               glFrontFace( GL_CW );
+
+               return 0;
+       `}
+
+       fun close is extern `{
+               if ( mnit_display != EGL_NO_DISPLAY) {
+                       eglMakeCurrent( mnit_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+                       if ( mnit_context != EGL_NO_CONTEXT) {
+                               eglDestroyContext( mnit_display,  mnit_context );
+                       }
+                       if ( mnit_surface != EGL_NO_SURFACE) {
+                               eglDestroySurface( mnit_display,  mnit_surface );
+                       }
+                       eglTerminate( mnit_display);
+               }
+                mnit_display = EGL_NO_DISPLAY;
+                mnit_context = EGL_NO_CONTEXT;
+                mnit_surface = EGL_NO_SURFACE;
+       `}
+
+       redef fun begin is extern `{
+               glClear(GL_COLOR_BUFFER_BIT);
+               glLoadIdentity();
+       `}
+
+       redef fun width: Int is extern `{
+               return mnit_width;
+       `}
+       redef fun height: Int is extern `{
+               return mnit_height;
+       `}
+
+       redef fun finish is extern `{
+               eglSwapBuffers( mnit_display, mnit_surface );
+       `}
+
+       fun set_as_target is extern `{
+               glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+       `}
+
+       redef fun set_viewport( x, y, w, h ) is extern `{
+               glLoadIdentity();
+               glViewport(0,0, mnit_width, mnit_height );
+               glMatrixMode(GL_PROJECTION);
+               glLoadIdentity();
+               glOrthof(x, x+w, y+h, y, 0.0f, 1.0f);
+               /*glOrthof(0.0f, w, h, 0.0f, 0.0f, 1.0f);*/
+               mnit_zoom = ((float)w)/mnit_width;
+               glMatrixMode(GL_MODELVIEW);
+               glFrontFace( GL_CW );
+       `}
+
+       redef fun blit( image, x, y ) is extern  `{
+               GLfloat texture_coord[6][2] =
+               {
+                       {image->src_xo, image->src_yo},
+                       {image->src_xo, image->src_yi},
+                       {image->src_xi, image->src_yi},
+                       {image->src_xo, image->src_yo},
+                       {image->src_xi, image->src_yi},
+                       {image->src_xi, image->src_yo}
+               };
+
+               glLoadIdentity();
+
+               glBindTexture(GL_TEXTURE_2D, image->texture);
+
+               glEnableClientState(GL_VERTEX_ARRAY);
+               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+               glTranslatef( x, y, 0.0f );
+               glScalef( image->width*image->scale, image->height*image->scale, 1.0f );
+
+               if ( image->blended ) {
+                       glEnable(GL_BLEND);
+                       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               }
+
+               glEnable(GL_TEXTURE_2D);
+               glDisable(GL_DEPTH_TEST);
+
+               glVertexPointer(3, GL_FLOAT, 0, mnit_opengles_vertices);
+               glTexCoordPointer(2, GL_FLOAT, 0, texture_coord ); /* mnit_opengles_texture); */
+
+               glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
+
+               glDisableClientState(GL_VERTEX_ARRAY);
+               glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+               if ( image->blended ) glDisable(GL_BLEND);
+               glDisable(GL_TEXTURE_2D);
+
+               if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
+                  LOGW ("error drawing: %i", mnit_opengles_error_code);
+               }
+       `}
+
+    redef fun blit_centered( img, x, y )
+    do
+               x = x - img.center_x
+               y = y - img.center_y
+               blit( img, x, y )
+    end
+
+       redef fun blit_rotated( image, x, y, angle ) is extern  `{
+               GLfloat texture_coord[6][2] =
+               {
+                       {image->src_xo, image->src_yo},
+                       {image->src_xo, image->src_yi},
+                       {image->src_xi, image->src_yi},
+                       {image->src_xo, image->src_yo},
+                       {image->src_xi, image->src_yi},
+                       {image->src_xi, image->src_yo}
+               };
+
+               glLoadIdentity();
+
+               glBindTexture(GL_TEXTURE_2D, image->texture);
+
+               glEnableClientState(GL_VERTEX_ARRAY);
+               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+               glTranslatef( x, y, 0.0f );
+               glRotatef( angle*180.0f/3.14156f, 0, 0, 1.0f );
+               glTranslatef( image->width*image->scale/-2, image->height*image->scale/-2, 0.0f );
+               glScalef( image->width*image->scale, image->height*image->scale, 1.0f );
+               if ( image->blended ) {
+                       glEnable(GL_BLEND);
+                       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               }
+               glEnable(GL_TEXTURE_2D);
+               glDisable(GL_DEPTH_TEST);
+
+               glVertexPointer(3, GL_FLOAT, 0, mnit_opengles_vertices);
+               glTexCoordPointer(2, GL_FLOAT, 0, texture_coord );
+
+               glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
+
+               glDisableClientState(GL_VERTEX_ARRAY);
+               glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+               if ( image->blended ) glDisable(GL_BLEND);
+               glDisable(GL_TEXTURE_2D);
+
+               if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
+                  LOGW ("error drawing: %i", mnit_opengles_error_code);
+               }
+       `}
+#    fun clear( r, g, b: Int ) is extern `{
+#      glClear(GL_COLOR_BUFFER_BIT);
+#    `}
+
+       # a = top left, b = bottom left, c = bottom right, d = top right
+       redef fun blit_stretched( image, ax, ay, bx, by, cx, cy, dx, dy ) is extern  `{
+               GLfloat texture_coord[6][2] =
+               {
+                       {image->src_xo, image->src_yo},
+                       {image->src_xo, image->src_yi},
+                       {image->src_xi, image->src_yi},
+                       {image->src_xo, image->src_yo},
+                       {image->src_xi, image->src_yi},
+                       {image->src_xi, image->src_yo}
+               };
+
+               GLfloat mnit_opengles_vertices_stretched[6][3] =
+               {
+                       {ax, ay, 0.0f},
+                       {bx, by, 0.0f},
+                       {cx, cy, 0.0f},
+                       {ax, ay, 0.0f},
+                       {cx, cy, 0.0f},
+                       {dx, dy, 0.0f},
+               };
+
+               glLoadIdentity();
+
+               glBindTexture(GL_TEXTURE_2D, image->texture);
+
+               glEnableClientState(GL_VERTEX_ARRAY);
+               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+               if ( image->blended ) {
+                       glEnable(GL_BLEND);
+                       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               }
+
+               glEnable(GL_TEXTURE_2D);
+               glDisable(GL_DEPTH_TEST);
+
+               glVertexPointer(3, GL_FLOAT, 0, mnit_opengles_vertices_stretched);
+               glTexCoordPointer(2, GL_FLOAT, 0, texture_coord );
+
+               glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
+
+               glDisableClientState(GL_VERTEX_ARRAY);
+               glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+               if ( image->blended ) glDisable(GL_BLEND);
+               glDisable(GL_TEXTURE_2D);
+
+               if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
+                  LOGW ("error drawing: %i", mnit_opengles_error_code);
+               }
+       `}
+
+       redef fun clear( r, g, b: Float ) is extern `{
+               glClearColor( r, g, b, 1.0 );
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+       `}
+
+       fun clear_alpha( r, g, b, a: Float ) is extern `{
+               glClearColor( r, g, b, a );
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+       `}
+end
+
+extern Opengles1Image in "C" `{struct mnit_opengles_Texture *`}
+       super Image
+
+    redef fun destroy is extern `{ free( recv ); `}
+
+    redef fun width: Int is extern `{ return recv->width; `}
+    redef fun height: Int is extern `{ return recv->height; `}
+
+       fun center_x: Int `{ return recv->center_x; `}
+       fun center_y: Int `{ return recv->center_y; `}
+
+    redef fun scale=( v: Float ) is extern `{
+               recv->scale = v;
+               recv->center_x = v*recv->width/2;
+               recv->center_y = v*recv->height/2;
+    `}
+    redef fun scale: Float is extern `{ return recv->scale; `}
+
+    redef fun blended=( v: Bool ) is extern `{ recv->blended = v; `}
+    redef fun blended: Bool is extern `{ return recv->blended; `}
+
+    # inherits scale and blend from source
+    redef fun subimage( x, y, w, h: Int ): Image is extern import Opengles1Image as ( Image ) `{
+               struct mnit_opengles_Texture* image =
+                       malloc( sizeof( struct mnit_opengles_Texture ) );
+
+               image->texture = recv->texture;
+               image->width = w;
+               image->height = h;
+               image->center_x = recv->scale*w/2;
+               image->center_y = recv->scale*h/2;
+               image->scale = recv->scale;
+               image->blended = recv->blended;
+
+               image->src_xo = ((float)x)/recv->width;
+               image->src_yo = ((float)y)/recv->height;
+               image->src_xi = ((float)w+w)/recv->width;
+               image->src_yi = ((float)x+h)/recv->height;
+
+               return Opengles1Image_as_Image( image );
+    `}
+end
+
+
+extern Opengles1DrawableImage in "C" `{struct mnit_opengles_DrawableTexture*`}
+       super DrawableImage
+    new ( w, h: Int ) is extern `{
+               struct mnit_opengles_DrawableTexture *image =
+                       malloc( sizeof(struct mnit_opengles_DrawableTexture) );
+
+               #ifdef a
+               const EGLint attribs[] = {
+                       EGL_WIDTH, w,
+                       EGL_HEIGHT, h,
+                       EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
+                       EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
+                       EGL_NONE
+               };
+
+               image->surface = eglCreatePbufferSurface( andronit.display,
+                                                                andronit.config,
+                                                                attribs );
+               if ( eglGetError() )
+                       LOGW( "eglCreatePbuffer error" );
+
+               image->width = w;
+               image->height = h;
+               image->center_x = w/2;
+               image->center_y = h/2;
+               eglMakeCurrent( andronit.display,
+                                               surface,
+                                               surface,
+                                               andronit.context );
+
+       #else
+               /* texture */
+               glGenTextures(1, &image->super.texture);
+               glBindTexture(GL_TEXTURE_2D, image->super.texture);
+               glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+               /* glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap generation included in OpenGL v1.4c */
+               glBindTexture(GL_TEXTURE_2D, 0);
+
+               /* fbo */
+               glGenFramebuffersOES( 1, &image->fbo );
+               glBindFramebufferOES( GL_FRAMEBUFFER_OES, image->fbo );
+               glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
+                               GL_COLOR_ATTACHMENT0_OES,
+                               GL_TEXTURE_2D,
+                               image->super.texture,
+                               0 );
+
+               /* depth */
+               glGenRenderbuffersOES(1, &image->depth);
+               glBindRenderbufferOES(GL_RENDERBUFFER_OES, image->depth);
+               glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES,
+                                        w, h);
+               glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);
+               glFramebufferRenderbufferOES( GL_FRAMEBUFFER_OES,
+                       GL_DEPTH_ATTACHMENT_OES,
+                       GL_RENDERBUFFER_OES,
+                       image->depth );
+
+               /* tex framebuffer */
+               glGenRenderbuffersOES(1, &image->color);
+               glBindRenderbufferOES(GL_RENDERBUFFER_OES, image->color);
+               glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, w, h);
+               glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, image->color );
+
+               if ( glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) != GL_FRAMEBUFFER_COMPLETE_OES )
+               {
+                       LOGW( "framebuffer not set" );
+                       if ( glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES )
+                               LOGW( "framebuffer not set a" );
+                       else if ( glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) == GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES )
+                               LOGW( "framebuffer not set b" );
+                       else if ( glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES )
+                               LOGW( "framebuffer not set c" );
+                       else if ( glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES )
+                               LOGW( "framebuffer not set d" );
+               }
+
+               image->super.width = w;
+               image->super.height = h;
+               image->super.center_x = w/2;
+               image->super.center_y = h/2;
+               image->super.scale = 1.0f;
+               image->super.blended = 0;
+
+               #endif
+
+               if (glGetError() != GL_NO_ERROR) LOGW( "gl error");
+
+               return image;
+       `}
+
+#    fun image: I is extern `{
+#        struct mnit_opengles_Texture *image;
+#        const uint_least32_t *pixels;
+#        pixels = malloc( sizeof(uint_least32_t)*recv->width*recv->height );
+#        glReadPixels( 0, 0, recv->width, recv->height,
+#                      GL_RGBA, GL_UNSIGNED_BYTE, pixels );
+#        image = mnit_opengles_load_image( pixels, recv->width, recv->height );
+#        return image;
+
+    fun set_as_target is extern `{
+               LOGI( "sat %i", recv->fbo );
+               glBindFramebufferOES(GL_FRAMEBUFFER_OES, recv->fbo);
+               /*glBindRenderbufferOES(GL_FRAMEBUFFER_OES, recv->color);*/
+               if (glGetError() != GL_NO_ERROR) LOGW( "gl error 0");
+               /*glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES,&recv->fbo);
+               //if (glGetError() != GL_NO_ERROR) LOGW( "gl error a");*/
+               glViewport(0, 0, recv->super.width, recv->super.height);
+
+               glMatrixMode(GL_PROJECTION);
+               glLoadIdentity();
+               glOrthof(0.0f, recv->super.width, recv->super.height, 0.0f, 0.0f, 1.0f);
+               glMatrixMode(GL_MODELVIEW);
+               glFrontFace( GL_CW );
+
+               glClearColor( 0.0f, 1.0f, 1.0f, 1.0f );
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+       `}
+
+    fun unset_as_target is extern `{
+               glFlush();
+               /*glBindTexture(GL_TEXTURE_2D, recv->super.texture);
+               glGenerateMipmapOES(GL_TEXTURE_2D);
+               glBindTexture(GL_TEXTURE_2D, 0);*/
+               glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
+               if (glGetError() != GL_NO_ERROR) LOGW( "gl error");
+       `}
+end
+