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