13ff8365a28677ec3e2263c4084874505690ffb9
[nit.git] / lib / mnit / opengles1.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2011-2013 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # OpenGL ES1 general support (most of it)
18 module opengles1
19
20 import display
21
22 in "C header" `{
23 #include <EGL/egl.h>
24 #include <GLES/gl.h>
25 #define GL_GLEXT_PROTOTYPES 1
26 #include <GLES/glext.h>
27 #include <errno.h>
28
29 #define LOGW(...) ((void)fprintf(stderr, "# warn: %s", __VA_ARGS__))
30 #ifdef DEBUG
31 #define LOGI(...) ((void)fprintf(stderr, "# info: %s", __VA_ARGS__))
32 #else
33 #define LOGI(...) (void)0
34 #endif
35
36 EGLDisplay mnit_display;
37 EGLSurface mnit_surface;
38 EGLContext mnit_context;
39 EGLConfig mnit_config;
40 int32_t mnit_width;
41 int32_t mnit_height;
42 float mnit_zoom;
43
44 struct mnit_opengles_Texture {
45 GLuint texture;
46
47 /* offsets on source texture */
48 float src_xo, src_yo, src_xi, src_yi;
49
50 /* destination width and height */
51 int width, height;
52
53 /* may vary depending on scaling */
54 int center_x, center_y;
55
56 float scale;
57 int blended;
58 };
59
60 struct mnit_opengles_DrawableTexture {
61 struct mnit_opengles_Texture super;
62 GLuint fbo;
63 GLuint depth;
64 GLuint color;
65 };
66
67 GLenum mnit_opengles_error_code;
68
69 struct mnit_opengles_Texture *mnit_opengles_load_image( const uint_least32_t *pixels, int width, int height, int has_alpha );
70 `}
71
72 in "C" `{
73 extern NativeWindowType mnit_window;
74 extern EGLNativeDisplayType mnit_native_display;
75
76 GLfloat mnit_opengles_vertices[6][3] =
77 {
78 {0.0f, 0.0f, 0.0f},
79 {0.0f, 1.0f, 0.0f},
80 {1.0f, 1.0f, 0.0f},
81 {0.0f, 0.0f, 0.0f},
82 {1.0f, 1.0f, 0.0f},
83 {1.0f, 0.0f, 0.0f},
84 };
85 GLfloat mnit_opengles_texture[6][2] =
86 {
87 {0.0f, 0.0f},
88 {0.0f, 1.0f},
89 {1.0f, 1.0f},
90 {0.0f, 0.0f},
91 {1.0f, 1.0f},
92 {1.0f, 0.0f}
93 };
94
95 struct mnit_opengles_Texture *mnit_opengles_load_image( const uint_least32_t *pixels, int width, int height, int has_alpha )
96 {
97 struct mnit_opengles_Texture *image = malloc(sizeof(struct mnit_opengles_Texture));
98 int format = has_alpha? GL_RGBA: GL_RGB;
99
100 image->width = width;
101 image->height = height;
102 image->center_x = width/2;
103 image->center_y = height/2;
104 image->scale = 1.0f;
105 image->blended = has_alpha;
106
107 image->src_xo = 0;
108 image->src_yo = 0;
109 image->src_xi = 1.0;
110 image->src_yi = 1.0;
111
112
113 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
114 LOGW ("a error loading image: %i\n", mnit_opengles_error_code);
115 printf( "%i\n", mnit_opengles_error_code );
116 }
117 glGenTextures(1, &image->texture);
118
119 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
120 LOGW ("b error loading image: %i\n", mnit_opengles_error_code);
121 printf( "%i\n", mnit_opengles_error_code );
122 }
123 glBindTexture(GL_TEXTURE_2D, image->texture);
124
125 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
126 LOGW ("c error loading image: %i\n", mnit_opengles_error_code);
127 printf( "%i\n", mnit_opengles_error_code );
128 }
129 glTexImage2D( GL_TEXTURE_2D, 0, format, width, height,
130 0, format, GL_UNSIGNED_BYTE, (GLvoid*)pixels);
131
132 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
133 LOGW ("d error loading image: %i\n", mnit_opengles_error_code);
134 printf( "%i\n", mnit_opengles_error_code );
135 }
136 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
137
138 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
139 LOGW ("e error loading image: %i\n", mnit_opengles_error_code);
140 printf( "%i\n", mnit_opengles_error_code );
141 }
142
143 return image;
144 }
145 `}
146
147 # OpenGL ES1 display
148 # Uses 3d hardware optimization
149 class Opengles1Display
150 super Display
151
152 redef type I: Opengles1Image
153
154 init do extern_init
155 fun midway_init( format: Int ) do end
156 fun extern_init: Bool is extern import midway_init `{
157 /* initialize OpenGL ES and EGL */
158 const EGLint attribs[] = {
159 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
160 EGL_BLUE_SIZE, 8,
161 EGL_GREEN_SIZE, 8,
162 EGL_RED_SIZE, 8,
163 EGL_NONE
164 };
165 EGLint w, h, dummy, format;
166 EGLint numConfigs;
167 EGLConfig config;
168 EGLSurface surface;
169 EGLContext context;
170
171 EGLDisplay display = eglGetDisplay(mnit_native_display);
172 if ( display == EGL_NO_DISPLAY) {
173 LOGW("Unable to eglGetDisplay");
174 return -1;
175 }
176
177 if ( eglInitialize(display, 0, 0) == EGL_FALSE) {
178 LOGW("Unable to eglInitialize");
179 return -1;
180 }
181
182 if ( eglChooseConfig(display, attribs, &config, 1, &numConfigs) == EGL_FALSE) {
183 LOGW("Unable to eglChooseConfig");
184 return -1;
185 }
186
187 if ( numConfigs == 0 ) {
188 LOGW("No configs available for egl");
189 return -1;
190 }
191
192 if ( eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format) == EGL_FALSE) {
193 LOGW("Unable to eglGetConfigAttrib");
194 return -1;
195 }
196
197 /* Used by Android to set buffer geometry */
198 Opengles1Display_midway_init(recv, format);
199
200 surface = eglCreateWindowSurface(display, config, mnit_window, NULL);
201 context = eglCreateContext(display, config, NULL, NULL);
202
203 if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
204 LOGW("Unable to eglMakeCurrent");
205 return -1;
206 }
207
208 eglQuerySurface(display, surface, EGL_WIDTH, &w);
209 eglQuerySurface(display, surface, EGL_HEIGHT, &h);
210
211 mnit_display = display;
212 mnit_context = context;
213 mnit_surface = surface;
214 mnit_config = config;
215 mnit_width = w;
216 mnit_height = h;
217 mnit_zoom = 1.0f;
218
219 LOGI( "surface: %i, display: %i, w %i, h %i", (int)surface, (int)display, w, h );
220
221 glViewport(0, 0, mnit_width, mnit_height);
222 glMatrixMode(GL_PROJECTION);
223 glLoadIdentity();
224 glOrthof(0.0f, w, h, 0.0f, 0.0f, 1.0f);
225 glMatrixMode(GL_MODELVIEW);
226
227 glFrontFace( GL_CW );
228
229 return 0;
230 `}
231
232 fun close is extern `{
233 if ( mnit_display != EGL_NO_DISPLAY) {
234 eglMakeCurrent( mnit_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
235 if ( mnit_context != EGL_NO_CONTEXT) {
236 eglDestroyContext( mnit_display, mnit_context );
237 }
238 if ( mnit_surface != EGL_NO_SURFACE) {
239 eglDestroySurface( mnit_display, mnit_surface );
240 }
241 eglTerminate( mnit_display);
242 }
243 mnit_display = EGL_NO_DISPLAY;
244 mnit_context = EGL_NO_CONTEXT;
245 mnit_surface = EGL_NO_SURFACE;
246 `}
247
248 redef fun begin is extern `{
249 glClear(GL_COLOR_BUFFER_BIT);
250 glLoadIdentity();
251 `}
252
253 redef fun width: Int is extern `{
254 return mnit_width;
255 `}
256 redef fun height: Int is extern `{
257 return mnit_height;
258 `}
259
260 redef fun finish is extern `{
261 eglSwapBuffers( mnit_display, mnit_surface );
262 `}
263
264 fun set_as_target is extern `{
265 glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
266 `}
267
268 redef fun set_viewport( x, y, w, h ) is extern `{
269 glLoadIdentity();
270 glViewport(0,0, mnit_width, mnit_height );
271 glMatrixMode(GL_PROJECTION);
272 glLoadIdentity();
273 glOrthof(x, x+w, y+h, y, 0.0f, 1.0f);
274 mnit_zoom = ((float)w)/mnit_width;
275 glMatrixMode(GL_MODELVIEW);
276 glFrontFace( GL_CW );
277 `}
278
279 redef fun blit( image, x, y ) is extern `{
280 GLfloat texture_coord[6][2] =
281 {
282 {image->src_xo, image->src_yo},
283 {image->src_xo, image->src_yi},
284 {image->src_xi, image->src_yi},
285 {image->src_xo, image->src_yo},
286 {image->src_xi, image->src_yi},
287 {image->src_xi, image->src_yo}
288 };
289
290 glLoadIdentity();
291
292 glBindTexture(GL_TEXTURE_2D, image->texture);
293
294 glEnableClientState(GL_VERTEX_ARRAY);
295 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
296 glTranslatef( x, y, 0.0f );
297 glScalef( image->width*image->scale, image->height*image->scale, 1.0f );
298
299 if ( image->blended ) {
300 glEnable(GL_BLEND);
301 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
302 }
303
304 glEnable(GL_TEXTURE_2D);
305 glDisable(GL_DEPTH_TEST);
306
307 glVertexPointer(3, GL_FLOAT, 0, mnit_opengles_vertices);
308 glTexCoordPointer(2, GL_FLOAT, 0, texture_coord ); /* mnit_opengles_texture); */
309
310 glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
311
312 glDisableClientState(GL_VERTEX_ARRAY);
313 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
314 if ( image->blended ) glDisable(GL_BLEND);
315 glDisable(GL_TEXTURE_2D);
316
317 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
318 LOGW ("error drawing: %i", mnit_opengles_error_code);
319 }
320 `}
321
322 redef fun blit_centered( img, x, y )
323 do
324 x = x - img.center_x
325 y = y - img.center_y
326 blit( img, x, y )
327 end
328
329 redef fun blit_rotated( image, x, y, angle ) is extern `{
330 GLfloat texture_coord[6][2] =
331 {
332 {image->src_xo, image->src_yo},
333 {image->src_xo, image->src_yi},
334 {image->src_xi, image->src_yi},
335 {image->src_xo, image->src_yo},
336 {image->src_xi, image->src_yi},
337 {image->src_xi, image->src_yo}
338 };
339
340 glLoadIdentity();
341
342 glBindTexture(GL_TEXTURE_2D, image->texture);
343
344 glEnableClientState(GL_VERTEX_ARRAY);
345 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
346 glTranslatef( x, y, 0.0f );
347 glRotatef( angle*180.0f/3.14156f, 0, 0, 1.0f );
348 glTranslatef( image->width*image->scale/-2, image->height*image->scale/-2, 0.0f );
349 glScalef( image->width*image->scale, image->height*image->scale, 1.0f );
350 if ( image->blended ) {
351 glEnable(GL_BLEND);
352 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
353 }
354 glEnable(GL_TEXTURE_2D);
355 glDisable(GL_DEPTH_TEST);
356
357 glVertexPointer(3, GL_FLOAT, 0, mnit_opengles_vertices);
358 glTexCoordPointer(2, GL_FLOAT, 0, texture_coord );
359
360 glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
361
362 glDisableClientState(GL_VERTEX_ARRAY);
363 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
364 if ( image->blended ) glDisable(GL_BLEND);
365 glDisable(GL_TEXTURE_2D);
366
367 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
368 LOGW ("error drawing: %i", mnit_opengles_error_code);
369 }
370 `}
371
372 # a = top left, b = bottom left, c = bottom right, d = top right
373 redef fun blit_stretched( image, ax, ay, bx, by, cx, cy, dx, dy ) is extern `{
374 GLfloat texture_coord[4][2] =
375 {
376 {image->src_xo, image->src_yi},
377 {image->src_xi, image->src_yi},
378 {image->src_xo, image->src_yo},
379 {image->src_xi, image->src_yo}
380 };
381
382 GLfloat mnit_opengles_vertices_stretched[6][3] =
383 {
384 {bx, by, 0.0f},
385 {cx, cy, 0.0f},
386 {ax, ay, 0.0f},
387 {dx, dy, 0.0f},
388 };
389
390 glLoadIdentity();
391
392 glBindTexture(GL_TEXTURE_2D, image->texture);
393
394 glEnableClientState(GL_VERTEX_ARRAY);
395 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
396
397 if ( image->blended ) {
398 glEnable(GL_BLEND);
399 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
400 }
401
402 glEnable(GL_TEXTURE_2D);
403 glDisable(GL_DEPTH_TEST);
404
405 glVertexPointer(3, GL_FLOAT, 0, mnit_opengles_vertices_stretched);
406 glTexCoordPointer(2, GL_FLOAT, 0, texture_coord );
407
408 glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
409
410 glDisableClientState(GL_VERTEX_ARRAY);
411 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
412 if ( image->blended ) glDisable(GL_BLEND);
413 glDisable(GL_TEXTURE_2D);
414
415 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
416 LOGW ("error drawing: %i", mnit_opengles_error_code);
417 }
418 `}
419
420 redef fun clear( r, g, b: Float ) is extern `{
421 glClearColor( r, g, b, 1.0 );
422 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
423 `}
424
425 fun clear_alpha( r, g, b, a: Float ) is extern `{
426 glClearColor( r, g, b, a );
427 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
428 `}
429 end
430
431 extern Opengles1Image in "C" `{struct mnit_opengles_Texture *`}
432 super Image
433
434 redef fun destroy is extern `{ free( recv ); `}
435
436 redef fun width: Int is extern `{ return recv->width; `}
437 redef fun height: Int is extern `{ return recv->height; `}
438
439 fun center_x: Int `{ return recv->center_x; `}
440 fun center_y: Int `{ return recv->center_y; `}
441
442 redef fun scale=( v: Float ) is extern `{
443 recv->scale = v;
444 recv->center_x = v*recv->width/2;
445 recv->center_y = v*recv->height/2;
446 `}
447 redef fun scale: Float is extern `{ return recv->scale; `}
448
449 redef fun blended=( v: Bool ) is extern `{ recv->blended = v; `}
450 redef fun blended: Bool is extern `{ return recv->blended; `}
451
452 # inherits scale and blend from source
453 redef fun subimage( x, y, w, h: Int ): Image is extern import Opengles1Image.as( Image ) `{
454 struct mnit_opengles_Texture* image =
455 malloc( sizeof( struct mnit_opengles_Texture ) );
456
457 image->texture = recv->texture;
458 image->width = w;
459 image->height = h;
460 image->center_x = recv->scale*w/2;
461 image->center_y = recv->scale*h/2;
462 image->scale = recv->scale;
463 image->blended = recv->blended;
464
465 image->src_xo = ((float)x)/recv->width;
466 image->src_yo = ((float)y)/recv->height;
467 image->src_xi = ((float)w+w)/recv->width;
468 image->src_yi = ((float)x+h)/recv->height;
469
470 return Opengles1Image_as_Image( image );
471 `}
472 end
473
474 # FIXME this class is broken
475 extern Opengles1DrawableImage in "C" `{struct mnit_opengles_DrawableTexture*`}
476 super DrawableImage
477 new ( w, h: Int ) is extern `{
478 struct mnit_opengles_DrawableTexture *image =
479 malloc( sizeof(struct mnit_opengles_DrawableTexture) );
480
481 /* texture */
482 glGenTextures(1, &image->super.texture);
483 glBindTexture(GL_TEXTURE_2D, image->super.texture);
484 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
485 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
486 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
487 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
488 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
489 /* glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap generation included in OpenGL v1.4c */
490 glBindTexture(GL_TEXTURE_2D, 0);
491
492 /* fbo */
493 glGenFramebuffersOES( 1, &image->fbo );
494 glBindFramebufferOES( GL_FRAMEBUFFER_OES, image->fbo );
495 glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
496 GL_COLOR_ATTACHMENT0_OES,
497 GL_TEXTURE_2D,
498 image->super.texture,
499 0 );
500
501 /* depth */
502 glGenRenderbuffersOES(1, &image->depth);
503 glBindRenderbufferOES(GL_RENDERBUFFER_OES, image->depth);
504 glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES,
505 w, h);
506 glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);
507 glFramebufferRenderbufferOES( GL_FRAMEBUFFER_OES,
508 GL_DEPTH_ATTACHMENT_OES,
509 GL_RENDERBUFFER_OES,
510 image->depth );
511
512 /* tex framebuffer */
513 glGenRenderbuffersOES(1, &image->color);
514 glBindRenderbufferOES(GL_RENDERBUFFER_OES, image->color);
515 glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, w, h);
516 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, image->color );
517
518 if ( glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) != GL_FRAMEBUFFER_COMPLETE_OES )
519 {
520 LOGW( "framebuffer not set" );
521 if ( glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES )
522 LOGW( "framebuffer not set a" );
523 else if ( glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) == GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES )
524 LOGW( "framebuffer not set b" );
525 else if ( glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES )
526 LOGW( "framebuffer not set c" );
527 else if ( glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES )
528 LOGW( "framebuffer not set d" );
529 }
530
531 image->super.width = w;
532 image->super.height = h;
533 image->super.center_x = w/2;
534 image->super.center_y = h/2;
535 image->super.scale = 1.0f;
536 image->super.blended = 0;
537
538 if (glGetError() != GL_NO_ERROR) LOGW( "gl error");
539
540 return image;
541 `}
542
543 fun set_as_target is extern `{
544 LOGI( "sat %i", recv->fbo );
545 glBindFramebufferOES(GL_FRAMEBUFFER_OES, recv->fbo);
546 if (glGetError() != GL_NO_ERROR) LOGW( "gl error 0");
547 /*glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES,&recv->fbo);
548 if (glGetError() != GL_NO_ERROR) LOGW( "gl error a");*/
549 glViewport(0, 0, recv->super.width, recv->super.height);
550
551 glMatrixMode(GL_PROJECTION);
552 glLoadIdentity();
553 glOrthof(0.0f, recv->super.width, recv->super.height, 0.0f, 0.0f, 1.0f);
554 glMatrixMode(GL_MODELVIEW);
555 glFrontFace( GL_CW );
556
557 glClearColor( 0.0f, 1.0f, 1.0f, 1.0f );
558 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
559 `}
560
561 fun unset_as_target is extern `{
562 glFlush();
563 /*glBindTexture(GL_TEXTURE_2D, recv->super.texture);
564 glGenerateMipmapOES(GL_TEXTURE_2D);
565 glBindTexture(GL_TEXTURE_2D, 0);*/
566 glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
567 if (glGetError() != GL_NO_ERROR) LOGW( "gl error");
568 `}
569 end
570