1 #include "gl.h"
2
3 #include "freetype.h"
4 #include "main.h"
5
6 #include "../native/ui.h"
7
8 #include "../debug.h"
9 #include "../macros.h"
10 #include "../settings.h"
11 #include "../text.h"
12
13 #include "../ui.h"
14 #include "../ui/svg.h"
15
16 #include "../main.h" // stbi
17
18 const char vertex_shader[] = "uniform vec4 matrix;"
19 "attribute vec2 pos;"
20 "attribute vec2 tex;"
21 "varying vec2 x;"
22 "void main(){"
23 "x = tex / 32768.0;"
24 "gl_Position = vec4((pos + matrix.xy) * matrix.zw, 0.0, 1.0);"
25 "}",
26 fragment_shader[] =
27 #ifndef NO_OPENGL_ES
28 "precision mediump float;"
29 #endif
30 "uniform sampler2D samp;"
31 "uniform vec3 k;"
32 "uniform vec3 k2;"
33 "varying vec2 x;"
34 "void main(){"
35 "gl_FragColor = (texture2D(samp, x) + vec4(k2, 0.0)) * vec4(k, 1.0);"
36 "}";
37
38 static GLuint prog, white;
39 static GLint matrix, k, k2, samp;
40 static GLuint bitmap[BM_ENDMARKER];
41
42 static QUAD2D quads[64];
43
44 static EGLDisplay display;
45 static EGLSurface surface;
46 static EGLContext context;
47 static EGLConfig config;
48
49 #ifndef NO_OPENGL_ES
50 #define glDrawQuads(x, y) glDrawElements(GL_TRIANGLES, (y)*6, GL_UNSIGNED_BYTE, &quad_indices[(x)*6])
51 static uint8_t quad_indices[384];
52 #else
53 #define glDrawQuads(x, y) glDrawArrays(GL_QUADS, (x), 4 * (y))
54 #endif
55
makequad(QUAD2D * quad,int16_t x,int16_t y,int16_t right,int16_t bottom)56 static void makequad(QUAD2D *quad, int16_t x, int16_t y, int16_t right, int16_t bottom) {
57 quad->vertex[0].x = x;
58 quad->vertex[0].y = y;
59 quad->vertex[0].tx = 0;
60 quad->vertex[0].ty = 0;
61
62 quad->vertex[1].x = right;
63 quad->vertex[1].y = y;
64 quad->vertex[1].tx = 32768;
65 quad->vertex[1].ty = 0;
66
67 quad->vertex[2].x = right;
68 quad->vertex[2].y = bottom;
69 quad->vertex[2].tx = 32768;
70 quad->vertex[2].ty = 32768;
71
72 quad->vertex[3].x = x;
73 quad->vertex[3].y = bottom;
74 quad->vertex[3].tx = 0;
75 quad->vertex[3].ty = 32768;
76 }
77
makeline(QUAD2D * quad,int16_t x,int16_t y,int16_t x2,int16_t y2)78 static void makeline(QUAD2D *quad, int16_t x, int16_t y, int16_t x2, int16_t y2) {
79 quad->vertex[0].x = x;
80 quad->vertex[0].y = y;
81
82 quad->vertex[1].x = x2;
83 quad->vertex[1].y = y2;
84 }
85
86
makeglyph(QUAD2D * quad,int16_t x,int16_t y,uint16_t mx,uint16_t my,uint16_t width,uint16_t height)87 void makeglyph(QUAD2D *quad, int16_t x, int16_t y, uint16_t mx, uint16_t my, uint16_t width, uint16_t height) {
88 quad->vertex[0].x = x;
89 quad->vertex[0].y = y;
90 quad->vertex[0].tx = mx * 64;
91 quad->vertex[0].ty = my * 64;
92
93 quad->vertex[1].x = x + width;
94 quad->vertex[1].y = y;
95 quad->vertex[1].tx = (mx + width) * 64;
96 quad->vertex[1].ty = my * 64;
97
98 quad->vertex[2].x = x + width;
99 quad->vertex[2].y = y + height;
100 quad->vertex[2].tx = (mx + width) * 64;
101 quad->vertex[2].ty = (my + height) * 64;
102
103 quad->vertex[3].x = x;
104 quad->vertex[3].y = y + height;
105 quad->vertex[3].tx = mx * 64;
106 quad->vertex[3].ty = (my + height) * 64;
107 }
108
set_color(uint32_t a)109 static void set_color(uint32_t a) {
110 union {
111 uint32_t c;
112 struct {
113 uint8_t r, g, b, a;
114 };
115 } color;
116 color.c = a;
117 float c[] = { (float)color.r / 255.0, (float)color.g / 255.0, (float)color.b / 255.0 };
118
119 glUniform3fv(k, 1, c);
120 }
121
122 uint32_t colori;
123 float colorf[3];
124
setcolor(uint32_t a)125 uint32_t setcolor(uint32_t a) {
126 union {
127 uint32_t c;
128 struct {
129 uint8_t r, g, b, a;
130 };
131 } color;
132 color.c = a;
133
134 colorf[0] = (float)color.r / 255.0;
135 colorf[1] = (float)color.g / 255.0;
136 colorf[2] = (float)color.b / 255.0;
137
138 uint32_t s = colori;
139 colori = a;
140 return s;
141 }
142
drawrect(int x,int y,int right,int bottom,uint32_t color)143 void drawrect(int x, int y, int right, int bottom, uint32_t color) {
144 set_color(color);
145 glBindTexture(GL_TEXTURE_2D, white);
146 makequad(&quads[0], x, y, right, bottom);
147 glDrawQuads(0, 1);
148 }
149
draw_rect_fill(int x,int y,int width,int height,uint32_t color)150 void draw_rect_fill(int x, int y, int width, int height, uint32_t color) {
151 drawrect(x, y, x + width, y + height, color);
152 }
153
draw_rect_frame(int x,int y,int width,int height,uint32_t color)154 void draw_rect_frame(int x, int y, int width, int height, uint32_t color) {
155 set_color(color);
156 glBindTexture(GL_TEXTURE_2D, white);
157 makequad(&quads[0], x, y, x + width, y + height);
158 glDrawArrays(GL_LINE_LOOP, 0, 4);
159 }
160
drawhline(int x,int y,int x2,uint32_t color)161 void drawhline(int x, int y, int x2, uint32_t color) {
162 set_color(color);
163 glBindTexture(GL_TEXTURE_2D, white);
164 makeline(&quads[0], x, y + 1, x2, y + 1);
165 glDrawArrays(GL_LINES, 0, 2);
166 }
167
drawvline(int x,int y,int y2,uint32_t color)168 void drawvline(int x, int y, int y2, uint32_t color) {
169 set_color(color);
170 glBindTexture(GL_TEXTURE_2D, white);
171 makeline(&quads[0], x + 1, y, x + 1, y2);
172 glDrawArrays(GL_LINES, 0, 2);
173 }
174
drawalpha(int bm,int x,int y,int width,int height,uint32_t color)175 void drawalpha(int bm, int x, int y, int width, int height, uint32_t color) {
176 set_color(color);
177 glBindTexture(GL_TEXTURE_2D, bitmap[bm]);
178 makequad(&quads[0], x, y, x + width, y + height);
179 glDrawQuads(0, 1);
180 }
181
loadalpha(int bm,void * data,int width,int height)182 void loadalpha(int bm, void *data, int width, int height) {
183 glBindTexture(GL_TEXTURE_2D, bitmap[bm]);
184 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
185 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
186 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data);
187 }
188
189 typedef struct {
190 int16_t x, y;
191 uint16_t width, height;
192 } RECT;
193
194 static RECT clip[16];
195 static int clipk;
196
pushclip(int left,int top,int w,int h)197 void pushclip(int left, int top, int w, int h) {
198 if (!clipk) {
199 glEnable(GL_SCISSOR_TEST);
200 }
201
202 RECT *r = &clip[clipk++];
203 r->x = left;
204 r->y = settings.window_height - (top + h);
205 r->width = w;
206 r->height = h;
207
208 glScissor(r->x, r->y, r->width, r->height);
209 }
210
popclip(void)211 void popclip(void) {
212 clipk--;
213 if (!clipk) {
214 glDisable(GL_SCISSOR_TEST);
215 return;
216 }
217
218 RECT *r = &clip[clipk - 1];
219
220 glScissor(r->x, r->y, r->width, r->height);
221 }
222
enddraw(int x,int y,int width,int height)223 void enddraw(int x, int y, int width, int height) {
224 LOG_TRACE("AndroidGL", "Going to swap buffers");
225 if (!eglSwapBuffers(display, surface)) {
226 LOG_ERR("AndroidGL", "OpenGL Swap errored! %d", eglGetError());
227 }
228 }
229
gl_init(void)230 bool gl_init(void) {
231 LOG_INFO("AndroidGL", "gl init\n");
232 GLuint vertshader, fragshader;
233 GLint status;
234 const GLchar *data;
235
236 vertshader = glCreateShader(GL_VERTEX_SHADER);
237 if (!vertshader) {
238 LOG_TRACE("gl", "glCreateShader() failed (vert)" );
239 return false;
240 }
241
242 data = vertex_shader;
243 glShaderSource(vertshader, 1, &data, NULL);
244 glCompileShader(vertshader);
245 glGetShaderiv(vertshader, GL_COMPILE_STATUS, &status);
246 if (!status) {
247 LOG_TRACE("gl", "glCompileShader() failed (vert):\n%s" , data);
248 GLint infologsize = 0;
249 glGetShaderiv(vertshader, GL_INFO_LOG_LENGTH, &infologsize);
250 if (infologsize) {
251 char *infolog = malloc(infologsize);
252 glGetShaderInfoLog(vertshader, infologsize, NULL, (GLbyte *)infolog);
253 LOG_TRACE("gl", "Infolog: %s" , infolog);
254 free(infolog);
255 }
256 return false;
257 }
258
259 fragshader = glCreateShader(GL_FRAGMENT_SHADER);
260 if (!fragshader) {
261 return false;
262 }
263
264 data = &fragment_shader[0];
265 glShaderSource(fragshader, 1, &data, NULL);
266 glCompileShader(fragshader);
267 glGetShaderiv(fragshader, GL_COMPILE_STATUS, &status);
268 if (!status) {
269 LOG_TRACE("gl", "glCompileShader failed (frag):\n%s" , data);
270 GLint infologsize = 0;
271 glGetShaderiv(fragshader, GL_INFO_LOG_LENGTH, &infologsize);
272 if (infologsize) {
273 char *infolog = malloc(infologsize);
274 glGetShaderInfoLog(fragshader, infologsize, NULL, (GLbyte *)infolog);
275 LOG_TRACE("gl", "Infolog: %s" , infolog);
276 free(infolog);
277 }
278 return false;
279 }
280
281 prog = glCreateProgram();
282 glAttachShader(prog, vertshader);
283 glAttachShader(prog, fragshader);
284 glBindAttribLocation(prog, 0, "pos");
285 glBindAttribLocation(prog, 1, "tex");
286
287 glLinkProgram(prog);
288 glGetProgramiv(prog, GL_LINK_STATUS, &status);
289 if (!status) {
290 LOG_TRACE("gl", "glLinkProgram failed" );
291 GLint infologsize = 0;
292 glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &infologsize);
293 if (infologsize) {
294 char *infolog = malloc(infologsize);
295 glGetShaderInfoLog(prog, infologsize, NULL, (GLbyte *)infolog);
296 LOG_TRACE("gl", "Infolog: %s" , infolog);
297 free(infolog);
298 }
299 return false;
300 }
301
302 glUseProgram(prog);
303
304 matrix = glGetUniformLocation(prog, "matrix");
305 k = glGetUniformLocation(prog, "k");
306 k2 = glGetUniformLocation(prog, "k2");
307 samp = glGetUniformLocation(prog, "samp");
308
309 LOG_TRACE("gl", "uniforms: %i %i %i" , matrix, k, samp);
310
311 GLint zero = 0;
312 float one[] = { 1.0, 1.0, 1.0 };
313 glUniform1iv(samp, 1, &zero);
314 glUniform3fv(k2, 1, one);
315
316 uint8_t wh = { 255 };
317 glGenTextures(1, &white);
318 glBindTexture(GL_TEXTURE_2D, white);
319 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
320 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
321 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 1, 1, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &wh);
322
323 //
324 glVertexAttribPointer(0, 2, GL_SHORT, GL_FALSE, sizeof(VERTEX2D), &quads[0]);
325 glVertexAttribPointer(1, 2, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(VERTEX2D), &quads[0].vertex[0].tx);
326 glEnableVertexAttribArray(0);
327 glEnableVertexAttribArray(1);
328
329 // Alpha blending
330 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
331 glEnable(GL_BLEND);
332
333 //
334 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
335
336 #ifndef NO_OPENGL_ES
337 uint8_t i = 0;
338 uint16_t ii = 0;
339 do {
340 quad_indices[ii] = i + 0;
341 quad_indices[ii + 1] = i + 1;
342 quad_indices[ii + 2] = i + 3;
343 quad_indices[ii + 3] = i + 3;
344 quad_indices[ii + 4] = i + 1;
345 quad_indices[ii + 5] = i + 2;
346 i += 4;
347 ii += 6;
348 } while (i);
349 #endif
350
351 glGenTextures(COUNTOF(bitmap), bitmap);
352
353 svg_draw(0);
354 loadfonts();
355
356 float vec[4];
357 vec[0] = -(float)settings.window_width / 2.0;
358 vec[1] = -(float)settings.window_height / 2.0;
359 vec[2] = 2.0 / (float)settings.window_width;
360 vec[3] = -2.0 / (float)settings.window_height;
361 glUniform4fv(matrix, 1, vec);
362
363 LOG_INFO("AndroidGL", "GL init ready w %u h %u", settings.window_width, settings.window_height);
364 ui_size(settings.window_width, settings.window_height);
365
366 glViewport(0, 0, settings.window_width, settings.window_height);
367
368 redraw();
369
370 return true;
371 }
372
373 /* gl initialization with EGL */
init_display(ANativeWindow * window)374 bool init_display(ANativeWindow *window) {
375 LOG_INFO("AndroidGL", "gl display init\n");
376 const EGLint attrib_list[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
377
378 const EGLint attribs[] = { EGL_SURFACE_TYPE,
379 EGL_WINDOW_BIT,
380 EGL_RENDERABLE_TYPE,
381 EGL_OPENGL_ES2_BIT,
382 EGL_BLUE_SIZE,
383 8,
384 EGL_GREEN_SIZE,
385 8,
386 EGL_RED_SIZE,
387 8,
388 EGL_ALPHA_SIZE,
389 8,
390 EGL_DEPTH_SIZE,
391 0,
392 EGL_NONE };
393
394 EGLint numConfigs;
395
396 display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
397 eglInitialize(display, NULL, NULL);
398 eglChooseConfig(display, attribs, &config, 1, &numConfigs);
399
400 EGLint format;
401 eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
402
403 ANativeWindow_setBuffersGeometry(window, 0, 0, format);
404 surface = eglCreateWindowSurface(display, config, window, NULL);
405 context = eglCreateContext(display, config, NULL, attrib_list);
406
407 if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
408 LOG_ERR("AndroidGL", "eglMakeCurrent failed!");
409 return false;
410 }
411
412 int32_t w, h;
413 eglQuerySurface(display, surface, EGL_WIDTH, &w);
414 eglQuerySurface(display, surface, EGL_HEIGHT, &h);
415
416 settings.window_width = w;
417 settings.window_height = h;
418
419 bool init = gl_init();
420 if (init == false) {
421 LOG_ERR("AndroidGL", "gl_init failed :<");
422 }
423
424 return init;
425 }
426
GL_draw_image(const NATIVE_IMAGE * data,int x,int y,uint32_t width,uint32_t height,uint32_t imgx,uint32_t imgy)427 void GL_draw_image(const NATIVE_IMAGE *data, int x, int y, uint32_t width, uint32_t height, uint32_t imgx, uint32_t imgy) {
428 GLuint texture = data->img;
429
430 makequad(&quads[0], x - imgx, y - imgy, x + width, y + height);
431
432 glBindTexture(GL_TEXTURE_2D, texture);
433
434 float one[] = { 1.0, 1.0, 1.0 };
435 float zero[] = { 0.0, 0.0, 0.0 };
436 glUniform3fv(k, 1, one);
437 glUniform3fv(k2, 1, zero);
438
439 glDrawQuads(0, 1);
440
441 glUniform3fv(k2, 1, one);
442 }
443
GL_utox_image_to_native(const uint8_t * data,size_t size,uint16_t * w,uint16_t * h,bool keep_alpha)444 NATIVE_IMAGE *GL_utox_image_to_native(const uint8_t *data, size_t size, uint16_t *w, uint16_t *h, bool keep_alpha) {
445 unsigned width, height, bpp;
446 uint8_t *out = stbi_load_from_memory(data, size, &width, &height, &bpp, 3);
447
448 if (out == NULL || width == 0 || height == 0) {
449 return 0;
450 }
451
452 *w = width;
453 *h = height;
454 GLuint texture = 0;
455 glGenTextures(1, &texture);
456 glBindTexture(GL_TEXTURE_2D, texture);
457 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
458 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
459 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, out);
460 free(out);
461
462 return texture;
463 }
464
465 // Returns 1 if redraw is needed
GL_utox_android_redraw_window()466 int GL_utox_android_redraw_window() {
467 LOG_DEBUG("AndroidGL", "Redraw window");
468 int32_t new_width, new_height;
469 eglQuerySurface(display, surface, EGL_WIDTH, &new_width);
470 eglQuerySurface(display, surface, EGL_HEIGHT, &new_height);
471
472 if (new_width != (int32_t)settings.window_width || new_height != (int32_t)settings.window_height) {
473 LOG_DEBUG("AndroidGL", "Redraw window new size");
474 settings.window_width = new_width;
475 settings.window_height = new_height;
476
477 float vec[4];
478 vec[0] = -(float)settings.window_width / 2.0;
479 vec[1] = -(float)settings.window_height / 2.0;
480 vec[2] = 2.0 / (float)settings.window_width;
481 vec[3] = -2.0 / (float)settings.window_height;
482 glUniform4fv(matrix, 1, vec);
483
484 ui_size(settings.window_width, settings.window_height);
485
486 glViewport(0, 0, settings.window_width, settings.window_height);
487
488 return 1;
489 }
490 return 0;
491 }
492
GL_raze_surface(void)493 void GL_raze_surface(void) {
494 // eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
495 eglDestroyContext(display, context);
496 eglDestroySurface(display, surface);
497 eglTerminate(display);
498 }
499
GL_drawtext(int x,int xmax,int y,char * str,uint16_t length)500 int GL_drawtext(int x, int xmax, int y, char *str, uint16_t length) {
501 glUniform3fv(k, 1, colorf);
502 glBindTexture(GL_TEXTURE_2D, sfont->texture);
503 int c = 0;
504
505 while (length > 0) {
506 uint32_t ch;
507 uint8_t len = utf8_len_read(str, &ch);
508 str += len;
509 length -= len;
510
511 GLYPH *g = font_getglyph(sfont, ch);
512 if (g) {
513 if (x + g->xadvance > xmax) {
514 x = -x;
515 break;
516 }
517
518 if (c == 64) {
519 glDrawQuads(0, 64);
520 c = 0;
521 }
522
523 makeglyph(&quads[c++], x + g->x, y + g->y, g->mx, g->my, g->width, g->height);
524
525 x += g->xadvance;
526 }
527 }
528
529 glDrawQuads(0, c);
530
531 return x;
532 }
533
534 #if 0
535 void drawimage(NATIVE_IMAGE data, int x, int y, int width, int height, int maxwidth, bool zoom, double position)
536 {
537 GLuint texture = data;
538
539 if(!zoom && width > maxwidth) {
540 makequad(&quads[0], x, y, x + maxwidth, y + (height * maxwidth / width));
541 } else {
542 makequad(&quads[0], x - (int)((double)(width - maxwidth) * position), y, x + width, y + height);
543 }
544
545 glBindTexture(GL_TEXTURE_2D, texture);
546
547 float one[] = {1.0, 1.0, 1.0};
548 float zero[] = {0.0, 0.0, 0.0};
549 glUniform3fv(k, 1, one);
550 glUniform3fv(k2, 1, zero);
551
552 glDrawQuads(0, 1);
553
554 glUniform3fv(k2, 1, one);
555 }
556 #endif
557