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