nanovg_gl.h (51729B)
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_GL_H 19 #define NANOVG_GL_H 20 21 #if defined NANOVG_GL2_FORCED 22 # undef NANOVG_GL3 23 # undef NANOVG_GLES2 24 # undef NANOVG_GLES3 25 # define NANOVG_GL2 1 26 #elif defined NANOVG_GL3_FORCED 27 # undef NANOVG_GL2 28 # undef NANOVG_GLES2 29 # undef NANOVG_GLES3 30 # define NANOVG_GL3 1 31 #elif defined NANOVG_GLES2_FORCED 32 # undef NANOVG_GL2 33 # undef NANOVG_GL3 34 # undef NANOVG_GLES3 35 # define NANOVG_GLES2 1 36 #elif defined NANOVG_GLES3_FORCED 37 # undef NANOVG_GL2 38 # undef NANOVG_GL3 39 # undef NANOVG_GLES2 40 # define NANOVG_GLES3 1 41 #endif 42 43 #ifdef __cplusplus 44 extern "C" { 45 #endif 46 47 // Create flags 48 49 enum NVGcreateFlags { 50 // Flag indicating if geometry based anti-aliasing is used (may not be needed when using MSAA). 51 NVG_ANTIALIAS = 1<<0, 52 // Flag indicating if strokes should be drawn using stencil buffer. The rendering will be a little 53 // slower, but path overlaps (i.e. self-intersecting or sharp turns) will be drawn just once. 54 NVG_STENCIL_STROKES = 1<<1, 55 // Flag indicating that additional debug checks are done. 56 NVG_DEBUG = 1<<2, 57 }; 58 59 #if defined NANOVG_GL2_IMPLEMENTATION 60 # define NANOVG_GL2 1 61 # define NANOVG_GL_IMPLEMENTATION 1 62 #elif defined NANOVG_GL3_IMPLEMENTATION 63 # define NANOVG_GL3 1 64 # define NANOVG_GL_IMPLEMENTATION 1 65 # define NANOVG_GL_USE_UNIFORMBUFFER 1 66 #elif defined NANOVG_GLES2_IMPLEMENTATION 67 # define NANOVG_GLES2 1 68 # define NANOVG_GL_IMPLEMENTATION 1 69 #elif defined NANOVG_GLES3_IMPLEMENTATION 70 # define NANOVG_GLES3 1 71 # define NANOVG_GL_IMPLEMENTATION 1 72 #endif 73 74 #define NANOVG_GL_USE_STATE_FILTER (1) 75 76 // Creates NanoVG contexts for different OpenGL (ES) versions. 77 // Flags should be combination of the create flags above. 78 79 #if defined NANOVG_GL2 80 81 NVGcontext* nvgCreateGL2(int flags); 82 NVGcontext* nvgCreateSharedGL2(NVGcontext* other, int flags); 83 void nvgDeleteGL2(NVGcontext* ctx); 84 85 int nvglCreateImageFromHandleGL2(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); 86 GLuint nvglImageHandleGL2(NVGcontext* ctx, int image); 87 88 #endif 89 90 #if defined NANOVG_GL3 91 92 NVGcontext* nvgCreateGL3(int flags); 93 NVGcontext* nvgCreateSharedGL3(NVGcontext* other, int flags); 94 void nvgDeleteGL3(NVGcontext* ctx); 95 96 int nvglCreateImageFromHandleGL3(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); 97 GLuint nvglImageHandleGL3(NVGcontext* ctx, int image); 98 99 #endif 100 101 #if defined NANOVG_GLES2 102 103 NVGcontext* nvgCreateGLES2(int flags); 104 NVGcontext* nvgCreateSharedGLES2(NVGcontext* other, int flags); 105 void nvgDeleteGLES2(NVGcontext* ctx); 106 107 int nvglCreateImageFromHandleGLES2(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); 108 GLuint nvglImageHandleGLES2(NVGcontext* ctx, int image); 109 110 #endif 111 112 #if defined NANOVG_GLES3 113 114 NVGcontext* nvgCreateGLES3(int flags); 115 NVGcontext* nvgCreateSharedGLES3(NVGcontext* other, int flags); 116 void nvgDeleteGLES3(NVGcontext* ctx); 117 118 int nvglCreateImageFromHandleGLES3(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); 119 GLuint nvglImageHandleGLES3(NVGcontext* ctx, int image); 120 121 #endif 122 123 // These are additional flags on top of NVGimageFlags. 124 enum NVGimageFlagsGL { 125 NVG_IMAGE_NODELETE = 1<<16, // Do not delete GL texture handle. 126 }; 127 128 #ifdef __cplusplus 129 } 130 #endif 131 132 #endif /* NANOVG_GL_H */ 133 134 #ifdef NANOVG_GL_IMPLEMENTATION 135 136 #include <stdlib.h> 137 #include <stdio.h> 138 #include <string.h> 139 #include <math.h> 140 #include "nanovg.h" 141 142 enum GLNVGuniformLoc { 143 GLNVG_LOC_VIEWSIZE, 144 GLNVG_LOC_TEX, 145 GLNVG_LOC_FRAG, 146 GLNVG_MAX_LOCS 147 }; 148 149 enum GLNVGshaderType { 150 NSVG_SHADER_FILLGRAD, 151 NSVG_SHADER_FILLIMG, 152 NSVG_SHADER_SIMPLE, 153 NSVG_SHADER_IMG 154 }; 155 156 #if NANOVG_GL_USE_UNIFORMBUFFER 157 enum GLNVGuniformBindings { 158 GLNVG_FRAG_BINDING = 0, 159 }; 160 #endif 161 162 struct GLNVGshader { 163 GLuint prog; 164 GLuint frag; 165 GLuint vert; 166 GLint loc[GLNVG_MAX_LOCS]; 167 }; 168 typedef struct GLNVGshader GLNVGshader; 169 170 struct GLNVGtexture { 171 int id; 172 GLuint tex; 173 int width, height; 174 int type; 175 int flags; 176 #if defined NANOVG_GLES2 177 unsigned char* data; 178 #endif 179 }; 180 typedef struct GLNVGtexture GLNVGtexture; 181 182 struct GLNVGblend 183 { 184 GLenum srcRGB; 185 GLenum dstRGB; 186 GLenum srcAlpha; 187 GLenum dstAlpha; 188 }; 189 typedef struct GLNVGblend GLNVGblend; 190 191 enum GLNVGcallType { 192 GLNVG_NONE = 0, 193 GLNVG_FILL, 194 GLNVG_CONVEXFILL, 195 GLNVG_STROKE, 196 GLNVG_TRIANGLES, 197 }; 198 199 struct GLNVGcall { 200 int type; 201 int image; 202 int pathOffset; 203 int pathCount; 204 int triangleOffset; 205 int triangleCount; 206 int uniformOffset; 207 GLNVGblend blendFunc; 208 }; 209 typedef struct GLNVGcall GLNVGcall; 210 211 struct GLNVGpath { 212 int fillOffset; 213 int fillCount; 214 int strokeOffset; 215 int strokeCount; 216 }; 217 typedef struct GLNVGpath GLNVGpath; 218 219 struct GLNVGfragUniforms { 220 #if NANOVG_GL_USE_UNIFORMBUFFER 221 float scissorMat[12]; // matrices are actually 3 vec4s 222 float paintMat[12]; 223 struct NVGcolor innerCol; 224 struct NVGcolor outerCol; 225 float scissorExt[2]; 226 float scissorScale[2]; 227 float extent[2]; 228 float radius; 229 float feather; 230 float strokeMult; 231 float strokeThr; 232 int texType; 233 int type; 234 #else 235 // note: after modifying layout or size of uniform array, 236 // don't forget to also update the fragment shader source! 237 #define NANOVG_GL_UNIFORMARRAY_SIZE 11 238 union { 239 struct { 240 float scissorMat[12]; // matrices are actually 3 vec4s 241 float paintMat[12]; 242 struct NVGcolor innerCol; 243 struct NVGcolor outerCol; 244 float scissorExt[2]; 245 float scissorScale[2]; 246 float extent[2]; 247 float radius; 248 float feather; 249 float strokeMult; 250 float strokeThr; 251 float texType; 252 float type; 253 }; 254 float uniformArray[NANOVG_GL_UNIFORMARRAY_SIZE][4]; 255 }; 256 #endif 257 }; 258 typedef struct GLNVGfragUniforms GLNVGfragUniforms; 259 260 struct GLNVGtextureContext { // Textures; shared between shared NanoVG contexts. 261 int refCount; 262 GLNVGtexture* textures; 263 int ntextures; 264 int ctextures; 265 int textureId; 266 }; 267 typedef struct GLNVGtextureContext GLNVGtextureContext; 268 269 struct GLNVGcontext { 270 GLNVGshader shader; 271 GLNVGtextureContext* textureContext; 272 float view[2]; 273 GLuint vertBuf; 274 #if defined NANOVG_GL3 275 GLuint vertArr; 276 #endif 277 #if NANOVG_GL_USE_UNIFORMBUFFER 278 GLuint fragBuf; 279 #endif 280 int fragSize; 281 int flags; 282 283 // Per frame buffers 284 GLNVGcall* calls; 285 int ccalls; 286 int ncalls; 287 GLNVGpath* paths; 288 int cpaths; 289 int npaths; 290 struct NVGvertex* verts; 291 int cverts; 292 int nverts; 293 unsigned char* uniforms; 294 int cuniforms; 295 int nuniforms; 296 297 // cached state 298 #if NANOVG_GL_USE_STATE_FILTER 299 GLuint boundTexture; 300 GLuint stencilMask; 301 GLenum stencilFunc; 302 GLint stencilFuncRef; 303 GLuint stencilFuncMask; 304 GLNVGblend blendFunc; 305 #endif 306 307 int dummyTex; 308 }; 309 typedef struct GLNVGcontext GLNVGcontext; 310 311 static int glnvg__maxi(int a, int b) { return a > b ? a : b; } 312 313 #ifdef NANOVG_GLES2 314 static unsigned int glnvg__nearestPow2(unsigned int num) 315 { 316 unsigned n = num > 0 ? num - 1 : 0; 317 n |= n >> 1; 318 n |= n >> 2; 319 n |= n >> 4; 320 n |= n >> 8; 321 n |= n >> 16; 322 n++; 323 return n; 324 } 325 #endif 326 327 static void glnvg__bindTexture(GLNVGcontext* gl, GLuint tex) 328 { 329 #if NANOVG_GL_USE_STATE_FILTER 330 if (gl->boundTexture != tex) { 331 gl->boundTexture = tex; 332 glBindTexture(GL_TEXTURE_2D, tex); 333 } 334 #else 335 glBindTexture(GL_TEXTURE_2D, tex); 336 #endif 337 } 338 339 static void glnvg__stencilMask(GLNVGcontext* gl, GLuint mask) 340 { 341 #if NANOVG_GL_USE_STATE_FILTER 342 if (gl->stencilMask != mask) { 343 gl->stencilMask = mask; 344 glStencilMask(mask); 345 } 346 #else 347 glStencilMask(mask); 348 #endif 349 } 350 351 static void glnvg__stencilFunc(GLNVGcontext* gl, GLenum func, GLint ref, GLuint mask) 352 { 353 #if NANOVG_GL_USE_STATE_FILTER 354 if ((gl->stencilFunc != func) || 355 (gl->stencilFuncRef != ref) || 356 (gl->stencilFuncMask != mask)) { 357 358 gl->stencilFunc = func; 359 gl->stencilFuncRef = ref; 360 gl->stencilFuncMask = mask; 361 glStencilFunc(func, ref, mask); 362 } 363 #else 364 glStencilFunc(func, ref, mask); 365 #endif 366 } 367 static void glnvg__blendFuncSeparate(GLNVGcontext* gl, const GLNVGblend* blend) 368 { 369 #if NANOVG_GL_USE_STATE_FILTER 370 if ((gl->blendFunc.srcRGB != blend->srcRGB) || 371 (gl->blendFunc.dstRGB != blend->dstRGB) || 372 (gl->blendFunc.srcAlpha != blend->srcAlpha) || 373 (gl->blendFunc.dstAlpha != blend->dstAlpha)) { 374 375 gl->blendFunc = *blend; 376 glBlendFuncSeparate(blend->srcRGB, blend->dstRGB, blend->srcAlpha,blend->dstAlpha); 377 } 378 #else 379 glBlendFuncSeparate(blend->srcRGB, blend->dstRGB, blend->srcAlpha,blend->dstAlpha); 380 #endif 381 } 382 383 static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl) 384 { 385 GLNVGtexture* tex = NULL; 386 int i; 387 388 for (i = 0; i < gl->textureContext->ntextures; i++) { 389 if (gl->textureContext->textures[i].id == 0) { 390 tex = &gl->textureContext->textures[i]; 391 break; 392 } 393 } 394 if (tex == NULL) { 395 if (gl->textureContext->ntextures+1 > gl->textureContext->ctextures) { 396 GLNVGtexture* textures; 397 int ctextures = glnvg__maxi(gl->textureContext->ntextures+1, 4) + gl->textureContext->ctextures/2; // 1.5x Overallocate 398 textures = (GLNVGtexture*)realloc(gl->textureContext->textures, sizeof(GLNVGtexture)*ctextures); 399 if (textures == NULL) return NULL; 400 gl->textureContext->textures = textures; 401 gl->textureContext->ctextures = ctextures; 402 } 403 tex = &gl->textureContext->textures[gl->textureContext->ntextures++]; 404 } 405 406 memset(tex, 0, sizeof(*tex)); 407 tex->id = ++gl->textureContext->textureId; 408 409 return tex; 410 } 411 412 static GLNVGtexture* glnvg__findTexture(GLNVGcontext* gl, int id) 413 { 414 int i; 415 for (i = 0; i < gl->textureContext->ntextures; i++) 416 if (gl->textureContext->textures[i].id == id) 417 return &gl->textureContext->textures[i]; 418 return NULL; 419 } 420 421 static int glnvg__deleteTexture(GLNVGcontext* gl, int id) 422 { 423 int i; 424 for (i = 0; i < gl->textureContext->ntextures; i++) { 425 if (gl->textureContext->textures[i].id == id) { 426 if (gl->textureContext->textures[i].tex != 0 && (gl->textureContext->textures[i].flags & NVG_IMAGE_NODELETE) == 0) 427 { 428 glDeleteTextures(1, &gl->textureContext->textures[i].tex); 429 #if defined NANOVG_GLES2 430 free(gl->textureContext->textures[i].data); 431 #endif 432 } 433 memset(&gl->textureContext->textures[i], 0, sizeof(gl->textureContext->textures[i])); 434 return 1; 435 } 436 } 437 return 0; 438 } 439 440 static void glnvg__dumpShaderError(GLuint shader, const char* name, const char* type) 441 { 442 GLchar str[512+1]; 443 GLsizei len = 0; 444 glGetShaderInfoLog(shader, 512, &len, str); 445 if (len > 512) len = 512; 446 str[len] = '\0'; 447 printf("Shader %s/%s error:\n%s\n", name, type, str); 448 } 449 450 static void glnvg__dumpProgramError(GLuint prog, const char* name) 451 { 452 GLchar str[512+1]; 453 GLsizei len = 0; 454 glGetProgramInfoLog(prog, 512, &len, str); 455 if (len > 512) len = 512; 456 str[len] = '\0'; 457 printf("Program %s error:\n%s\n", name, str); 458 } 459 460 static void glnvg__checkError(GLNVGcontext* gl, const char* str) 461 { 462 GLenum err; 463 if ((gl->flags & NVG_DEBUG) == 0) return; 464 err = glGetError(); 465 if (err != GL_NO_ERROR) { 466 printf("Error %08x after %s\n", err, str); 467 return; 468 } 469 } 470 471 static int glnvg__createShader(GLNVGshader* shader, const char* name, const char* header, const char* opts, const char* vshader, const char* fshader) 472 { 473 GLint status; 474 GLuint prog, vert, frag; 475 const char* str[3]; 476 str[0] = header; 477 str[1] = opts != NULL ? opts : ""; 478 479 memset(shader, 0, sizeof(*shader)); 480 481 prog = glCreateProgram(); 482 vert = glCreateShader(GL_VERTEX_SHADER); 483 frag = glCreateShader(GL_FRAGMENT_SHADER); 484 str[2] = vshader; 485 glShaderSource(vert, 3, str, 0); 486 str[2] = fshader; 487 glShaderSource(frag, 3, str, 0); 488 489 glCompileShader(vert); 490 glGetShaderiv(vert, GL_COMPILE_STATUS, &status); 491 if (status != GL_TRUE) { 492 glnvg__dumpShaderError(vert, name, "vert"); 493 return 0; 494 } 495 496 glCompileShader(frag); 497 glGetShaderiv(frag, GL_COMPILE_STATUS, &status); 498 if (status != GL_TRUE) { 499 glnvg__dumpShaderError(frag, name, "frag"); 500 return 0; 501 } 502 503 glAttachShader(prog, vert); 504 glAttachShader(prog, frag); 505 506 glBindAttribLocation(prog, 0, "vertex"); 507 glBindAttribLocation(prog, 1, "tcoord"); 508 509 glLinkProgram(prog); 510 glGetProgramiv(prog, GL_LINK_STATUS, &status); 511 if (status != GL_TRUE) { 512 glnvg__dumpProgramError(prog, name); 513 return 0; 514 } 515 516 shader->prog = prog; 517 shader->vert = vert; 518 shader->frag = frag; 519 520 return 1; 521 } 522 523 static void glnvg__deleteShader(GLNVGshader* shader) 524 { 525 if (shader->prog != 0) 526 glDeleteProgram(shader->prog); 527 if (shader->vert != 0) 528 glDeleteShader(shader->vert); 529 if (shader->frag != 0) 530 glDeleteShader(shader->frag); 531 } 532 533 static void glnvg__getUniforms(GLNVGshader* shader) 534 { 535 shader->loc[GLNVG_LOC_VIEWSIZE] = glGetUniformLocation(shader->prog, "viewSize"); 536 shader->loc[GLNVG_LOC_TEX] = glGetUniformLocation(shader->prog, "tex"); 537 538 #if NANOVG_GL_USE_UNIFORMBUFFER 539 shader->loc[GLNVG_LOC_FRAG] = glGetUniformBlockIndex(shader->prog, "frag"); 540 #else 541 shader->loc[GLNVG_LOC_FRAG] = glGetUniformLocation(shader->prog, "frag"); 542 #endif 543 } 544 545 static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data); 546 547 static int glnvg__renderCreate(void* uptr, void* otherUptr) // Share the textures of GLNVGcontext 'otherUptr' if it's non-NULL. 548 { 549 GLNVGcontext* gl = (GLNVGcontext*)uptr; 550 551 if (otherUptr) { 552 GLNVGcontext* other = (GLNVGcontext*)otherUptr; 553 gl->textureContext = other->textureContext; 554 gl->textureContext->refCount++; 555 } else { 556 gl->textureContext = (GLNVGtextureContext*)malloc(sizeof(GLNVGtextureContext)); 557 memset(gl->textureContext, 0, sizeof(GLNVGtextureContext)); 558 gl->textureContext->refCount = 1; 559 } 560 561 int align = 4; 562 563 // TODO: mediump float may not be enough for GLES2 in iOS. 564 // see the following discussion: https://github.com/memononen/nanovg/issues/46 565 static const char* shaderHeader = 566 #if defined NANOVG_GL2 567 "#define NANOVG_GL2 1\n" 568 #elif defined NANOVG_GL3 569 "#version 150 core\n" 570 "#define NANOVG_GL3 1\n" 571 #elif defined NANOVG_GLES2 572 "#version 100\n" 573 "#define NANOVG_GL2 1\n" 574 #elif defined NANOVG_GLES3 575 "#version 300 es\n" 576 "#define NANOVG_GL3 1\n" 577 #endif 578 579 #if NANOVG_GL_USE_UNIFORMBUFFER 580 "#define USE_UNIFORMBUFFER 1\n" 581 #else 582 "#define UNIFORMARRAY_SIZE 11\n" 583 #endif 584 "\n"; 585 586 static const char* fillVertShader = 587 "#ifdef NANOVG_GL3\n" 588 " uniform vec2 viewSize;\n" 589 " in vec2 vertex;\n" 590 " in vec2 tcoord;\n" 591 " out vec2 ftcoord;\n" 592 " out vec2 fpos;\n" 593 "#else\n" 594 " uniform vec2 viewSize;\n" 595 " attribute vec2 vertex;\n" 596 " attribute vec2 tcoord;\n" 597 " varying vec2 ftcoord;\n" 598 " varying vec2 fpos;\n" 599 "#endif\n" 600 "void main(void) {\n" 601 " ftcoord = tcoord;\n" 602 " fpos = vertex;\n" 603 " gl_Position = vec4(2.0*vertex.x/viewSize.x - 1.0, 1.0 - 2.0*vertex.y/viewSize.y, 0, 1);\n" 604 "}\n"; 605 606 static const char* fillFragShader = 607 "#ifdef GL_ES\n" 608 "#if defined(GL_FRAGMENT_PRECISION_HIGH) || defined(NANOVG_GL3)\n" 609 " precision highp float;\n" 610 "#else\n" 611 " precision mediump float;\n" 612 "#endif\n" 613 "#endif\n" 614 "#ifdef NANOVG_GL3\n" 615 "#ifdef USE_UNIFORMBUFFER\n" 616 " layout(std140) uniform frag {\n" 617 " mat3 scissorMat;\n" 618 " mat3 paintMat;\n" 619 " vec4 innerCol;\n" 620 " vec4 outerCol;\n" 621 " vec2 scissorExt;\n" 622 " vec2 scissorScale;\n" 623 " vec2 extent;\n" 624 " float radius;\n" 625 " float feather;\n" 626 " float strokeMult;\n" 627 " float strokeThr;\n" 628 " int texType;\n" 629 " int type;\n" 630 " };\n" 631 "#else\n" // NANOVG_GL3 && !USE_UNIFORMBUFFER 632 " uniform vec4 frag[UNIFORMARRAY_SIZE];\n" 633 "#endif\n" 634 " uniform sampler2D tex;\n" 635 " in vec2 ftcoord;\n" 636 " in vec2 fpos;\n" 637 " out vec4 outColor;\n" 638 "#else\n" // !NANOVG_GL3 639 " uniform vec4 frag[UNIFORMARRAY_SIZE];\n" 640 " uniform sampler2D tex;\n" 641 " varying vec2 ftcoord;\n" 642 " varying vec2 fpos;\n" 643 "#endif\n" 644 "#ifndef USE_UNIFORMBUFFER\n" 645 " #define scissorMat mat3(frag[0].xyz, frag[1].xyz, frag[2].xyz)\n" 646 " #define paintMat mat3(frag[3].xyz, frag[4].xyz, frag[5].xyz)\n" 647 " #define innerCol frag[6]\n" 648 " #define outerCol frag[7]\n" 649 " #define scissorExt frag[8].xy\n" 650 " #define scissorScale frag[8].zw\n" 651 " #define extent frag[9].xy\n" 652 " #define radius frag[9].z\n" 653 " #define feather frag[9].w\n" 654 " #define strokeMult frag[10].x\n" 655 " #define strokeThr frag[10].y\n" 656 " #define texType int(frag[10].z)\n" 657 " #define type int(frag[10].w)\n" 658 "#endif\n" 659 "\n" 660 "float sdroundrect(vec2 pt, vec2 ext, float rad) {\n" 661 " vec2 ext2 = ext - vec2(rad,rad);\n" 662 " vec2 d = abs(pt) - ext2;\n" 663 " return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rad;\n" 664 "}\n" 665 "\n" 666 "// Scissoring\n" 667 "float scissorMask(vec2 p) {\n" 668 " vec2 sc = (abs((scissorMat * vec3(p,1.0)).xy) - scissorExt);\n" 669 " sc = vec2(0.5,0.5) - sc * scissorScale;\n" 670 " return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);\n" 671 "}\n" 672 "#ifdef EDGE_AA\n" 673 "// Stroke - from [0..1] to clipped pyramid, where the slope is 1px.\n" 674 "float strokeMask() {\n" 675 " return min(1.0, (1.0-abs(ftcoord.x*2.0-1.0))*strokeMult) * min(1.0, ftcoord.y);\n" 676 "}\n" 677 "#endif\n" 678 "\n" 679 "void main(void) {\n" 680 " vec4 result;\n" 681 " float scissor = scissorMask(fpos);\n" 682 "#ifdef EDGE_AA\n" 683 " float strokeAlpha = strokeMask();\n" 684 " if (strokeAlpha < strokeThr) discard;\n" 685 "#else\n" 686 " float strokeAlpha = 1.0;\n" 687 "#endif\n" 688 " if (type == 0) { // Gradient\n" 689 " // Calculate gradient color using box gradient\n" 690 " vec2 pt = (paintMat * vec3(fpos,1.0)).xy;\n" 691 " float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0);\n" 692 " vec4 color = mix(innerCol,outerCol,d);\n" 693 " // Combine alpha\n" 694 " color *= strokeAlpha * scissor;\n" 695 " result = color;\n" 696 " } else if (type == 1) { // Image\n" 697 " // Calculate color fron texture\n" 698 " vec2 pt = (paintMat * vec3(fpos,1.0)).xy / extent;\n" 699 "#ifdef NANOVG_GL3\n" 700 " vec4 color = texture(tex, pt);\n" 701 "#else\n" 702 " vec4 color = texture2D(tex, pt);\n" 703 "#endif\n" 704 " if (texType == 1) color = vec4(color.xyz*color.w,color.w);" 705 " if (texType == 2) color = vec4(color.x);" 706 " // Apply color tint and alpha.\n" 707 " color *= innerCol;\n" 708 " // Combine alpha\n" 709 " color *= strokeAlpha * scissor;\n" 710 " result = color;\n" 711 " } else if (type == 2) { // Stencil fill\n" 712 " result = vec4(1,1,1,1);\n" 713 " } else if (type == 3) { // Textured tris\n" 714 "#ifdef NANOVG_GL3\n" 715 " vec4 color = texture(tex, ftcoord);\n" 716 "#else\n" 717 " vec4 color = texture2D(tex, ftcoord);\n" 718 "#endif\n" 719 " if (texType == 1) color = vec4(color.xyz*color.w,color.w);" 720 " if (texType == 2) color = vec4(color.x);" 721 " color *= scissor;\n" 722 " result = color * innerCol;\n" 723 " }\n" 724 "#ifdef NANOVG_GL3\n" 725 " outColor = result;\n" 726 "#else\n" 727 " gl_FragColor = result;\n" 728 "#endif\n" 729 "}\n"; 730 731 glnvg__checkError(gl, "init"); 732 733 if (gl->flags & NVG_ANTIALIAS) { 734 if (glnvg__createShader(&gl->shader, "shader", shaderHeader, "#define EDGE_AA 1\n", fillVertShader, fillFragShader) == 0) 735 return 0; 736 } else { 737 if (glnvg__createShader(&gl->shader, "shader", shaderHeader, NULL, fillVertShader, fillFragShader) == 0) 738 return 0; 739 } 740 741 glnvg__checkError(gl, "uniform locations"); 742 glnvg__getUniforms(&gl->shader); 743 744 // Create dynamic vertex array 745 #if defined NANOVG_GL3 746 glGenVertexArrays(1, &gl->vertArr); 747 #endif 748 glGenBuffers(1, &gl->vertBuf); 749 750 #if NANOVG_GL_USE_UNIFORMBUFFER 751 // Create UBOs 752 glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_FRAG], GLNVG_FRAG_BINDING); 753 glGenBuffers(1, &gl->fragBuf); 754 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &align); 755 #endif 756 gl->fragSize = sizeof(GLNVGfragUniforms) + align - sizeof(GLNVGfragUniforms) % align; 757 758 // Some platforms does not allow to have samples to unset textures. 759 // Create empty one which is bound when there's no texture specified. 760 gl->dummyTex = glnvg__renderCreateTexture(gl, NVG_TEXTURE_ALPHA, 1, 1, 0, NULL); 761 762 glnvg__checkError(gl, "create done"); 763 764 glFinish(); 765 766 return 1; 767 } 768 769 static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data) 770 { 771 GLNVGcontext* gl = (GLNVGcontext*)uptr; 772 GLNVGtexture* tex = glnvg__allocTexture(gl); 773 774 if (tex == NULL) return 0; 775 776 #ifdef NANOVG_GLES2 777 // Check for non-power of 2. 778 if (glnvg__nearestPow2(w) != (unsigned int)w || glnvg__nearestPow2(h) != (unsigned int)h) { 779 // No repeat 780 if ((imageFlags & NVG_IMAGE_REPEATX) != 0 || (imageFlags & NVG_IMAGE_REPEATY) != 0) { 781 printf("Repeat X/Y is not supported for non power-of-two textures (%d x %d)\n", w, h); 782 imageFlags &= ~(NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); 783 } 784 // No mips. 785 if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) { 786 printf("Mip-maps is not supported for non power-of-two textures (%d x %d)\n", w, h); 787 imageFlags &= ~NVG_IMAGE_GENERATE_MIPMAPS; 788 } 789 } 790 #endif 791 792 glGenTextures(1, &tex->tex); 793 tex->width = w; 794 tex->height = h; 795 tex->type = type; 796 tex->flags = imageFlags; 797 glnvg__bindTexture(gl, tex->tex); 798 799 glPixelStorei(GL_UNPACK_ALIGNMENT,1); 800 #ifndef NANOVG_GLES2 801 glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->width); 802 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); 803 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); 804 #endif 805 806 #if defined (NANOVG_GL2) 807 // GL 1.4 and later has support for generating mipmaps using a tex parameter. 808 if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) { 809 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); 810 } 811 #endif 812 813 switch (type) 814 { 815 case NVG_TEXTURE_BGR: 816 #if NANOVG_GLES2 817 // GLES2 cannot handle GL_BGR, do local conversion to GL_RGB 818 tex->data = (uint8_t*)malloc(sizeof(uint8_t) * 3 * w * h); 819 for (uint32_t i=0; i<w*h; ++i) 820 { 821 tex->data[i*3+0] = data[i*3+2]; 822 tex->data[i*3+1] = data[i*3+1]; 823 tex->data[i*3+2] = data[i*3+0]; 824 } 825 data = tex->data; 826 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 827 #else 828 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_BGR, GL_UNSIGNED_BYTE, data); 829 #endif 830 break; 831 case NVG_TEXTURE_BGRA: 832 #if NANOVG_GLES2 833 // GLES2 cannot handle GL_BGRA, do local conversion to GL_RGBA 834 tex->data = (uint8_t*)malloc(sizeof(uint8_t) * 4 * w * h); 835 for (uint32_t i=0; i<w*h; ++i) 836 { 837 tex->data[i*3+0] = data[i*3+3]; 838 tex->data[i*3+1] = data[i*3+2]; 839 tex->data[i*3+2] = data[i*3+1]; 840 tex->data[i*3+3] = data[i*3+0]; 841 } 842 data = tex->data; 843 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, data); 844 #else 845 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, data); 846 #endif 847 break; 848 case NVG_TEXTURE_RGB: 849 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 850 break; 851 case NVG_TEXTURE_RGBA: 852 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); 853 break; 854 default: 855 #if defined(NANOVG_GLES2) || defined (NANOVG_GL2) 856 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); 857 #elif defined(NANOVG_GLES3) 858 glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data); 859 #else 860 glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data); 861 #endif 862 break; 863 } 864 865 if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) { 866 if (imageFlags & NVG_IMAGE_NEAREST) { 867 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); 868 } else { 869 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 870 } 871 } else { 872 if (imageFlags & NVG_IMAGE_NEAREST) { 873 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 874 } else { 875 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 876 } 877 } 878 879 if (imageFlags & NVG_IMAGE_NEAREST) { 880 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 881 } else { 882 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 883 } 884 885 if (imageFlags & NVG_IMAGE_REPEATX) 886 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 887 else 888 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 889 890 if (imageFlags & NVG_IMAGE_REPEATY) 891 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 892 else 893 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 894 895 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 896 #ifndef NANOVG_GLES2 897 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 898 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); 899 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); 900 #endif 901 902 // The new way to build mipmaps on GLES and GL3 903 #if !defined(NANOVG_GL2) 904 if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) { 905 glGenerateMipmap(GL_TEXTURE_2D); 906 } 907 #endif 908 909 glnvg__checkError(gl, "create tex"); 910 glnvg__bindTexture(gl, 0); 911 912 return tex->id; 913 } 914 915 916 static int glnvg__renderDeleteTexture(void* uptr, int image) 917 { 918 GLNVGcontext* gl = (GLNVGcontext*)uptr; 919 return glnvg__deleteTexture(gl, image); 920 } 921 922 static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data) 923 { 924 GLNVGcontext* gl = (GLNVGcontext*)uptr; 925 GLNVGtexture* tex = glnvg__findTexture(gl, image); 926 927 if (tex == NULL) return 0; 928 glnvg__bindTexture(gl, tex->tex); 929 930 glPixelStorei(GL_UNPACK_ALIGNMENT,1); 931 932 #ifndef NANOVG_GLES2 933 glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->width); 934 glPixelStorei(GL_UNPACK_SKIP_PIXELS, x); 935 glPixelStorei(GL_UNPACK_SKIP_ROWS, y); 936 #else 937 // No support for all of skip, need to update a whole row at a time. 938 switch (tex->type) 939 { 940 case NVG_TEXTURE_BGR: 941 data += y*tex->width*3; 942 break; 943 case NVG_TEXTURE_BGRA: 944 data += y*tex->width*4; 945 break; 946 case NVG_TEXTURE_RGB: 947 data += y*tex->width*3; 948 break; 949 case NVG_TEXTURE_RGBA: 950 data += y*tex->width*4; 951 break; 952 default: 953 data += y*tex->width; 954 break; 955 } 956 x = 0; 957 w = tex->width; 958 #endif 959 960 switch (tex->type) 961 { 962 case NVG_TEXTURE_BGR: 963 glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_BGR, GL_UNSIGNED_BYTE, data); 964 break; 965 case NVG_TEXTURE_BGRA: 966 glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_BGRA, GL_UNSIGNED_BYTE, data); 967 break; 968 case NVG_TEXTURE_RGB: 969 glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGB, GL_UNSIGNED_BYTE, data); 970 break; 971 case NVG_TEXTURE_RGBA: 972 glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGBA, GL_UNSIGNED_BYTE, data); 973 break; 974 default: 975 #if defined(NANOVG_GLES2) || defined(NANOVG_GL2) 976 glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); 977 #else 978 glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RED, GL_UNSIGNED_BYTE, data); 979 #endif 980 break; 981 } 982 983 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 984 #ifndef NANOVG_GLES2 985 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 986 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); 987 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); 988 #endif 989 990 glnvg__bindTexture(gl, 0); 991 992 return 1; 993 } 994 995 static int glnvg__renderGetTextureSize(void* uptr, int image, int* w, int* h) 996 { 997 GLNVGcontext* gl = (GLNVGcontext*)uptr; 998 GLNVGtexture* tex = glnvg__findTexture(gl, image); 999 if (tex == NULL) return 0; 1000 *w = tex->width; 1001 *h = tex->height; 1002 return 1; 1003 } 1004 1005 static void glnvg__xformToMat3x4(float* m3, float* t) 1006 { 1007 m3[0] = t[0]; 1008 m3[1] = t[1]; 1009 m3[2] = 0.0f; 1010 m3[3] = 0.0f; 1011 m3[4] = t[2]; 1012 m3[5] = t[3]; 1013 m3[6] = 0.0f; 1014 m3[7] = 0.0f; 1015 m3[8] = t[4]; 1016 m3[9] = t[5]; 1017 m3[10] = 1.0f; 1018 m3[11] = 0.0f; 1019 } 1020 1021 static NVGcolor glnvg__premulColor(NVGcolor c) 1022 { 1023 c.r *= c.a; 1024 c.g *= c.a; 1025 c.b *= c.a; 1026 return c; 1027 } 1028 1029 static int glnvg__convertPaint(GLNVGcontext* gl, GLNVGfragUniforms* frag, NVGpaint* paint, 1030 NVGscissor* scissor, float width, float fringe, float strokeThr) 1031 { 1032 GLNVGtexture* tex = NULL; 1033 float invxform[6]; 1034 1035 memset(frag, 0, sizeof(*frag)); 1036 1037 frag->innerCol = glnvg__premulColor(paint->innerColor); 1038 frag->outerCol = glnvg__premulColor(paint->outerColor); 1039 1040 if (scissor->extent[0] < -0.5f || scissor->extent[1] < -0.5f) { 1041 memset(frag->scissorMat, 0, sizeof(frag->scissorMat)); 1042 frag->scissorExt[0] = 1.0f; 1043 frag->scissorExt[1] = 1.0f; 1044 frag->scissorScale[0] = 1.0f; 1045 frag->scissorScale[1] = 1.0f; 1046 } else { 1047 nvgTransformInverse(invxform, scissor->xform); 1048 glnvg__xformToMat3x4(frag->scissorMat, invxform); 1049 frag->scissorExt[0] = scissor->extent[0]; 1050 frag->scissorExt[1] = scissor->extent[1]; 1051 frag->scissorScale[0] = sqrtf(scissor->xform[0]*scissor->xform[0] + scissor->xform[2]*scissor->xform[2]) / fringe; 1052 frag->scissorScale[1] = sqrtf(scissor->xform[1]*scissor->xform[1] + scissor->xform[3]*scissor->xform[3]) / fringe; 1053 } 1054 1055 memcpy(frag->extent, paint->extent, sizeof(frag->extent)); 1056 frag->strokeMult = (width*0.5f + fringe*0.5f) / fringe; 1057 frag->strokeThr = strokeThr; 1058 1059 if (paint->image != 0) { 1060 tex = glnvg__findTexture(gl, paint->image); 1061 if (tex == NULL) return 0; 1062 if ((tex->flags & NVG_IMAGE_FLIPY) != 0) { 1063 float m1[6], m2[6]; 1064 nvgTransformTranslate(m1, 0.0f, frag->extent[1] * 0.5f); 1065 nvgTransformMultiply(m1, paint->xform); 1066 nvgTransformScale(m2, 1.0f, -1.0f); 1067 nvgTransformMultiply(m2, m1); 1068 nvgTransformTranslate(m1, 0.0f, -frag->extent[1] * 0.5f); 1069 nvgTransformMultiply(m1, m2); 1070 nvgTransformInverse(invxform, m1); 1071 } else { 1072 nvgTransformInverse(invxform, paint->xform); 1073 } 1074 frag->type = NSVG_SHADER_FILLIMG; 1075 1076 #if NANOVG_GL_USE_UNIFORMBUFFER 1077 switch (tex->type) 1078 { 1079 case NVG_TEXTURE_BGR: 1080 case NVG_TEXTURE_BGRA: 1081 case NVG_TEXTURE_RGB: 1082 case NVG_TEXTURE_RGBA: 1083 frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0 : 1; 1084 break; 1085 default: 1086 frag->texType = 2; 1087 break; 1088 } 1089 #else 1090 switch (tex->type) 1091 { 1092 case NVG_TEXTURE_BGR: 1093 case NVG_TEXTURE_BGRA: 1094 case NVG_TEXTURE_RGB: 1095 case NVG_TEXTURE_RGBA: 1096 frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0.0f : 1.0f; 1097 break; 1098 default: 1099 frag->texType = 2.0f; 1100 break; 1101 } 1102 #endif 1103 // printf("frag->texType = %d\n", frag->texType); 1104 } else { 1105 frag->type = NSVG_SHADER_FILLGRAD; 1106 frag->radius = paint->radius; 1107 frag->feather = paint->feather; 1108 nvgTransformInverse(invxform, paint->xform); 1109 } 1110 1111 glnvg__xformToMat3x4(frag->paintMat, invxform); 1112 1113 return 1; 1114 } 1115 1116 static GLNVGfragUniforms* nvg__fragUniformPtr(GLNVGcontext* gl, int i); 1117 1118 static void glnvg__setUniforms(GLNVGcontext* gl, int uniformOffset, int image) 1119 { 1120 GLNVGtexture* tex = NULL; 1121 #if NANOVG_GL_USE_UNIFORMBUFFER 1122 glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_FRAG_BINDING, gl->fragBuf, uniformOffset, sizeof(GLNVGfragUniforms)); 1123 #else 1124 GLNVGfragUniforms* frag = nvg__fragUniformPtr(gl, uniformOffset); 1125 glUniform4fv(gl->shader.loc[GLNVG_LOC_FRAG], NANOVG_GL_UNIFORMARRAY_SIZE, &(frag->uniformArray[0][0])); 1126 #endif 1127 1128 if (image != 0) { 1129 tex = glnvg__findTexture(gl, image); 1130 } 1131 // If no image is set, use empty texture 1132 if (tex == NULL) { 1133 tex = glnvg__findTexture(gl, gl->dummyTex); 1134 } 1135 glnvg__bindTexture(gl, tex != NULL ? tex->tex : 0); 1136 glnvg__checkError(gl, "tex paint tex"); 1137 } 1138 1139 static void glnvg__renderViewport(void* uptr, float width, float height, float devicePixelRatio) 1140 { 1141 NVG_NOTUSED(devicePixelRatio); 1142 GLNVGcontext* gl = (GLNVGcontext*)uptr; 1143 gl->view[0] = width; 1144 gl->view[1] = height; 1145 } 1146 1147 static void glnvg__fill(GLNVGcontext* gl, GLNVGcall* call) 1148 { 1149 GLNVGpath* paths = &gl->paths[call->pathOffset]; 1150 int i, npaths = call->pathCount; 1151 1152 // Draw shapes 1153 glEnable(GL_STENCIL_TEST); 1154 glnvg__stencilMask(gl, 0xff); 1155 glnvg__stencilFunc(gl, GL_ALWAYS, 0, 0xff); 1156 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 1157 1158 // set bindpoint for solid loc 1159 glnvg__setUniforms(gl, call->uniformOffset, 0); 1160 glnvg__checkError(gl, "fill simple"); 1161 1162 glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); 1163 glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); 1164 glDisable(GL_CULL_FACE); 1165 for (i = 0; i < npaths; i++) 1166 glDrawArrays(GL_TRIANGLE_FAN, paths[i].fillOffset, paths[i].fillCount); 1167 glEnable(GL_CULL_FACE); 1168 1169 // Draw anti-aliased pixels 1170 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 1171 1172 glnvg__setUniforms(gl, call->uniformOffset + gl->fragSize, call->image); 1173 glnvg__checkError(gl, "fill fill"); 1174 1175 if (gl->flags & NVG_ANTIALIAS) { 1176 glnvg__stencilFunc(gl, GL_EQUAL, 0x00, 0xff); 1177 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); 1178 // Draw fringes 1179 for (i = 0; i < npaths; i++) 1180 glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount); 1181 } 1182 1183 // Draw fill 1184 glnvg__stencilFunc(gl, GL_NOTEQUAL, 0x0, 0xff); 1185 glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); 1186 glDrawArrays(GL_TRIANGLE_STRIP, call->triangleOffset, call->triangleCount); 1187 1188 glDisable(GL_STENCIL_TEST); 1189 } 1190 1191 static void glnvg__convexFill(GLNVGcontext* gl, GLNVGcall* call) 1192 { 1193 GLNVGpath* paths = &gl->paths[call->pathOffset]; 1194 int i, npaths = call->pathCount; 1195 1196 glnvg__setUniforms(gl, call->uniformOffset, call->image); 1197 glnvg__checkError(gl, "convex fill"); 1198 1199 for (i = 0; i < npaths; i++) { 1200 glDrawArrays(GL_TRIANGLE_FAN, paths[i].fillOffset, paths[i].fillCount); 1201 // Draw fringes 1202 if (paths[i].strokeCount > 0) { 1203 glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount); 1204 } 1205 } 1206 } 1207 1208 static void glnvg__stroke(GLNVGcontext* gl, GLNVGcall* call) 1209 { 1210 GLNVGpath* paths = &gl->paths[call->pathOffset]; 1211 int npaths = call->pathCount, i; 1212 1213 if (gl->flags & NVG_STENCIL_STROKES) { 1214 1215 glEnable(GL_STENCIL_TEST); 1216 glnvg__stencilMask(gl, 0xff); 1217 1218 // Fill the stroke base without overlap 1219 glnvg__stencilFunc(gl, GL_EQUAL, 0x0, 0xff); 1220 glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); 1221 glnvg__setUniforms(gl, call->uniformOffset + gl->fragSize, call->image); 1222 glnvg__checkError(gl, "stroke fill 0"); 1223 for (i = 0; i < npaths; i++) 1224 glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount); 1225 1226 // Draw anti-aliased pixels. 1227 glnvg__setUniforms(gl, call->uniformOffset, call->image); 1228 glnvg__stencilFunc(gl, GL_EQUAL, 0x00, 0xff); 1229 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); 1230 for (i = 0; i < npaths; i++) 1231 glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount); 1232 1233 // Clear stencil buffer. 1234 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 1235 glnvg__stencilFunc(gl, GL_ALWAYS, 0x0, 0xff); 1236 glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); 1237 glnvg__checkError(gl, "stroke fill 1"); 1238 for (i = 0; i < npaths; i++) 1239 glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount); 1240 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 1241 1242 glDisable(GL_STENCIL_TEST); 1243 1244 // glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset + gl->fragSize), paint, scissor, strokeWidth, fringe, 1.0f - 0.5f/255.0f); 1245 1246 } else { 1247 glnvg__setUniforms(gl, call->uniformOffset, call->image); 1248 glnvg__checkError(gl, "stroke fill"); 1249 // Draw Strokes 1250 for (i = 0; i < npaths; i++) 1251 glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount); 1252 } 1253 } 1254 1255 static void glnvg__triangles(GLNVGcontext* gl, GLNVGcall* call) 1256 { 1257 glnvg__setUniforms(gl, call->uniformOffset, call->image); 1258 glnvg__checkError(gl, "triangles fill"); 1259 1260 glDrawArrays(GL_TRIANGLES, call->triangleOffset, call->triangleCount); 1261 } 1262 1263 static void glnvg__renderCancel(void* uptr) { 1264 GLNVGcontext* gl = (GLNVGcontext*)uptr; 1265 gl->nverts = 0; 1266 gl->npaths = 0; 1267 gl->ncalls = 0; 1268 gl->nuniforms = 0; 1269 } 1270 1271 static GLenum glnvg_convertBlendFuncFactor(int factor) 1272 { 1273 if (factor == NVG_ZERO) 1274 return GL_ZERO; 1275 if (factor == NVG_ONE) 1276 return GL_ONE; 1277 if (factor == NVG_SRC_COLOR) 1278 return GL_SRC_COLOR; 1279 if (factor == NVG_ONE_MINUS_SRC_COLOR) 1280 return GL_ONE_MINUS_SRC_COLOR; 1281 if (factor == NVG_DST_COLOR) 1282 return GL_DST_COLOR; 1283 if (factor == NVG_ONE_MINUS_DST_COLOR) 1284 return GL_ONE_MINUS_DST_COLOR; 1285 if (factor == NVG_SRC_ALPHA) 1286 return GL_SRC_ALPHA; 1287 if (factor == NVG_ONE_MINUS_SRC_ALPHA) 1288 return GL_ONE_MINUS_SRC_ALPHA; 1289 if (factor == NVG_DST_ALPHA) 1290 return GL_DST_ALPHA; 1291 if (factor == NVG_ONE_MINUS_DST_ALPHA) 1292 return GL_ONE_MINUS_DST_ALPHA; 1293 if (factor == NVG_SRC_ALPHA_SATURATE) 1294 return GL_SRC_ALPHA_SATURATE; 1295 return GL_INVALID_ENUM; 1296 } 1297 1298 static GLNVGblend glnvg__blendCompositeOperation(NVGcompositeOperationState op) 1299 { 1300 GLNVGblend blend; 1301 blend.srcRGB = glnvg_convertBlendFuncFactor(op.srcRGB); 1302 blend.dstRGB = glnvg_convertBlendFuncFactor(op.dstRGB); 1303 blend.srcAlpha = glnvg_convertBlendFuncFactor(op.srcAlpha); 1304 blend.dstAlpha = glnvg_convertBlendFuncFactor(op.dstAlpha); 1305 if (blend.srcRGB == GL_INVALID_ENUM || blend.dstRGB == GL_INVALID_ENUM || blend.srcAlpha == GL_INVALID_ENUM || blend.dstAlpha == GL_INVALID_ENUM) 1306 { 1307 blend.srcRGB = GL_ONE; 1308 blend.dstRGB = GL_ONE_MINUS_SRC_ALPHA; 1309 blend.srcAlpha = GL_ONE; 1310 blend.dstAlpha = GL_ONE_MINUS_SRC_ALPHA; 1311 } 1312 return blend; 1313 } 1314 1315 static void glnvg__renderFlush(void* uptr) 1316 { 1317 GLNVGcontext* gl = (GLNVGcontext*)uptr; 1318 int i; 1319 1320 if (gl->ncalls > 0) { 1321 1322 // Setup require GL state. 1323 glUseProgram(gl->shader.prog); 1324 1325 glEnable(GL_CULL_FACE); 1326 glCullFace(GL_BACK); 1327 glFrontFace(GL_CCW); 1328 glEnable(GL_BLEND); 1329 glDisable(GL_DEPTH_TEST); 1330 glDisable(GL_SCISSOR_TEST); 1331 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 1332 glStencilMask(0xffffffff); 1333 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); 1334 glStencilFunc(GL_ALWAYS, 0, 0xffffffff); 1335 glActiveTexture(GL_TEXTURE0); 1336 glBindTexture(GL_TEXTURE_2D, 0); 1337 #if NANOVG_GL_USE_STATE_FILTER 1338 gl->boundTexture = 0; 1339 gl->stencilMask = 0xffffffff; 1340 gl->stencilFunc = GL_ALWAYS; 1341 gl->stencilFuncRef = 0; 1342 gl->stencilFuncMask = 0xffffffff; 1343 gl->blendFunc.srcRGB = GL_INVALID_ENUM; 1344 gl->blendFunc.srcAlpha = GL_INVALID_ENUM; 1345 gl->blendFunc.dstRGB = GL_INVALID_ENUM; 1346 gl->blendFunc.dstAlpha = GL_INVALID_ENUM; 1347 #endif 1348 1349 #if NANOVG_GL_USE_UNIFORMBUFFER 1350 // Upload ubo for frag shaders 1351 glBindBuffer(GL_UNIFORM_BUFFER, gl->fragBuf); 1352 glBufferData(GL_UNIFORM_BUFFER, gl->nuniforms * gl->fragSize, gl->uniforms, GL_STREAM_DRAW); 1353 #endif 1354 1355 // Upload vertex data 1356 #if defined NANOVG_GL3 1357 glBindVertexArray(gl->vertArr); 1358 #endif 1359 glBindBuffer(GL_ARRAY_BUFFER, gl->vertBuf); 1360 glBufferData(GL_ARRAY_BUFFER, gl->nverts * sizeof(NVGvertex), gl->verts, GL_STREAM_DRAW); 1361 glEnableVertexAttribArray(0); 1362 glEnableVertexAttribArray(1); 1363 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(NVGvertex), (const GLvoid*)(size_t)0); 1364 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(NVGvertex), (const GLvoid*)(0 + 2*sizeof(float))); 1365 1366 // Set view and texture just once per frame. 1367 glUniform1i(gl->shader.loc[GLNVG_LOC_TEX], 0); 1368 glUniform2fv(gl->shader.loc[GLNVG_LOC_VIEWSIZE], 1, gl->view); 1369 1370 #if NANOVG_GL_USE_UNIFORMBUFFER 1371 glBindBuffer(GL_UNIFORM_BUFFER, gl->fragBuf); 1372 #endif 1373 1374 for (i = 0; i < gl->ncalls; i++) { 1375 GLNVGcall* call = &gl->calls[i]; 1376 glnvg__blendFuncSeparate(gl,&call->blendFunc); 1377 if (call->type == GLNVG_FILL) 1378 glnvg__fill(gl, call); 1379 else if (call->type == GLNVG_CONVEXFILL) 1380 glnvg__convexFill(gl, call); 1381 else if (call->type == GLNVG_STROKE) 1382 glnvg__stroke(gl, call); 1383 else if (call->type == GLNVG_TRIANGLES) 1384 glnvg__triangles(gl, call); 1385 } 1386 1387 glDisableVertexAttribArray(0); 1388 glDisableVertexAttribArray(1); 1389 #if defined NANOVG_GL3 1390 glBindVertexArray(0); 1391 #endif 1392 glDisable(GL_CULL_FACE); 1393 glBindBuffer(GL_ARRAY_BUFFER, 0); 1394 glUseProgram(0); 1395 glnvg__bindTexture(gl, 0); 1396 } 1397 1398 // Reset calls 1399 gl->nverts = 0; 1400 gl->npaths = 0; 1401 gl->ncalls = 0; 1402 gl->nuniforms = 0; 1403 } 1404 1405 static int glnvg__maxVertCount(const NVGpath* paths, int npaths) 1406 { 1407 int i, count = 0; 1408 for (i = 0; i < npaths; i++) { 1409 count += paths[i].nfill; 1410 count += paths[i].nstroke; 1411 } 1412 return count; 1413 } 1414 1415 static GLNVGcall* glnvg__allocCall(GLNVGcontext* gl) 1416 { 1417 GLNVGcall* ret = NULL; 1418 if (gl->ncalls+1 > gl->ccalls) { 1419 GLNVGcall* calls; 1420 int ccalls = glnvg__maxi(gl->ncalls+1, 128) + gl->ccalls/2; // 1.5x Overallocate 1421 calls = (GLNVGcall*)realloc(gl->calls, sizeof(GLNVGcall) * ccalls); 1422 if (calls == NULL) return NULL; 1423 gl->calls = calls; 1424 gl->ccalls = ccalls; 1425 } 1426 ret = &gl->calls[gl->ncalls++]; 1427 memset(ret, 0, sizeof(GLNVGcall)); 1428 return ret; 1429 } 1430 1431 static int glnvg__allocPaths(GLNVGcontext* gl, int n) 1432 { 1433 int ret = 0; 1434 if (gl->npaths+n > gl->cpaths) { 1435 GLNVGpath* paths; 1436 int cpaths = glnvg__maxi(gl->npaths + n, 128) + gl->cpaths/2; // 1.5x Overallocate 1437 paths = (GLNVGpath*)realloc(gl->paths, sizeof(GLNVGpath) * cpaths); 1438 if (paths == NULL) return -1; 1439 gl->paths = paths; 1440 gl->cpaths = cpaths; 1441 } 1442 ret = gl->npaths; 1443 gl->npaths += n; 1444 return ret; 1445 } 1446 1447 static int glnvg__allocVerts(GLNVGcontext* gl, int n) 1448 { 1449 int ret = 0; 1450 if (gl->nverts+n > gl->cverts) { 1451 NVGvertex* verts; 1452 int cverts = glnvg__maxi(gl->nverts + n, 4096) + gl->cverts/2; // 1.5x Overallocate 1453 verts = (NVGvertex*)realloc(gl->verts, sizeof(NVGvertex) * cverts); 1454 if (verts == NULL) return -1; 1455 gl->verts = verts; 1456 gl->cverts = cverts; 1457 } 1458 ret = gl->nverts; 1459 gl->nverts += n; 1460 return ret; 1461 } 1462 1463 static int glnvg__allocFragUniforms(GLNVGcontext* gl, int n) 1464 { 1465 int ret = 0, structSize = gl->fragSize; 1466 if (gl->nuniforms+n > gl->cuniforms) { 1467 unsigned char* uniforms; 1468 int cuniforms = glnvg__maxi(gl->nuniforms+n, 128) + gl->cuniforms/2; // 1.5x Overallocate 1469 uniforms = (unsigned char*)realloc(gl->uniforms, structSize * cuniforms); 1470 if (uniforms == NULL) return -1; 1471 gl->uniforms = uniforms; 1472 gl->cuniforms = cuniforms; 1473 } 1474 ret = gl->nuniforms * structSize; 1475 gl->nuniforms += n; 1476 return ret; 1477 } 1478 1479 static GLNVGfragUniforms* nvg__fragUniformPtr(GLNVGcontext* gl, int i) 1480 { 1481 return (GLNVGfragUniforms*)&gl->uniforms[i]; 1482 } 1483 1484 static void glnvg__vset(NVGvertex* vtx, float x, float y, float u, float v) 1485 { 1486 vtx->x = x; 1487 vtx->y = y; 1488 vtx->u = u; 1489 vtx->v = v; 1490 } 1491 1492 static void glnvg__renderFill(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, 1493 const float* bounds, const NVGpath* paths, int npaths) 1494 { 1495 GLNVGcontext* gl = (GLNVGcontext*)uptr; 1496 GLNVGcall* call = glnvg__allocCall(gl); 1497 NVGvertex* quad; 1498 GLNVGfragUniforms* frag; 1499 int i, maxverts, offset; 1500 1501 if (call == NULL) return; 1502 1503 call->type = GLNVG_FILL; 1504 call->triangleCount = 4; 1505 call->pathOffset = glnvg__allocPaths(gl, npaths); 1506 if (call->pathOffset == -1) goto error; 1507 call->pathCount = npaths; 1508 call->image = paint->image; 1509 call->blendFunc = glnvg__blendCompositeOperation(compositeOperation); 1510 1511 if (npaths == 1 && paths[0].convex) 1512 { 1513 call->type = GLNVG_CONVEXFILL; 1514 call->triangleCount = 0; // Bounding box fill quad not needed for convex fill 1515 } 1516 1517 // Allocate vertices for all the paths. 1518 maxverts = glnvg__maxVertCount(paths, npaths) + call->triangleCount; 1519 offset = glnvg__allocVerts(gl, maxverts); 1520 if (offset == -1) goto error; 1521 1522 for (i = 0; i < npaths; i++) { 1523 GLNVGpath* copy = &gl->paths[call->pathOffset + i]; 1524 const NVGpath* path = &paths[i]; 1525 memset(copy, 0, sizeof(GLNVGpath)); 1526 if (path->nfill > 0) { 1527 copy->fillOffset = offset; 1528 copy->fillCount = path->nfill; 1529 memcpy(&gl->verts[offset], path->fill, sizeof(NVGvertex) * path->nfill); 1530 offset += path->nfill; 1531 } 1532 if (path->nstroke > 0) { 1533 copy->strokeOffset = offset; 1534 copy->strokeCount = path->nstroke; 1535 memcpy(&gl->verts[offset], path->stroke, sizeof(NVGvertex) * path->nstroke); 1536 offset += path->nstroke; 1537 } 1538 } 1539 1540 // Setup uniforms for draw calls 1541 if (call->type == GLNVG_FILL) { 1542 // Quad 1543 call->triangleOffset = offset; 1544 quad = &gl->verts[call->triangleOffset]; 1545 glnvg__vset(&quad[0], bounds[2], bounds[3], 0.5f, 1.0f); 1546 glnvg__vset(&quad[1], bounds[2], bounds[1], 0.5f, 1.0f); 1547 glnvg__vset(&quad[2], bounds[0], bounds[3], 0.5f, 1.0f); 1548 glnvg__vset(&quad[3], bounds[0], bounds[1], 0.5f, 1.0f); 1549 1550 call->uniformOffset = glnvg__allocFragUniforms(gl, 2); 1551 if (call->uniformOffset == -1) goto error; 1552 // Simple shader for stencil 1553 frag = nvg__fragUniformPtr(gl, call->uniformOffset); 1554 memset(frag, 0, sizeof(*frag)); 1555 frag->strokeThr = -1.0f; 1556 frag->type = NSVG_SHADER_SIMPLE; 1557 // Fill shader 1558 glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset + gl->fragSize), paint, scissor, fringe, fringe, -1.0f); 1559 } else { 1560 call->uniformOffset = glnvg__allocFragUniforms(gl, 1); 1561 if (call->uniformOffset == -1) goto error; 1562 // Fill shader 1563 glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset), paint, scissor, fringe, fringe, -1.0f); 1564 } 1565 1566 return; 1567 1568 error: 1569 // We get here if call alloc was ok, but something else is not. 1570 // Roll back the last call to prevent drawing it. 1571 if (gl->ncalls > 0) gl->ncalls--; 1572 } 1573 1574 static void glnvg__renderStroke(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, 1575 float strokeWidth, const NVGpath* paths, int npaths) 1576 { 1577 GLNVGcontext* gl = (GLNVGcontext*)uptr; 1578 GLNVGcall* call = glnvg__allocCall(gl); 1579 int i, maxverts, offset; 1580 1581 if (call == NULL) return; 1582 1583 call->type = GLNVG_STROKE; 1584 call->pathOffset = glnvg__allocPaths(gl, npaths); 1585 if (call->pathOffset == -1) goto error; 1586 call->pathCount = npaths; 1587 call->image = paint->image; 1588 call->blendFunc = glnvg__blendCompositeOperation(compositeOperation); 1589 1590 // Allocate vertices for all the paths. 1591 maxverts = glnvg__maxVertCount(paths, npaths); 1592 offset = glnvg__allocVerts(gl, maxverts); 1593 if (offset == -1) goto error; 1594 1595 for (i = 0; i < npaths; i++) { 1596 GLNVGpath* copy = &gl->paths[call->pathOffset + i]; 1597 const NVGpath* path = &paths[i]; 1598 memset(copy, 0, sizeof(GLNVGpath)); 1599 if (path->nstroke) { 1600 copy->strokeOffset = offset; 1601 copy->strokeCount = path->nstroke; 1602 memcpy(&gl->verts[offset], path->stroke, sizeof(NVGvertex) * path->nstroke); 1603 offset += path->nstroke; 1604 } 1605 } 1606 1607 if (gl->flags & NVG_STENCIL_STROKES) { 1608 // Fill shader 1609 call->uniformOffset = glnvg__allocFragUniforms(gl, 2); 1610 if (call->uniformOffset == -1) goto error; 1611 1612 glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset), paint, scissor, strokeWidth, fringe, -1.0f); 1613 glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset + gl->fragSize), paint, scissor, strokeWidth, fringe, 1.0f - 0.5f/255.0f); 1614 1615 } else { 1616 // Fill shader 1617 call->uniformOffset = glnvg__allocFragUniforms(gl, 1); 1618 if (call->uniformOffset == -1) goto error; 1619 glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset), paint, scissor, strokeWidth, fringe, -1.0f); 1620 } 1621 1622 return; 1623 1624 error: 1625 // We get here if call alloc was ok, but something else is not. 1626 // Roll back the last call to prevent drawing it. 1627 if (gl->ncalls > 0) gl->ncalls--; 1628 } 1629 1630 static void glnvg__renderTriangles(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, 1631 const NVGvertex* verts, int nverts, float fringe) 1632 { 1633 GLNVGcontext* gl = (GLNVGcontext*)uptr; 1634 GLNVGcall* call = glnvg__allocCall(gl); 1635 GLNVGfragUniforms* frag; 1636 1637 if (call == NULL) return; 1638 1639 call->type = GLNVG_TRIANGLES; 1640 call->image = paint->image; 1641 call->blendFunc = glnvg__blendCompositeOperation(compositeOperation); 1642 1643 // Allocate vertices for all the paths. 1644 call->triangleOffset = glnvg__allocVerts(gl, nverts); 1645 if (call->triangleOffset == -1) goto error; 1646 call->triangleCount = nverts; 1647 1648 memcpy(&gl->verts[call->triangleOffset], verts, sizeof(NVGvertex) * nverts); 1649 1650 // Fill shader 1651 call->uniformOffset = glnvg__allocFragUniforms(gl, 1); 1652 if (call->uniformOffset == -1) goto error; 1653 frag = nvg__fragUniformPtr(gl, call->uniformOffset); 1654 glnvg__convertPaint(gl, frag, paint, scissor, 1.0f, fringe, -1.0f); 1655 frag->type = NSVG_SHADER_IMG; 1656 1657 return; 1658 1659 error: 1660 // We get here if call alloc was ok, but something else is not. 1661 // Roll back the last call to prevent drawing it. 1662 if (gl->ncalls > 0) gl->ncalls--; 1663 } 1664 1665 static void glnvg__renderDelete(void* uptr) 1666 { 1667 GLNVGcontext* gl = (GLNVGcontext*)uptr; 1668 int i; 1669 if (gl == NULL) return; 1670 1671 glnvg__deleteShader(&gl->shader); 1672 1673 #if NANOVG_GL3 1674 #if NANOVG_GL_USE_UNIFORMBUFFER 1675 if (gl->fragBuf != 0) 1676 glDeleteBuffers(1, &gl->fragBuf); 1677 #endif 1678 if (gl->vertArr != 0) 1679 glDeleteVertexArrays(1, &gl->vertArr); 1680 #endif 1681 if (gl->vertBuf != 0) 1682 glDeleteBuffers(1, &gl->vertBuf); 1683 1684 if (gl->textureContext != NULL && --gl->textureContext->refCount == 0) { 1685 for (i = 0; i < gl->textureContext->ntextures; i++) { 1686 if (gl->textureContext->textures[i].tex != 0 && (gl->textureContext->textures[i].flags & NVG_IMAGE_NODELETE) == 0) 1687 glDeleteTextures(1, &gl->textureContext->textures[i].tex); 1688 } 1689 free(gl->textureContext->textures); 1690 free(gl->textureContext); 1691 } 1692 1693 free(gl->paths); 1694 free(gl->verts); 1695 free(gl->uniforms); 1696 free(gl->calls); 1697 1698 free(gl); 1699 } 1700 1701 1702 #if defined NANOVG_GL2 1703 NVGcontext* nvgCreateGL2(int flags) 1704 #elif defined NANOVG_GL3 1705 NVGcontext* nvgCreateGL3(int flags) 1706 #elif defined NANOVG_GLES2 1707 NVGcontext* nvgCreateGLES2(int flags) 1708 #elif defined NANOVG_GLES3 1709 NVGcontext* nvgCreateGLES3(int flags) 1710 #endif 1711 { 1712 #if defined NANOVG_GL2 1713 return nvgCreateSharedGL2(NULL, flags); 1714 #elif defined NANOVG_GL3 1715 return nvgCreateSharedGL3(NULL, flags); 1716 #elif defined NANOVG_GLES2 1717 return nvgCreateSharedGLES2(NULL, flags); 1718 #elif defined NANOVG_GLES3 1719 return nvgCreateSharedGLES3(NULL, flags); 1720 #endif 1721 } 1722 1723 // Share the fonts and textures of 'other' if it's non-NULL. 1724 #if defined NANOVG_GL2 1725 NVGcontext* nvgCreateSharedGL2(NVGcontext* other, int flags) 1726 #elif defined NANOVG_GL3 1727 NVGcontext* nvgCreateSharedGL3(NVGcontext* other, int flags) 1728 #elif defined NANOVG_GLES2 1729 NVGcontext* nvgCreateSharedGLES2(NVGcontext* other, int flags) 1730 #elif defined NANOVG_GLES3 1731 NVGcontext* nvgCreateSharedGLES3(NVGcontext* other, int flags) 1732 #endif 1733 { 1734 NVGparams params; 1735 NVGcontext* ctx = NULL; 1736 GLNVGcontext* gl = (GLNVGcontext*)malloc(sizeof(GLNVGcontext)); 1737 if (gl == NULL) goto error; 1738 memset(gl, 0, sizeof(GLNVGcontext)); 1739 1740 memset(¶ms, 0, sizeof(params)); 1741 params.renderCreate = glnvg__renderCreate; 1742 params.renderCreateTexture = glnvg__renderCreateTexture; 1743 params.renderDeleteTexture = glnvg__renderDeleteTexture; 1744 params.renderUpdateTexture = glnvg__renderUpdateTexture; 1745 params.renderGetTextureSize = glnvg__renderGetTextureSize; 1746 params.renderViewport = glnvg__renderViewport; 1747 params.renderCancel = glnvg__renderCancel; 1748 params.renderFlush = glnvg__renderFlush; 1749 params.renderFill = glnvg__renderFill; 1750 params.renderStroke = glnvg__renderStroke; 1751 params.renderTriangles = glnvg__renderTriangles; 1752 params.renderDelete = glnvg__renderDelete; 1753 params.userPtr = gl; 1754 params.edgeAntiAlias = flags & NVG_ANTIALIAS ? 1 : 0; 1755 1756 gl->flags = flags; 1757 1758 ctx = nvgCreateInternal(¶ms, other); 1759 if (ctx == NULL) goto error; 1760 1761 return ctx; 1762 1763 error: 1764 // 'gl' is freed by nvgDeleteInternal. 1765 if (ctx != NULL) nvgDeleteInternal(ctx); 1766 return NULL; 1767 } 1768 1769 #if defined NANOVG_GL2 1770 void nvgDeleteGL2(NVGcontext* ctx) 1771 #elif defined NANOVG_GL3 1772 void nvgDeleteGL3(NVGcontext* ctx) 1773 #elif defined NANOVG_GLES2 1774 void nvgDeleteGLES2(NVGcontext* ctx) 1775 #elif defined NANOVG_GLES3 1776 void nvgDeleteGLES3(NVGcontext* ctx) 1777 #endif 1778 { 1779 nvgDeleteInternal(ctx); 1780 } 1781 1782 #if defined NANOVG_GL2 1783 int nvglCreateImageFromHandleGL2(NVGcontext* ctx, GLuint textureId, int w, int h, int imageFlags) 1784 #elif defined NANOVG_GL3 1785 int nvglCreateImageFromHandleGL3(NVGcontext* ctx, GLuint textureId, int w, int h, int imageFlags) 1786 #elif defined NANOVG_GLES2 1787 int nvglCreateImageFromHandleGLES2(NVGcontext* ctx, GLuint textureId, int w, int h, int imageFlags) 1788 #elif defined NANOVG_GLES3 1789 int nvglCreateImageFromHandleGLES3(NVGcontext* ctx, GLuint textureId, int w, int h, int imageFlags) 1790 #endif 1791 { 1792 GLNVGcontext* gl = (GLNVGcontext*)nvgInternalParams(ctx)->userPtr; 1793 GLNVGtexture* tex = glnvg__allocTexture(gl); 1794 1795 if (tex == NULL) return 0; 1796 1797 tex->type = NVG_TEXTURE_RGBA; 1798 tex->tex = textureId; 1799 tex->flags = imageFlags; 1800 tex->width = w; 1801 tex->height = h; 1802 1803 return tex->id; 1804 } 1805 1806 #if defined NANOVG_GL2 1807 GLuint nvglImageHandleGL2(NVGcontext* ctx, int image) 1808 #elif defined NANOVG_GL3 1809 GLuint nvglImageHandleGL3(NVGcontext* ctx, int image) 1810 #elif defined NANOVG_GLES2 1811 GLuint nvglImageHandleGLES2(NVGcontext* ctx, int image) 1812 #elif defined NANOVG_GLES3 1813 GLuint nvglImageHandleGLES3(NVGcontext* ctx, int image) 1814 #endif 1815 { 1816 GLNVGcontext* gl = (GLNVGcontext*)nvgInternalParams(ctx)->userPtr; 1817 GLNVGtexture* tex = glnvg__findTexture(gl, image); 1818 return tex->tex; 1819 } 1820 1821 #endif /* NANOVG_GL_IMPLEMENTATION */