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