lib/mnit: use PRINT_ERROR instead of printf on portable code
[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", "egl")
19
20 import mnit_display
21
22 in "C header" `{
23 #include <EGL/egl.h>
24 #include <GLES/gl.h>
25
26 EGLDisplay mnit_display;
27 EGLSurface mnit_surface;
28 EGLContext mnit_context;
29 EGLConfig mnit_config;
30 int32_t mnit_width;
31 int32_t mnit_height;
32
33 struct mnit_opengles_Texture {
34 GLuint texture;
35
36 /* offsets on source texture */
37 float src_xo, src_yo, src_xi, src_yi;
38
39 /* destination width and height */
40 int width, height;
41
42 /* may vary depending on scaling */
43 int center_x, center_y;
44
45 float scale;
46 int blended;
47 };
48
49 struct mnit_opengles_DrawableTexture {
50 struct mnit_opengles_Texture super;
51 GLuint fbo;
52 GLuint depth;
53 GLuint color;
54 };
55
56 GLenum mnit_opengles_error_code;
57
58 struct mnit_opengles_Texture *mnit_opengles_load_image( const uint_least32_t *pixels, int width, int height, int has_alpha );
59 `}
60
61 in "C" `{
62 extern NativeWindowType mnit_window;
63 extern EGLNativeDisplayType mnit_native_display;
64
65 GLfloat mnit_opengles_vertices[6][3] =
66 {
67 {0.0f, 1.0f, 0.0f},
68 {1.0f, 1.0f, 0.0f},
69 {0.0f, 0.0f, 0.0f},
70 {1.0f, 0.0f, 0.0f},
71 };
72 GLfloat mnit_opengles_texture[6][2] =
73 {
74 {0.0f, 0.0f},
75 {0.0f, 1.0f},
76 {1.0f, 1.0f},
77 {0.0f, 0.0f},
78 {1.0f, 1.0f},
79 {1.0f, 0.0f}
80 };
81
82 struct mnit_opengles_Texture *mnit_opengles_load_image( const uint_least32_t *pixels, int width, int height, int has_alpha )
83 {
84 struct mnit_opengles_Texture *image = malloc(sizeof(struct mnit_opengles_Texture));
85 int format = has_alpha? GL_RGBA: GL_RGB;
86
87 image->width = width;
88 image->height = height;
89 image->center_x = width/2;
90 image->center_y = height/2;
91 image->scale = 1.0f;
92 image->blended = has_alpha;
93
94 image->src_xo = 0;
95 image->src_yo = 0;
96 image->src_xi = 1.0;
97 image->src_yi = 1.0;
98
99 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
100 PRINT_ERROR("error loading image after malloc: %i", mnit_opengles_error_code);
101 }
102
103 glGenTextures(1, &image->texture);
104
105 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
106 PRINT_ERROR("error loading image after glGenTextures: %i", mnit_opengles_error_code);
107 }
108
109 glBindTexture(GL_TEXTURE_2D, image->texture);
110
111 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
112 PRINT_ERROR("error loading image glBindTexture: %i", mnit_opengles_error_code);
113 }
114
115 glTexImage2D( GL_TEXTURE_2D, 0, format, width, height,
116 0, format, GL_UNSIGNED_BYTE, (GLvoid*)pixels);
117
118 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
119 PRINT_ERROR("error loading image after glTexImage2D: %i", mnit_opengles_error_code);
120 }
121
122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
123
124 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
125 PRINT_ERROR("error loading image after gtTexParameter: %i", mnit_opengles_error_code);
126 }
127
128 return image;
129 }
130 `}
131
132 # OpenGL ES1 display
133 # Uses 3d hardware optimization
134 class Opengles1Display
135 super Display
136
137 redef type I: Opengles1Image
138
139 init do extern_init
140 fun midway_init( format: Int ) do end
141 fun extern_init: Bool is extern import midway_init `{
142 /* initialize OpenGL ES and EGL */
143 const EGLint attribs[] = {
144 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
145 EGL_BLUE_SIZE, 8,
146 EGL_GREEN_SIZE, 8,
147 EGL_RED_SIZE, 8,
148 EGL_NONE
149 };
150 EGLint w, h, dummy, format;
151 EGLint numConfigs;
152 EGLConfig config;
153 EGLSurface surface;
154 EGLContext context;
155
156 EGLDisplay display = eglGetDisplay(mnit_native_display);
157 if ( display == EGL_NO_DISPLAY) {
158 PRINT_ERROR("Unable to eglGetDisplay");
159 return -1;
160 }
161
162 if ( eglInitialize(display, 0, 0) == EGL_FALSE) {
163 PRINT_ERROR("Unable to eglInitialize");
164 return -1;
165 }
166
167 if ( eglChooseConfig(display, attribs, &config, 1, &numConfigs) == EGL_FALSE) {
168 PRINT_ERROR("Unable to eglChooseConfig");
169 return -1;
170 }
171
172 if ( numConfigs == 0 ) {
173 PRINT_ERROR("No configs available for egl");
174 return -1;
175 }
176
177 if ( eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format) == EGL_FALSE) {
178 PRINT_ERROR("Unable to eglGetConfigAttrib");
179 return -1;
180 }
181
182 /* Used by Android to set buffer geometry */
183 Opengles1Display_midway_init(recv, format);
184
185 surface = eglCreateWindowSurface(display, config, mnit_window, NULL);
186 context = eglCreateContext(display, config, NULL, NULL);
187
188 if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
189 PRINT_ERROR("Unable to eglMakeCurrent");
190 return -1;
191 }
192
193 eglQuerySurface(display, surface, EGL_WIDTH, &w);
194 eglQuerySurface(display, surface, EGL_HEIGHT, &h);
195
196 mnit_display = display;
197 mnit_context = context;
198 mnit_surface = surface;
199 mnit_config = config;
200 mnit_width = w;
201 mnit_height = h;
202
203 glViewport(0, 0, mnit_width, mnit_height);
204 glMatrixMode(GL_PROJECTION);
205 glLoadIdentity();
206 glOrthof(0.0f, w, h, 0.0f, 0.0f, 1.0f);
207 glMatrixMode(GL_MODELVIEW);
208
209 glFrontFace( GL_CW );
210
211 return 0;
212 `}
213
214 fun close is extern `{
215 if ( mnit_display != EGL_NO_DISPLAY) {
216 eglMakeCurrent( mnit_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
217 if ( mnit_context != EGL_NO_CONTEXT) {
218 eglDestroyContext( mnit_display, mnit_context );
219 }
220 if ( mnit_surface != EGL_NO_SURFACE) {
221 eglDestroySurface( mnit_display, mnit_surface );
222 }
223 eglTerminate( mnit_display);
224 }
225 mnit_display = EGL_NO_DISPLAY;
226 mnit_context = EGL_NO_CONTEXT;
227 mnit_surface = EGL_NO_SURFACE;
228 `}
229
230 redef fun begin is extern `{
231 glClear(GL_COLOR_BUFFER_BIT);
232 glLoadIdentity();
233 `}
234
235 redef fun width: Int is extern `{
236 return mnit_width;
237 `}
238 redef fun height: Int is extern `{
239 return mnit_height;
240 `}
241
242 redef fun finish is extern `{
243 eglSwapBuffers( mnit_display, mnit_surface );
244 `}
245
246 redef fun set_viewport( x, y, w, h ) is extern `{
247 glLoadIdentity();
248 glViewport(0,0, mnit_width, mnit_height );
249 glMatrixMode(GL_PROJECTION);
250 glLoadIdentity();
251 glOrthof(x, x+w, y+h, y, 0.0f, 1.0f);
252 glMatrixMode(GL_MODELVIEW);
253 glFrontFace( GL_CW );
254 `}
255
256 redef fun blit(image, x, y) do native_blit(image, x.to_f, y.to_f)
257
258 private fun native_blit(image: Opengles1Image, x, y: Float) `{
259 GLfloat texture_coord[4][2] =
260 {
261 {image->src_xo, image->src_yi},
262 {image->src_xi, image->src_yi},
263 {image->src_xo, image->src_yo},
264 {image->src_xi, image->src_yo}
265 };
266
267 glLoadIdentity();
268
269 glBindTexture(GL_TEXTURE_2D, image->texture);
270
271 glEnableClientState(GL_VERTEX_ARRAY);
272 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
273 glTranslatef( x, y, 0.0f );
274 glScalef( image->width*image->scale, image->height*image->scale, 1.0f );
275
276 if ( image->blended ) {
277 glEnable(GL_BLEND);
278 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
279 }
280
281 glEnable(GL_TEXTURE_2D);
282 glDisable(GL_DEPTH_TEST);
283
284 glVertexPointer(3, GL_FLOAT, 0, mnit_opengles_vertices);
285 glTexCoordPointer(2, GL_FLOAT, 0, texture_coord );
286
287 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
288
289 glDisableClientState(GL_VERTEX_ARRAY);
290 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
291 if ( image->blended ) glDisable(GL_BLEND);
292 glDisable(GL_TEXTURE_2D);
293
294 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
295 PRINT_ERROR("error drawing: %i", mnit_opengles_error_code);
296 }
297 `}
298
299 redef fun blit_centered(img, x, y)
300 do
301 x = x.sub(img.center_x)
302 y = y.sub(img.center_y)
303 blit(img, x, y)
304 end
305
306 redef fun blit_rotated(image, x, y, angle) do native_blit_rotated(image, x.to_f, y.to_f, angle)
307
308 private fun native_blit_rotated(image: Opengles1Image, x, y, angle: Float) `{
309 GLfloat texture_coord[4][2] =
310 {
311 {image->src_xo, image->src_yi},
312 {image->src_xi, image->src_yi},
313 {image->src_xo, image->src_yo},
314 {image->src_xi, image->src_yo}
315 };
316
317 glLoadIdentity();
318
319 glBindTexture(GL_TEXTURE_2D, image->texture);
320
321 glEnableClientState(GL_VERTEX_ARRAY);
322 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
323 glTranslatef( x, y, 0.0f );
324 glRotatef( angle*180.0f/3.14156f, 0, 0, 1.0f );
325 glTranslatef( image->width*image->scale/-2, image->height*image->scale/-2, 0.0f );
326 glScalef( image->width*image->scale, image->height*image->scale, 1.0f );
327 if ( image->blended ) {
328 glEnable(GL_BLEND);
329 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
330 }
331 glEnable(GL_TEXTURE_2D);
332 glDisable(GL_DEPTH_TEST);
333
334 glVertexPointer(3, GL_FLOAT, 0, mnit_opengles_vertices);
335 glTexCoordPointer(2, GL_FLOAT, 0, texture_coord );
336
337 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
338
339 glDisableClientState(GL_VERTEX_ARRAY);
340 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
341 if ( image->blended ) glDisable(GL_BLEND);
342 glDisable(GL_TEXTURE_2D);
343
344 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
345 PRINT_ERROR("error drawing: %i", mnit_opengles_error_code);
346 }
347 `}
348
349 # a = top left, b = bottom left, c = bottom right, d = top right
350 redef fun blit_stretched(image, ax, ay, bx, by, cx, cy, dx, dy)
351 do
352 native_blit_stretched(image,
353 ax.to_f, ay.to_f, bx.to_f, by.to_f,
354 cx.to_f, cy.to_f, dx.to_f, dy.to_f)
355 end
356
357 private fun native_blit_stretched(image: I, ax, ay, bx, by, cx, cy, dx, dy: Float) `{
358 GLfloat texture_coord[4][2] =
359 {
360 {image->src_xo, image->src_yi},
361 {image->src_xi, image->src_yi},
362 {image->src_xo, image->src_yo},
363 {image->src_xi, image->src_yo}
364 };
365
366 GLfloat mnit_opengles_vertices_stretched[6][3] =
367 {
368 {bx, by, 0.0f},
369 {cx, cy, 0.0f},
370 {ax, ay, 0.0f},
371 {dx, dy, 0.0f},
372 };
373
374 glLoadIdentity();
375
376 glBindTexture(GL_TEXTURE_2D, image->texture);
377
378 glEnableClientState(GL_VERTEX_ARRAY);
379 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
380
381 if ( image->blended ) {
382 glEnable(GL_BLEND);
383 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
384 }
385
386 glEnable(GL_TEXTURE_2D);
387 glDisable(GL_DEPTH_TEST);
388
389 glVertexPointer(3, GL_FLOAT, 0, mnit_opengles_vertices_stretched);
390 glTexCoordPointer(2, GL_FLOAT, 0, texture_coord );
391
392 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
393
394 glDisableClientState(GL_VERTEX_ARRAY);
395 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
396 if ( image->blended ) glDisable(GL_BLEND);
397 glDisable(GL_TEXTURE_2D);
398
399 if ((mnit_opengles_error_code = glGetError()) != GL_NO_ERROR) {
400 PRINT_ERROR("error drawing: %i", mnit_opengles_error_code);
401 }
402 `}
403
404 redef fun clear( r, g, b: Float ) is extern `{
405 glClearColor( r, g, b, 1.0 );
406 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
407 `}
408
409 fun clear_alpha( r, g, b, a: Float ) is extern `{
410 glClearColor( r, g, b, a );
411 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
412 `}
413
414 # Set the current color applied to all drawing
415 #
416 # require: r, g, b, a in [0.0 .. 1.0]
417 fun color(r, g, b, a: Float) `{ glColor4f(r, g, b, a); `}
418
419 # Reset the current color to opaque white
420 fun reset_color `{ glColor4f(1.0f, 1.0f, 1.0f, 1.0f); `}
421 end
422
423 extern class Opengles1Image in "C" `{struct mnit_opengles_Texture *`}
424 super Image
425
426 redef fun destroy is extern `{ free( recv ); `}
427
428 redef fun width: Int is extern `{ return recv->width; `}
429 redef fun height: Int is extern `{ return recv->height; `}
430
431 fun center_x: Int `{ return recv->center_x; `}
432 fun center_y: Int `{ return recv->center_y; `}
433
434 redef fun scale=( v: Float ) is extern `{
435 recv->scale = v;
436 recv->center_x = v*recv->width/2;
437 recv->center_y = v*recv->height/2;
438 `}
439 redef fun scale: Float is extern `{ return recv->scale; `}
440
441 redef fun blended=( v: Bool ) is extern `{ recv->blended = v; `}
442 redef fun blended: Bool is extern `{ return recv->blended; `}
443
444 # inherits scale and blend from source
445 redef fun subimage( x, y, w, h: Int ): Image is extern import Opengles1Image.as( Image ) `{
446 struct mnit_opengles_Texture* image =
447 malloc( sizeof( struct mnit_opengles_Texture ) );
448
449 image->texture = recv->texture;
450 image->width = w;
451 image->height = h;
452 image->center_x = recv->scale*w/2;
453 image->center_y = recv->scale*h/2;
454 image->scale = recv->scale;
455 image->blended = recv->blended;
456
457 image->src_xo = ((float)x)/recv->width;
458 image->src_yo = ((float)y)/recv->height;
459 image->src_xi = ((float)x+w)/recv->width;
460 image->src_yi = ((float)y+h)/recv->height;
461
462 return Opengles1Image_as_Image( image );
463 `}
464 end