1 //
2 // Copyright (c) 2009-2013 Mikko Mononen memon@inside.org
3 //
4 // This software is provided 'as-is', without any express or implied
5 // warranty. In no event will the authors be held liable for any damages
6 // arising from the use of this software.
7 // Permission is granted to anyone to use this software for any purpose,
8 // including commercial applications, and to alter it and redistribute it
9 // freely, subject to the following restrictions:
10 // 1. The origin of this software must not be misrepresented; you must not
11 // claim that you wrote the original software. If you use this software
12 // in a product, an acknowledgment in the product documentation would be
13 // appreciated but is not required.
14 // 2. Altered source versions must be plainly marked as such, and must not be
15 // misrepresented as being the original software.
16 // 3. This notice may not be removed or altered from any source distribution.
17 //
18 #ifndef NANOVG_GL2_H
19 #define NANOVG_GL2_H
20
21 #ifdef __cplusplus
22 extern "C" {
23 #endif
24
25 #define NVG_ANTIALIAS 1
26
27 #ifdef NANOVG_GLES2_IMPLEMENTATION
28 # ifndef NANOVG_GLES2
29 # define NANOVG_GLES2
30 # endif
31 # ifndef NANOVG_GL2_IMPLEMENTATION
32 # define NANOVG_GL2_IMPLEMENTATION
33 # endif
34 #endif
35
36 #ifdef NANOVG_GLES2
37
38 struct NVGcontext* nvgCreateGLES2(int atlasw, int atlash, int edgeaa);
39 void nvgDeleteGLES2(struct NVGcontext* ctx);
40
41 #else
42
43 struct NVGcontext* nvgCreateGL2(int atlasw, int atlash, int edgeaa);
44 void nvgDeleteGL2(struct NVGcontext* ctx);
45
46 #endif
47
48
49 #ifdef __cplusplus
50 }
51 #endif
52
53 #endif
54
55 #ifdef NANOVG_GL2_IMPLEMENTATION
56
57 #include <stdlib.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <math.h>
61 #include "nanovg.h"
62
63 enum GLNVGuniformLoc {
64 GLNVG_LOC_VIEWSIZE,
65 GLNVG_LOC_SCISSORMAT,
66 GLNVG_LOC_SCISSOREXT,
67 GLNVG_LOC_SCISSORSCALE,
68 GLNVG_LOC_PAINTMAT,
69 GLNVG_LOC_EXTENT,
70 GLNVG_LOC_RADIUS,
71 GLNVG_LOC_FEATHER,
72 GLNVG_LOC_INNERCOL,
73 GLNVG_LOC_OUTERCOL,
74 GLNVG_LOC_STROKEMULT,
75 GLNVG_LOC_TEX,
76 GLNVG_LOC_TEXTYPE,
77 GLNVG_LOC_TYPE,
78 GLNVG_MAX_LOCS
79 };
80
81 enum GLNVGshaderType {
82 NSVG_SHADER_FILLGRAD,
83 NSVG_SHADER_FILLIMG,
84 NSVG_SHADER_SIMPLE,
85 NSVG_SHADER_IMG
86 };
87
88 struct GLNVGshader {
89 GLuint prog;
90 GLuint frag;
91 GLuint vert;
92 GLint loc[GLNVG_MAX_LOCS];
93 };
94
95 struct GLNVGtexture {
96 int id;
97 GLuint tex;
98 int width, height;
99 int type;
100 };
101
102 struct GLNVGcontext {
103 struct GLNVGshader shader;
104 struct GLNVGtexture* textures;
105 float viewWidth, viewHeight;
106 int ntextures;
107 int ctextures;
108 int textureId;
109 GLuint vertBuf;
110 int edgeAntiAlias;
111 };
112
glnvg__allocTexture(struct GLNVGcontext * gl)113 static struct GLNVGtexture* glnvg__allocTexture(struct GLNVGcontext* gl)
114 {
115 struct GLNVGtexture* tex = NULL;
116 int i;
117
118 for (i = 0; i < gl->ntextures; i++) {
119 if (gl->textures[i].id == 0) {
120 tex = &gl->textures[i];
121 break;
122 }
123 }
124 if (tex == NULL) {
125 if (gl->ntextures+1 > gl->ctextures) {
126 gl->ctextures = (gl->ctextures == 0) ? 2 : gl->ctextures*2;
127 gl->textures = (struct GLNVGtexture*)realloc(gl->textures, sizeof(struct GLNVGtexture)*gl->ctextures);
128 if (gl->textures == NULL) return NULL;
129 }
130 tex = &gl->textures[gl->ntextures++];
131 }
132
133 memset(tex, 0, sizeof(*tex));
134 tex->id = ++gl->textureId;
135
136 return tex;
137 }
138
glnvg__findTexture(struct GLNVGcontext * gl,int id)139 static struct GLNVGtexture* glnvg__findTexture(struct GLNVGcontext* gl, int id)
140 {
141 int i;
142 for (i = 0; i < gl->ntextures; i++)
143 if (gl->textures[i].id == id)
144 return &gl->textures[i];
145 return NULL;
146 }
147
glnvg__deleteTexture(struct GLNVGcontext * gl,int id)148 static int glnvg__deleteTexture(struct GLNVGcontext* gl, int id)
149 {
150 int i;
151 for (i = 0; i < gl->ntextures; i++) {
152 if (gl->textures[i].id == id) {
153 if (gl->textures[i].tex != 0)
154 glDeleteTextures(1, &gl->textures[i].tex);
155 memset(&gl->textures[i], 0, sizeof(gl->textures[i]));
156 return 1;
157 }
158 }
159 return 0;
160 }
161
glnvg__dumpShaderError(GLuint shader,const char * name,const char * type)162 static void glnvg__dumpShaderError(GLuint shader, const char* name, const char* type)
163 {
164 char str[512+1];
165 int len = 0;
166 glGetShaderInfoLog(shader, 512, &len, str);
167 if (len > 512) len = 512;
168 str[len] = '\0';
169 printf("Shader %s/%s error:\n%s\n", name, type, str);
170 }
171
glnvg__dumpProgramError(GLuint prog,const char * name)172 static void glnvg__dumpProgramError(GLuint prog, const char* name)
173 {
174 char str[512+1];
175 int len = 0;
176 glGetProgramInfoLog(prog, 512, &len, str);
177 if (len > 512) len = 512;
178 str[len] = '\0';
179 printf("Program %s error:\n%s\n", name, str);
180 }
181
glnvg__checkError(const char * str)182 static int glnvg__checkError(const char* str)
183 {
184 GLenum err = glGetError();
185 if (err != GL_NO_ERROR) {
186 printf("Error %08x after %s\n", err, str);
187 return 1;
188 }
189 return 0;
190 }
191
glnvg__createShader(struct GLNVGshader * shader,const char * name,const char * vshader,const char * fshader)192 static int glnvg__createShader(struct GLNVGshader* shader, const char* name, const char* vshader, const char* fshader)
193 {
194 GLint status;
195 GLuint prog, vert, frag;
196
197 memset(shader, 0, sizeof(*shader));
198
199 prog = glCreateProgram();
200 vert = glCreateShader(GL_VERTEX_SHADER);
201 frag = glCreateShader(GL_FRAGMENT_SHADER);
202 glShaderSource(vert, 1, &vshader, 0);
203 glShaderSource(frag, 1, &fshader, 0);
204
205 glCompileShader(vert);
206 glGetShaderiv(vert, GL_COMPILE_STATUS, &status);
207 if (status != GL_TRUE) {
208 glnvg__dumpShaderError(vert, name, "vert");
209 return 0;
210 }
211
212 glCompileShader(frag);
213 glGetShaderiv(frag, GL_COMPILE_STATUS, &status);
214 if (status != GL_TRUE) {
215 glnvg__dumpShaderError(frag, name, "frag");
216 return 0;
217 }
218
219 glAttachShader(prog, vert);
220 glAttachShader(prog, frag);
221
222 glBindAttribLocation(prog, 0, "vertex");
223 glBindAttribLocation(prog, 1, "tcoord");
224 glBindAttribLocation(prog, 2, "color");
225
226 glLinkProgram(prog);
227 glGetProgramiv(prog, GL_LINK_STATUS, &status);
228 if (status != GL_TRUE) {
229 glnvg__dumpProgramError(prog, name);
230 return 0;
231 }
232
233 shader->prog = prog;
234 shader->vert = vert;
235 shader->frag = frag;
236
237 return 1;
238 }
239
glnvg__deleteShader(struct GLNVGshader * shader)240 static void glnvg__deleteShader(struct GLNVGshader* shader)
241 {
242 if (shader->prog != 0)
243 glDeleteProgram(shader->prog);
244 if (shader->vert != 0)
245 glDeleteShader(shader->vert);
246 if (shader->frag != 0)
247 glDeleteShader(shader->frag);
248 }
249
glnvg__getUniforms(struct GLNVGshader * shader)250 static void glnvg__getUniforms(struct GLNVGshader* shader)
251 {
252 shader->loc[GLNVG_LOC_VIEWSIZE] = glGetUniformLocation(shader->prog, "viewSize");
253 shader->loc[GLNVG_LOC_SCISSORMAT] = glGetUniformLocation(shader->prog, "scissorMat");
254 shader->loc[GLNVG_LOC_SCISSOREXT] = glGetUniformLocation(shader->prog, "scissorExt");
255 shader->loc[GLNVG_LOC_SCISSORSCALE] = glGetUniformLocation(shader->prog, "scissorScale");
256 shader->loc[GLNVG_LOC_PAINTMAT] = glGetUniformLocation(shader->prog, "paintMat");
257 shader->loc[GLNVG_LOC_EXTENT] = glGetUniformLocation(shader->prog, "extent");
258 shader->loc[GLNVG_LOC_RADIUS] = glGetUniformLocation(shader->prog, "radius");
259 shader->loc[GLNVG_LOC_FEATHER] = glGetUniformLocation(shader->prog, "feather");
260 shader->loc[GLNVG_LOC_INNERCOL] = glGetUniformLocation(shader->prog, "innerCol");
261 shader->loc[GLNVG_LOC_OUTERCOL] = glGetUniformLocation(shader->prog, "outerCol");
262 shader->loc[GLNVG_LOC_STROKEMULT] = glGetUniformLocation(shader->prog, "strokeMult");
263 shader->loc[GLNVG_LOC_TEX] = glGetUniformLocation(shader->prog, "tex");
264 shader->loc[GLNVG_LOC_TEXTYPE] = glGetUniformLocation(shader->prog, "texType");
265 shader->loc[GLNVG_LOC_TYPE] = glGetUniformLocation(shader->prog, "type");
266 }
267
glnvg__renderCreate(void * uptr)268 static int glnvg__renderCreate(void* uptr)
269 {
270 struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
271
272 static const char* fillVertShader =
273 #ifdef NANOVG_GLES2
274 "#version 100\n"
275 "precision mediump float;\n"
276 #endif
277 "uniform vec2 viewSize;\n"
278 "attribute vec2 vertex;\n"
279 "attribute vec2 tcoord;\n"
280 "attribute vec4 color;\n"
281 "varying vec2 ftcoord;\n"
282 "varying vec4 fcolor;\n"
283 "varying vec2 fpos;\n"
284 "void main(void) {\n"
285 " ftcoord = tcoord;\n"
286 " fcolor = color;\n"
287 " fpos = vertex;\n"
288 " gl_Position = vec4(2.0*vertex.x/viewSize.x - 1.0, 1.0 - 2.0*vertex.y/viewSize.y, 0, 1);\n"
289 "}\n";
290
291 static const char* fillFragShaderEdgeAA =
292 #ifdef NANOVG_GLES2
293 "#version 100\n"
294 "precision mediump float;\n"
295 #endif
296 "uniform mat3 scissorMat;\n"
297 "uniform vec2 scissorExt;\n"
298 "uniform vec2 scissorScale;\n"
299 "uniform mat3 paintMat;\n"
300 "uniform vec2 extent;\n"
301 "uniform float radius;\n"
302 "uniform float feather;\n"
303 "uniform vec4 innerCol;\n"
304 "uniform vec4 outerCol;\n"
305 "uniform float strokeMult;\n"
306 "uniform sampler2D tex;\n"
307 "uniform int texType;\n"
308 "uniform int type;\n"
309 "varying vec2 ftcoord;\n"
310 "varying vec4 fcolor;\n"
311 "varying vec2 fpos;\n"
312 "\n"
313 "float sdroundrect(vec2 pt, vec2 ext, float rad) {\n"
314 " vec2 ext2 = ext - vec2(rad,rad);\n"
315 " vec2 d = abs(pt) - ext2;\n"
316 " return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rad;\n"
317 "}\n"
318 "\n"
319 "// Scissoring\n"
320 "float scissorMask(vec2 p) {\n"
321 " vec2 sc = (abs((scissorMat * vec3(p,1.0)).xy) - scissorExt);\n"
322 " sc = vec2(0.5,0.5) - sc * scissorScale;\n"
323 " return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);\n"
324 "}\n"
325 "\n"
326 "// Stroke - from [0..1] to clipped pyramid, where the slope is 1px.\n"
327 "float strokeMask() {\n"
328 " return min(1.0, (1.0-abs(ftcoord.x*2.0-1.0))*strokeMult) * ftcoord.y;\n"
329 "}\n"
330 "\n"
331 "void main(void) {\n"
332 " if (type == 0) {\n"
333 " float scissor = scissorMask(fpos);\n"
334 " float strokeAlpha = strokeMask();\n"
335 " // Calculate gradient color using box gradient\n"
336 " vec2 pt = (paintMat * vec3(fpos,1.0)).xy;\n"
337 " float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0);\n"
338 " vec4 color = mix(innerCol,outerCol,d);\n"
339 " // Combine alpha\n"
340 " color.w *= strokeAlpha * scissor;\n"
341 " gl_FragColor = color;\n"
342 " } else if (type == 1) {\n"
343 " float scissor = scissorMask(fpos);\n"
344 " float strokeAlpha = strokeMask();\n"
345 " // Calculate color fron texture\n"
346 " vec2 pt = (paintMat * vec3(fpos,1.0)).xy / extent;\n"
347 " vec4 color = texture2D(tex, pt);\n"
348 " color = texType == 0 ? color : vec4(1,1,1,color.x);\n"
349 " // Combine alpha\n"
350 " color.w *= strokeAlpha * scissor;\n"
351 " gl_FragColor = color;\n"
352 " } else if (type == 2) {\n"
353 " gl_FragColor = vec4(1,1,1,1);\n"
354 " } else if (type == 3) {\n"
355 " vec4 color = texture2D(tex, ftcoord);\n"
356 " color = texType == 0 ? color : vec4(1,1,1,color.x);\n"
357 " gl_FragColor = color * fcolor;\n"
358 " }\n"
359 "}\n";
360
361 static const char* fillFragShader =
362 #ifdef NANOVG_GLES2
363 "#version 100\n"
364 "precision mediump float;\n"
365 #endif
366 "uniform mat3 scissorMat;\n"
367 "uniform vec2 scissorExt;\n"
368 "uniform vec2 scissorScale;\n"
369 "uniform mat3 paintMat;\n"
370 "uniform vec2 extent;\n"
371 "uniform float radius;\n"
372 "uniform float feather;\n"
373 "uniform vec4 innerCol;\n"
374 "uniform vec4 outerCol;\n"
375 "uniform float strokeMult;\n"
376 "uniform sampler2D tex;\n"
377 "uniform int texType;\n"
378 "uniform int type;\n"
379 "varying vec2 ftcoord;\n"
380 "varying vec4 fcolor;\n"
381 "varying vec2 fpos;\n"
382 "\n"
383 "float sdroundrect(vec2 pt, vec2 ext, float rad) {\n"
384 " vec2 ext2 = ext - vec2(rad,rad);\n"
385 " vec2 d = abs(pt) - ext2;\n"
386 " return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rad;\n"
387 "}\n"
388 "\n"
389 "// Scissoring\n"
390 "float scissorMask(vec2 p) {\n"
391 " vec2 sc = (abs((scissorMat * vec3(p,1.0)).xy) - scissorExt);\n"
392 " sc = vec2(0.5,0.5) - sc * scissorScale;\n"
393 " return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);\n"
394 "}\n"
395 "\n"
396 "void main(void) {\n"
397 " if (type == 0) {\n"
398 " float scissor = scissorMask(fpos);\n"
399 " // Calculate gradient color using box gradient\n"
400 " vec2 pt = (paintMat * vec3(fpos,1.0)).xy;\n"
401 " float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0);\n"
402 " vec4 color = mix(innerCol,outerCol,d);\n"
403 " // Combine alpha\n"
404 " color.w *= scissor;\n"
405 " gl_FragColor = color;\n"
406 " } else if (type == 1) {\n"
407 " float scissor = scissorMask(fpos);\n"
408 " // Calculate color fron texture\n"
409 " vec2 pt = (paintMat * vec3(fpos,1.0)).xy / extent;\n"
410 " vec4 color = texture2D(tex, pt);\n"
411 " color = texType == 0 ? color : vec4(1,1,1,color.x);\n"
412 " // Combine alpha\n"
413 " color.w *= scissor;\n"
414 " gl_FragColor = color;\n"
415 " } else if (type == 2) {\n"
416 " gl_FragColor = vec4(1,1,1,1);\n"
417 " } else if (type == 3) {\n"
418 " vec4 color = texture2D(tex, ftcoord);\n"
419 " color = texType == 0 ? color : vec4(1,1,1,color.x);\n"
420 " gl_FragColor = color * fcolor;\n"
421 " }\n"
422 "}\n";
423
424 glnvg__checkError("init");
425
426 if (gl->edgeAntiAlias) {
427 if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShaderEdgeAA) == 0)
428 return 0;
429 } else {
430 if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShader) == 0)
431 return 0;
432 }
433
434 glnvg__checkError("uniform locations");
435 glnvg__getUniforms(&gl->shader);
436
437 // Create dynamic vertex array
438 glGenBuffers(1, &gl->vertBuf);
439
440 glnvg__checkError("done");
441
442 return 1;
443 }
444
glnvg__renderCreateTexture(void * uptr,int type,int w,int h,const unsigned char * data)445 static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, const unsigned char* data)
446 {
447 struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
448 struct GLNVGtexture* tex = glnvg__allocTexture(gl);
449 if (tex == NULL) return 0;
450 glGenTextures(1, &tex->tex);
451 tex->width = w;
452 tex->height = h;
453 tex->type = type;
454 glBindTexture(GL_TEXTURE_2D, tex->tex);
455
456 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
457
458 if (type == NVG_TEXTURE_RGBA)
459 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
460 else
461 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
462
463 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
464 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
465
466 if (glnvg__checkError("create tex"))
467 return 0;
468
469 return tex->id;
470 }
471
glnvg__renderDeleteTexture(void * uptr,int image)472 static int glnvg__renderDeleteTexture(void* uptr, int image)
473 {
474 struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
475 return glnvg__deleteTexture(gl, image);
476 }
477
glnvg__renderUpdateTexture(void * uptr,int image,int x,int y,int w,int h,const unsigned char * data)478 static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data)
479 {
480 struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
481 struct GLNVGtexture* tex = glnvg__findTexture(gl, image);
482
483 if (tex == NULL) return 0;
484 glBindTexture(GL_TEXTURE_2D, tex->tex);
485
486 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
487 #ifdef NANOVG_GLES2
488 // No support for all of unpack, need to update a whole row at a time.
489 if (tex->type == NVG_TEXTURE_RGBA)
490 data += y*tex->width*4;
491 else
492 data += y*tex->width;
493 x = 0;
494 w = tex->width;
495 #else
496 glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->width);
497 glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
498 glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
499 #endif
500
501 if (tex->type == NVG_TEXTURE_RGBA)
502 glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGBA, GL_UNSIGNED_BYTE, data);
503 else
504 glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
505
506 return 1;
507 }
508
glnvg__renderGetTextureSize(void * uptr,int image,int * w,int * h)509 static int glnvg__renderGetTextureSize(void* uptr, int image, int* w, int* h)
510 {
511 struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
512 struct GLNVGtexture* tex = glnvg__findTexture(gl, image);
513 if (tex == NULL) return 0;
514 *w = tex->width;
515 *h = tex->height;
516 return 1;
517 }
518
glnvg__xformIdentity(float * t)519 static void glnvg__xformIdentity(float* t)
520 {
521 t[0] = 1.0f; t[1] = 0.0f;
522 t[2] = 0.0f; t[3] = 1.0f;
523 t[4] = 0.0f; t[5] = 0.0f;
524 }
525
glnvg__xformInverse(float * inv,float * t)526 static void glnvg__xformInverse(float* inv, float* t)
527 {
528 double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1];
529 if (det > -1e-6 && det < 1e-6) {
530 glnvg__xformIdentity(t);
531 return;
532 }
533 invdet = 1.0 / det;
534 inv[0] = (float)(t[3] * invdet);
535 inv[2] = (float)(-t[2] * invdet);
536 inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet);
537 inv[1] = (float)(-t[1] * invdet);
538 inv[3] = (float)(t[0] * invdet);
539 inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet);
540 }
541
glnvg__xformToMat3x3(float * m3,float * t)542 static void glnvg__xformToMat3x3(float* m3, float* t)
543 {
544 m3[0] = t[0];
545 m3[1] = t[1];
546 m3[2] = 0.0f;
547 m3[3] = t[2];
548 m3[4] = t[3];
549 m3[5] = 0.0f;
550 m3[6] = t[4];
551 m3[7] = t[5];
552 m3[8] = 1.0f;
553 }
554
glnvg__setupPaint(struct GLNVGcontext * gl,struct NVGpaint * paint,struct NVGscissor * scissor,float width,float fringe)555 static int glnvg__setupPaint(struct GLNVGcontext* gl, struct NVGpaint* paint, struct NVGscissor* scissor, float width, float fringe)
556 {
557 struct NVGcolor innerCol;
558 struct NVGcolor outerCol;
559 struct GLNVGtexture* tex = NULL;
560 float invxform[6], paintMat[9], scissorMat[9];
561 float scissorx = 0, scissory = 0;
562 float scissorsx = 0, scissorsy = 0;
563
564 innerCol = paint->innerColor;
565 outerCol = paint->outerColor;
566
567 glnvg__xformInverse(invxform, paint->xform);
568 glnvg__xformToMat3x3(paintMat, invxform);
569
570 if (scissor->extent[0] < 0.5f || scissor->extent[1] < 0.5f) {
571 memset(scissorMat, 0, sizeof(scissorMat));
572 scissorx = 1.0f;
573 scissory = 1.0f;
574 scissorsx = 1.0f;
575 scissorsy = 1.0f;
576 } else {
577 glnvg__xformInverse(invxform, scissor->xform);
578 glnvg__xformToMat3x3(scissorMat, invxform);
579 scissorx = scissor->extent[0];
580 scissory = scissor->extent[1];
581 scissorsx = sqrtf(scissor->xform[0]*scissor->xform[0] + scissor->xform[2]*scissor->xform[2]) / fringe;
582 scissorsy = sqrtf(scissor->xform[1]*scissor->xform[1] + scissor->xform[3]*scissor->xform[3]) / fringe;
583 }
584
585 if (paint->image != 0) {
586 tex = glnvg__findTexture(gl, paint->image);
587 if (tex == NULL) return 0;
588 glUseProgram(gl->shader.prog);
589 glUniform1i(gl->shader.loc[GLNVG_LOC_TYPE], NSVG_SHADER_FILLIMG);
590 glUniform2f(gl->shader.loc[GLNVG_LOC_VIEWSIZE], gl->viewWidth, gl->viewHeight);
591 glUniformMatrix3fv(gl->shader.loc[GLNVG_LOC_SCISSORMAT], 1, GL_FALSE, scissorMat);
592 glUniform2f(gl->shader.loc[GLNVG_LOC_SCISSOREXT], scissorx, scissory);
593 glUniform2f(gl->shader.loc[GLNVG_LOC_SCISSORSCALE], scissorsx, scissorsy);
594 glUniformMatrix3fv(gl->shader.loc[GLNVG_LOC_PAINTMAT], 1, GL_FALSE, paintMat);
595 glUniform2f(gl->shader.loc[GLNVG_LOC_EXTENT], paint->extent[0], paint->extent[1]);
596 glUniform1f(gl->shader.loc[GLNVG_LOC_STROKEMULT], (width*0.5f + fringe*0.5f)/fringe);
597 glUniform1i(gl->shader.loc[GLNVG_LOC_TEX], 0);
598 glUniform1i(gl->shader.loc[GLNVG_LOC_TEXTYPE], tex->type == NVG_TEXTURE_RGBA ? 0 : 1);
599 glnvg__checkError("tex paint loc");
600 glBindTexture(GL_TEXTURE_2D, tex->tex);
601 glnvg__checkError("tex paint tex");
602 } else {
603 glUseProgram(gl->shader.prog);
604 glUniform1i(gl->shader.loc[GLNVG_LOC_TYPE], NSVG_SHADER_FILLGRAD);
605 glUniform2f(gl->shader.loc[GLNVG_LOC_VIEWSIZE], gl->viewWidth, gl->viewHeight);
606 glUniformMatrix3fv(gl->shader.loc[GLNVG_LOC_SCISSORMAT], 1, GL_FALSE, scissorMat);
607 glUniform2f(gl->shader.loc[GLNVG_LOC_SCISSOREXT], scissorx, scissory);
608 glUniform2f(gl->shader.loc[GLNVG_LOC_SCISSORSCALE], scissorsx, scissorsy);
609 glUniformMatrix3fv(gl->shader.loc[GLNVG_LOC_PAINTMAT], 1, GL_FALSE, paintMat);
610 glUniform2f(gl->shader.loc[GLNVG_LOC_EXTENT], paint->extent[0], paint->extent[1]);
611 glUniform1f(gl->shader.loc[GLNVG_LOC_RADIUS], paint->radius);
612 glUniform1f(gl->shader.loc[GLNVG_LOC_FEATHER], paint->feather);
613 glUniform4fv(gl->shader.loc[GLNVG_LOC_INNERCOL], 1, innerCol.rgba);
614 glUniform4fv(gl->shader.loc[GLNVG_LOC_OUTERCOL], 1, outerCol.rgba);
615 glUniform1f(gl->shader.loc[GLNVG_LOC_STROKEMULT], (width*0.5f + fringe*0.5f)/fringe);
616 glnvg__checkError("grad paint loc");
617 }
618 return 1;
619 }
620
glnvg__renderViewport(void * uptr,int width,int height,int alphaBlend)621 static void glnvg__renderViewport(void* uptr, int width, int height, int alphaBlend)
622 {
623 struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
624 gl->viewWidth = (float)width;
625 gl->viewHeight = (float)height;
626
627 glEnable(GL_BLEND);
628 glEnable(GL_CULL_FACE);
629 glDisable(GL_DEPTH_TEST);
630
631 if (alphaBlend == NVG_PREMULTIPLIED_ALPHA)
632 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
633 else
634 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
635 }
636
637
glnvg__renderFlush(void * uptr,int alphaBlend)638 static void glnvg__renderFlush(void* uptr, int alphaBlend)
639 {
640 // struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
641 NVG_NOTUSED(uptr);
642 NVG_NOTUSED(alphaBlend);
643 }
644
glnvg__maxVertCount(const struct NVGpath * paths,int npaths)645 static int glnvg__maxVertCount(const struct NVGpath* paths, int npaths)
646 {
647 int i, count = 0;
648 for (i = 0; i < npaths; i++) {
649 count += paths[i].nfill;
650 count += paths[i].nstroke;
651 }
652 return count;
653 }
654
glnvg__uploadPaths(const struct NVGpath * paths,int npaths)655 static void glnvg__uploadPaths(const struct NVGpath* paths, int npaths)
656 {
657 const struct NVGpath* path;
658 int i, n = 0;
659 for (i = 0; i < npaths; i++) {
660 path = &paths[i];
661 if (path->nfill > 0) {
662 glBufferSubData(GL_ARRAY_BUFFER, n*sizeof(struct NVGvertex), path->nfill * sizeof(struct NVGvertex), &path->fill[0].x);
663 n += path->nfill;
664 }
665 if (path->nstroke > 0) {
666 glBufferSubData(GL_ARRAY_BUFFER, n*sizeof(struct NVGvertex), path->nstroke * sizeof(struct NVGvertex), &path->stroke[0].x);
667 n += path->nstroke;
668 }
669 }
670 }
671
glnvg__renderFill(void * uptr,struct NVGpaint * paint,struct NVGscissor * scissor,float fringe,const float * bounds,const struct NVGpath * paths,int npaths)672 static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float fringe,
673 const float* bounds, const struct NVGpath* paths, int npaths)
674 {
675 struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
676 const struct NVGpath* path;
677 int i, n, offset, maxCount;
678
679 if (gl->shader.prog == 0)
680 return;
681
682 maxCount = glnvg__maxVertCount(paths, npaths);
683 glBindBuffer(GL_ARRAY_BUFFER, gl->vertBuf);
684 glBufferData(GL_ARRAY_BUFFER, maxCount * sizeof(struct NVGvertex), NULL, GL_STREAM_DRAW);
685 glnvg__uploadPaths(paths, npaths);
686
687 if (npaths == 1 && paths[0].convex) {
688
689 glEnable(GL_CULL_FACE);
690
691 glEnableVertexAttribArray(0);
692 glEnableVertexAttribArray(1);
693 glnvg__setupPaint(gl, paint, scissor, fringe, fringe);
694
695 glDisable(GL_CULL_FACE);
696 n = 0;
697 for (i = 0; i < npaths; i++) {
698 path = &paths[i];
699 offset = n * sizeof(struct NVGvertex);
700 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(size_t)offset);
701 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(offset + 2*sizeof(float)));
702 glDrawArrays(GL_TRIANGLE_FAN, 0, path->nfill);
703 n += path->nfill + path->nstroke;
704 }
705
706 glEnable(GL_CULL_FACE);
707
708 if (gl->edgeAntiAlias) {
709 // Draw fringes
710 n = 0;
711 for (i = 0; i < npaths; i++) {
712 path = &paths[i];
713 offset = (n + path->nfill) * sizeof(struct NVGvertex);
714 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(size_t)offset);
715 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(offset + 2*sizeof(float)));
716 glDrawArrays(GL_TRIANGLE_STRIP, 0, path->nstroke);
717 n += path->nfill + path->nstroke;
718 }
719 }
720
721 glUseProgram(0);
722 glDisableVertexAttribArray(0);
723 glDisableVertexAttribArray(1);
724
725 } else {
726 float quad[6*2] = {
727 bounds[0], bounds[3], bounds[2], bounds[3], bounds[2], bounds[1],
728 bounds[0], bounds[3], bounds[2], bounds[1], bounds[0], bounds[1],
729 };
730
731 glEnable(GL_CULL_FACE);
732
733 glBindBuffer(GL_ARRAY_BUFFER, gl->vertBuf);
734
735 // Draw shapes
736 glDisable(GL_BLEND);
737 glEnable(GL_STENCIL_TEST);
738 glStencilMask(0xff);
739 glStencilFunc(GL_ALWAYS, 0, ~0U);
740 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
741
742 glUseProgram(gl->shader.prog);
743 glUniform1i(gl->shader.loc[GLNVG_LOC_TYPE], NSVG_SHADER_SIMPLE);
744 glUniform2f(gl->shader.loc[GLNVG_LOC_VIEWSIZE], gl->viewWidth, gl->viewHeight);
745 glnvg__checkError("fill solid loc");
746
747 glEnableVertexAttribArray(0);
748
749 glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP);
750 glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP);
751 glDisable(GL_CULL_FACE);
752 n = 0;
753 for (i = 0; i < npaths; i++) {
754 path = &paths[i];
755 offset = n * sizeof(struct NVGvertex);
756 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(size_t)offset);
757 glDrawArrays(GL_TRIANGLE_FAN, 0, path->nfill);
758 n += path->nfill + path->nstroke;
759 }
760
761 glEnable(GL_CULL_FACE);
762
763 // Draw aliased off-pixels
764 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
765 glEnable(GL_BLEND);
766
767 glEnableVertexAttribArray(1);
768 glnvg__setupPaint(gl, paint, scissor, fringe, fringe);
769
770 if (gl->edgeAntiAlias) {
771 glStencilFunc(GL_EQUAL, 0x00, 0xff);
772 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
773
774 // Draw fringes
775 n = 0;
776 for (i = 0; i < npaths; i++) {
777 path = &paths[i];
778 offset = (n + path->nfill) * sizeof(struct NVGvertex);
779 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(size_t)offset);
780 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(offset + 2*sizeof(float)));
781 glDrawArrays(GL_TRIANGLE_STRIP, 0, path->nstroke);
782 n += path->nfill + path->nstroke;
783 }
784 }
785
786 // Draw fill
787 glStencilFunc(GL_NOTEQUAL, 0x0, 0xff);
788 glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
789
790 glDisableVertexAttribArray(1);
791
792 glBufferSubData(GL_ARRAY_BUFFER, 0, 6 * 2*sizeof(float), quad);
793 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (const GLvoid*)0);
794 glVertexAttrib2f(1, 0.5f, 1.0f);
795 glDrawArrays(GL_TRIANGLES, 0, 6);
796
797 glUseProgram(0);
798
799 glDisableVertexAttribArray(0);
800
801 glDisable(GL_STENCIL_TEST);
802 }
803 }
804
glnvg__renderStroke(void * uptr,struct NVGpaint * paint,struct NVGscissor * scissor,float fringe,float width,const struct NVGpath * paths,int npaths)805 static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float fringe,
806 float width, const struct NVGpath* paths, int npaths)
807 {
808 struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
809 const struct NVGpath* path;
810 int i, n, offset, maxCount;
811
812 if (gl->shader.prog == 0)
813 return;
814
815 glnvg__setupPaint(gl, paint, scissor, width, fringe);
816
817 glEnable(GL_CULL_FACE);
818
819 maxCount = glnvg__maxVertCount(paths, npaths);
820 glBindBuffer(GL_ARRAY_BUFFER, gl->vertBuf);
821 glBufferData(GL_ARRAY_BUFFER, maxCount * sizeof(struct NVGvertex), NULL, GL_STREAM_DRAW);
822 glnvg__uploadPaths(paths, npaths);
823
824 glEnableVertexAttribArray(0);
825 glEnableVertexAttribArray(1);
826
827 // Draw Strokes
828 n = 0;
829 for (i = 0; i < npaths; i++) {
830 path = &paths[i];
831 offset = (n + path->nfill) * sizeof(struct NVGvertex);
832 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(size_t)offset);
833 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(offset + 2*sizeof(float)));
834 glDrawArrays(GL_TRIANGLE_STRIP, 0, path->nstroke);
835 n += path->nfill + path->nstroke;
836 }
837
838 glDisableVertexAttribArray(0);
839 glDisableVertexAttribArray(1);
840
841 glUseProgram(0);
842 }
843
glnvg__renderTriangles(void * uptr,struct NVGpaint * paint,struct NVGscissor * scissor,const struct NVGvertex * verts,int nverts)844 static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor,
845 const struct NVGvertex* verts, int nverts)
846 {
847 struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
848 struct GLNVGtexture* tex = glnvg__findTexture(gl, paint->image);
849 struct NVGcolor color;
850 NVG_NOTUSED(scissor);
851
852 if (gl->shader.prog == 0)
853 return;
854
855 if (tex != NULL) {
856 glBindTexture(GL_TEXTURE_2D, tex->tex);
857 }
858
859 glUseProgram(gl->shader.prog);
860 glUniform1i(gl->shader.loc[GLNVG_LOC_TYPE], NSVG_SHADER_IMG);
861 glUniform2f(gl->shader.loc[GLNVG_LOC_VIEWSIZE], gl->viewWidth, gl->viewHeight);
862 glUniform1i(gl->shader.loc[GLNVG_LOC_TEX], 0);
863 glUniform1i(gl->shader.loc[GLNVG_LOC_TEXTYPE], (tex != NULL && tex->type == NVG_TEXTURE_RGBA) ? 0 : 1);
864 glnvg__checkError("tris solid img loc");
865
866 glBindBuffer(GL_ARRAY_BUFFER, gl->vertBuf);
867 glBufferData(GL_ARRAY_BUFFER, nverts * sizeof(struct NVGvertex), verts, GL_STREAM_DRAW);
868
869 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)0);
870 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(2 * sizeof(float)));
871 glEnableVertexAttribArray(0);
872 glEnableVertexAttribArray(1);
873
874 color = paint->innerColor;
875 glVertexAttrib4fv(2, color.rgba);
876
877 glDrawArrays(GL_TRIANGLES, 0, nverts);
878
879 glDisableVertexAttribArray(0);
880 glDisableVertexAttribArray(1);
881 }
882
glnvg__renderDelete(void * uptr)883 static void glnvg__renderDelete(void* uptr)
884 {
885 struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
886 int i;
887 if (gl == NULL) return;
888
889 glnvg__deleteShader(&gl->shader);
890
891 for (i = 0; i < gl->ntextures; i++) {
892 if (gl->textures[i].tex != 0)
893 glDeleteTextures(1, &gl->textures[i].tex);
894 }
895 free(gl->textures);
896
897 free(gl);
898 }
899
900
901 #ifdef NANOVG_GLES2
nvgCreateGLES2(int atlasw,int atlash,int edgeaa)902 struct NVGcontext* nvgCreateGLES2(int atlasw, int atlash, int edgeaa)
903 #else
904 struct NVGcontext* nvgCreateGL2(int atlasw, int atlash, int edgeaa)
905 #endif
906 {
907 struct NVGparams params;
908 struct NVGcontext* ctx = NULL;
909 struct GLNVGcontext* gl = (struct GLNVGcontext*)malloc(sizeof(struct GLNVGcontext));
910 if (gl == NULL) goto error;
911 memset(gl, 0, sizeof(struct GLNVGcontext));
912
913 memset(¶ms, 0, sizeof(params));
914 params.renderCreate = glnvg__renderCreate;
915 params.renderCreateTexture = glnvg__renderCreateTexture;
916 params.renderDeleteTexture = glnvg__renderDeleteTexture;
917 params.renderUpdateTexture = glnvg__renderUpdateTexture;
918 params.renderGetTextureSize = glnvg__renderGetTextureSize;
919 params.renderViewport = glnvg__renderViewport;
920 params.renderFlush = glnvg__renderFlush;
921 params.renderFill = glnvg__renderFill;
922 params.renderStroke = glnvg__renderStroke;
923 params.renderTriangles = glnvg__renderTriangles;
924 params.renderDelete = glnvg__renderDelete;
925 params.userPtr = gl;
926 params.atlasWidth = atlasw;
927 params.atlasHeight = atlash;
928 params.edgeAntiAlias = edgeaa;
929
930 gl->edgeAntiAlias = edgeaa;
931
932 ctx = nvgCreateInternal(¶ms);
933 if (ctx == NULL) goto error;
934
935 return ctx;
936
937 error:
938 // 'gl' is freed by nvgDeleteInternal.
939 if (ctx != NULL) nvgDeleteInternal(ctx);
940 return NULL;
941 }
942
943 #ifdef NANOVG_GLES2
nvgDeleteGLES2(struct NVGcontext * ctx)944 void nvgDeleteGLES2(struct NVGcontext* ctx)
945 #else
946 void nvgDeleteGL2(struct NVGcontext* ctx)
947 #endif
948 {
949 nvgDeleteInternal(ctx);
950 }
951
952 #endif
953