lib/mnit: expand images to the nearest power of 2 for OpenGL ES 1.0
[nit.git] / lib / mnit / opengles1.nit
index fda5a3f..24a904b 100644 (file)
 # limitations under the License.
 
 # OpenGL ES1 general support (most of it)
-module opengles1
+module opengles1 is pkgconfig("glesv1_cm", "egl")
 
-import display
+import mnit_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;
@@ -39,7 +29,6 @@ in "C header" `{
        EGLConfig mnit_config;
        int32_t mnit_width;
        int32_t mnit_height;
-       float mnit_zoom;
 
        struct mnit_opengles_Texture {
                GLuint texture;
@@ -66,7 +55,9 @@ in "C header" `{
 
        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 );
+       struct mnit_opengles_Texture *mnit_opengles_load_image(
+               const uint_least32_t *pixels, int width, int height,
+               int width_pow2, int height_pow2, int has_alpha);
 `}
 
 in "C" `{
@@ -90,7 +81,9 @@ in "C" `{
                {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 *mnit_opengles_load_image(
+               const uint_least32_t *pixels, int width, int height,
+               int width_pow2, int height_pow2, int has_alpha)
        {
                struct mnit_opengles_Texture *image = malloc(sizeof(struct mnit_opengles_Texture));
                int format = has_alpha? GL_RGBA: GL_RGB;
@@ -104,38 +97,36 @@ in "C" `{
 
                image->src_xo = 0;
                image->src_yo = 0;
-               image->src_xi = 1.0;
-               image->src_yi = 1.0;
-
+               image->src_xi = ((float)width)/width_pow2;
+               image->src_yi = ((float)height)/height_pow2;
 
                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 );
+                       PRINT_ERROR("error loading image after malloc: %i", 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 );
+                       PRINT_ERROR("error loading image after glGenTextures: %i", 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 );
+                       PRINT_ERROR("error loading image glBindTexture: %i", mnit_opengles_error_code);
                }
-               glTexImage2D(   GL_TEXTURE_2D, 0, format, width, height,
+
+               glTexImage2D(   GL_TEXTURE_2D, 0, format, width_pow2, height_pow2,
                                                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 );
+                       PRINT_ERROR("error loading image after glTexImage2D: %i", 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 );
+                       PRINT_ERROR("error loading image after gtTexParameter: %i", mnit_opengles_error_code);
                }
 
                return image;
@@ -168,27 +159,27 @@ class Opengles1Display
 
                EGLDisplay display = eglGetDisplay(mnit_native_display);
                if ( display == EGL_NO_DISPLAY) {
-                       LOGW("Unable to eglGetDisplay");
+                       PRINT_ERROR("Unable to eglGetDisplay");
                        return -1;
                }
 
                if ( eglInitialize(display, 0, 0) == EGL_FALSE) {
-                       LOGW("Unable to eglInitialize");
+                       PRINT_ERROR("Unable to eglInitialize");
                        return -1;
                }
 
                if ( eglChooseConfig(display, attribs, &config, 1, &numConfigs) == EGL_FALSE) {
-                       LOGW("Unable to eglChooseConfig");
+                       PRINT_ERROR("Unable to eglChooseConfig");
                        return -1;
                }
 
                if ( numConfigs == 0 ) {
-                       LOGW("No configs available for egl");
+                       PRINT_ERROR("No configs available for egl");
                        return -1;
                }
 
                if ( eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format) == EGL_FALSE) {
-                       LOGW("Unable to eglGetConfigAttrib");
+                       PRINT_ERROR("Unable to eglGetConfigAttrib");
                        return -1;
                }
 
@@ -199,7 +190,7 @@ class Opengles1Display
                context = eglCreateContext(display, config, NULL, NULL);
 
                if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
-                       LOGW("Unable to eglMakeCurrent");
+                       PRINT_ERROR("Unable to eglMakeCurrent");
                        return -1;
                }
 
@@ -212,9 +203,6 @@ class Opengles1Display
                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);
@@ -259,22 +247,19 @@ class Opengles1Display
                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);
-               mnit_zoom = ((float)w)/mnit_width;
                glMatrixMode(GL_MODELVIEW);
                glFrontFace( GL_CW );
        `}
 
-       redef fun blit( image, x, y ) is extern  `{
+       redef fun blit(image, x, y) do native_blit(image, x.to_f, y.to_f)
+
+       private fun native_blit(image: Opengles1Image, x, y: Float)  `{
                GLfloat texture_coord[4][2] =
                {
                        {image->src_xo, image->src_yi},
@@ -311,18 +296,20 @@ class Opengles1Display
                glDisable(GL_TEXTURE_2D);
 
                if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
-                  LOGW ("error drawing: %i", mnit_opengles_error_code);
+                  PRINT_ERROR("error drawing: %i", mnit_opengles_error_code);
                }
        `}
 
-    redef fun blit_centered( img, x, y )
+    redef fun blit_centered(img, x, y)
     do
-               x = x - img.center_x
-               y = y - img.center_y
-               blit( img, x, y )
+               x = x.sub(img.center_x)
+               y = y.sub(img.center_y)
+               blit(img, x, y)
     end
 
-       redef fun blit_rotated( image, x, y, angle ) is extern  `{
+       redef fun blit_rotated(image, x, y, angle) do native_blit_rotated(image, x.to_f, y.to_f, angle)
+
+       private fun native_blit_rotated(image: Opengles1Image, x, y, angle: Float) `{
                GLfloat texture_coord[4][2] =
                {
                        {image->src_xo, image->src_yi},
@@ -359,12 +346,19 @@ class Opengles1Display
                glDisable(GL_TEXTURE_2D);
 
                if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
-                  LOGW ("error drawing: %i", mnit_opengles_error_code);
+                  PRINT_ERROR("error drawing: %i", mnit_opengles_error_code);
                }
        `}
 
        # 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  `{
+       redef fun blit_stretched(image, ax, ay, bx, by, cx, cy, dx, dy)
+       do
+               native_blit_stretched(image,
+                       ax.to_f, ay.to_f, bx.to_f, by.to_f,
+                       cx.to_f, cy.to_f, dx.to_f, dy.to_f)
+       end
+
+       private fun native_blit_stretched(image: I, ax, ay, bx, by, cx, cy, dx, dy: Float) `{
                GLfloat texture_coord[4][2] =
                {
                        {image->src_xo, image->src_yi},
@@ -407,7 +401,7 @@ class Opengles1Display
                glDisable(GL_TEXTURE_2D);
 
                if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
-                  LOGW ("error drawing: %i", mnit_opengles_error_code);
+                  PRINT_ERROR("error drawing: %i", mnit_opengles_error_code);
                }
        `}
 
@@ -420,9 +414,17 @@ class Opengles1Display
                glClearColor( r, g, b, a );
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        `}
+
+       # Set the current color applied to all drawing
+       #
+       # require: r, g, b, a in [0.0 .. 1.0]
+       fun color(r, g, b, a: Float) `{ glColor4f(r, g, b, a); `}
+
+       # Reset the current color to opaque white
+       fun reset_color `{ glColor4f(1.0f, 1.0f, 1.0f, 1.0f); `}
 end
 
-extern Opengles1Image in "C" `{struct mnit_opengles_Texture *`}
+extern class Opengles1Image in "C" `{struct mnit_opengles_Texture *`}
        super Image
 
     redef fun destroy is extern `{ free( recv ); `}
@@ -456,109 +458,13 @@ extern Opengles1Image in "C" `{struct mnit_opengles_Texture *`}
                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)x+w)/recv->width;
-               image->src_yi = ((float)y+h)/recv->height;
+               float r_dx = recv->src_xi - recv->src_xo;
+               float r_dy = recv->src_yi - recv->src_yo;
+               image->src_xo = recv->src_xo + ((float)x)/recv->width*r_dx;
+               image->src_yo = recv->src_yo + ((float)y)/recv->height*r_dy;
+               image->src_xi = recv->src_xo + ((float)x+w)/recv->width*r_dx;
+               image->src_yi = recv->src_yo + ((float)y+h)/recv->height*r_dy;
 
                return Opengles1Image_as_Image( image );
     `}
 end
-
-# FIXME this class is broken
-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) );
-
-               /* 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;
-
-               if (glGetError() != GL_NO_ERROR) LOGW( "gl error");
-
-               return image;
-       `}
-
-    fun set_as_target is extern `{
-               LOGI( "sat %i", recv->fbo );
-               glBindFramebufferOES(GL_FRAMEBUFFER_OES, recv->fbo);
-               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
-