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