1 /*
2 * Copyright 2011-2019 Branimir Karadzic. All rights reserved.
3 * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
4 */
5
6 //
7 // Copyright (c) 2009-2013 Mikko Mononen memon@inside.org
8 //
9 // This software is provided 'as-is', without any express or implied
10 // warranty. In no event will the authors be held liable for any damages
11 // arising from the use of this software.
12 // Permission is granted to anyone to use this software for any purpose,
13 // including commercial applications, and to alter it and redistribute it
14 // freely, subject to the following restrictions:
15 // 1. The origin of this software must not be misrepresented; you must not
16 // claim that you wrote the original software. If you use this software
17 // in a product, an acknowledgment in the product documentation would be
18 // appreciated but is not required.
19 // 2. Altered source versions must be plainly marked as such, and must not be
20 // misrepresented as being the original software.
21 // 3. This notice may not be removed or altered from any source distribution.
22 //
23 #define NVG_ANTIALIAS 1
24
25 #include <stdlib.h>
26 #include <math.h>
27 #include "nanovg.h"
28
29 #include <bgfx/bgfx.h>
30 #include <bgfx/embedded_shader.h>
31
32 #include <bx/bx.h>
33 #include <bx/allocator.h>
34 #include <bx/uint32_t.h>
35
36 BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4244); // warning C4244: '=' : conversion from '' to '', possible loss of data
37
38 #include "vs_nanovg_fill.bin.h"
39 #include "fs_nanovg_fill.bin.h"
40
41 static const bgfx::EmbeddedShader s_embeddedShaders[] =
42 {
43 BGFX_EMBEDDED_SHADER(vs_nanovg_fill),
44 BGFX_EMBEDDED_SHADER(fs_nanovg_fill),
45
46 BGFX_EMBEDDED_SHADER_END()
47 };
48
49 namespace
50 {
51 static bgfx::VertexLayout s_nvgLayout;
52
53 enum GLNVGshaderType
54 {
55 NSVG_SHADER_FILLGRAD,
56 NSVG_SHADER_FILLIMG,
57 NSVG_SHADER_SIMPLE,
58 NSVG_SHADER_IMG
59 };
60
61 // These are additional flags on top of NVGimageFlags.
62 enum NVGimageFlagsGL {
63 NVG_IMAGE_NODELETE = 1<<16, // Do not delete GL texture handle.
64 };
65
66 struct GLNVGtexture
67 {
68 bgfx::TextureHandle id;
69 int width, height;
70 int type;
71 int flags;
72 };
73
74 struct GLNVGblend
75 {
76 uint64_t srcRGB;
77 uint64_t dstRGB;
78 uint64_t srcAlpha;
79 uint64_t dstAlpha;
80 };
81
82 enum GLNVGcallType
83 {
84 GLNVG_FILL,
85 GLNVG_CONVEXFILL,
86 GLNVG_STROKE,
87 GLNVG_TRIANGLES,
88 };
89
90 struct GLNVGcall
91 {
92 int type;
93 int image;
94 int pathOffset;
95 int pathCount;
96 int vertexOffset;
97 int vertexCount;
98 int uniformOffset;
99 GLNVGblend blendFunc;
100 };
101
102 struct GLNVGpath
103 {
104 int fillOffset;
105 int fillCount;
106 int strokeOffset;
107 int strokeCount;
108 };
109
110 struct GLNVGfragUniforms
111 {
112 float scissorMat[12]; // matrices are actually 3 vec4s
113 float paintMat[12];
114 NVGcolor innerCol;
115 NVGcolor outerCol;
116
117 // u_scissorExtScale
118 float scissorExt[2];
119 float scissorScale[2];
120
121 // u_extentRadius
122 float extent[2];
123 float radius;
124
125 // u_params
126 float feather;
127 float strokeMult;
128 float texType;
129 float type;
130 };
131
132 struct GLNVGcontext
133 {
134 bx::AllocatorI* allocator;
135
136 bgfx::ProgramHandle prog;
137 bgfx::UniformHandle u_scissorMat;
138 bgfx::UniformHandle u_paintMat;
139 bgfx::UniformHandle u_innerCol;
140 bgfx::UniformHandle u_outerCol;
141 bgfx::UniformHandle u_viewSize;
142 bgfx::UniformHandle u_scissorExtScale;
143 bgfx::UniformHandle u_extentRadius;
144 bgfx::UniformHandle u_params;
145 bgfx::UniformHandle u_halfTexel;
146
147 bgfx::UniformHandle s_tex;
148
149 uint64_t state;
150 bgfx::TextureHandle th;
151 bgfx::TextureHandle texMissing;
152
153 bgfx::TransientVertexBuffer tvb;
154 bgfx::ViewId viewId;
155
156 struct GLNVGtexture* textures;
157 float view[2];
158 int ntextures;
159 int ctextures;
160 int textureId;
161 int vertBuf;
162 int fragSize;
163 int edgeAntiAlias;
164
165 // Per frame buffers
166 struct GLNVGcall* calls;
167 int ccalls;
168 int ncalls;
169 struct GLNVGpath* paths;
170 int cpaths;
171 int npaths;
172 struct NVGvertex* verts;
173 int cverts;
174 int nverts;
175 unsigned char* uniforms;
176 int cuniforms;
177 int nuniforms;
178 };
179
glnvg__allocTexture(struct GLNVGcontext * gl)180 static struct GLNVGtexture* glnvg__allocTexture(struct GLNVGcontext* gl)
181 {
182 struct GLNVGtexture* tex = NULL;
183 int i;
184
185 for (i = 0; i < gl->ntextures; i++)
186 {
187 if (gl->textures[i].id.idx == bgfx::kInvalidHandle)
188 {
189 tex = &gl->textures[i];
190 break;
191 }
192 }
193
194 if (tex == NULL)
195 {
196 if (gl->ntextures+1 > gl->ctextures)
197 {
198 int old = gl->ctextures;
199 gl->ctextures = (gl->ctextures == 0) ? 2 : gl->ctextures*2;
200 gl->textures = (struct GLNVGtexture*)BX_REALLOC(gl->allocator, gl->textures, sizeof(struct GLNVGtexture)*gl->ctextures);
201 bx::memSet(&gl->textures[old], 0xff, (gl->ctextures-old)*sizeof(struct GLNVGtexture) );
202
203 if (gl->textures == NULL)
204 {
205 return NULL;
206 }
207 }
208 tex = &gl->textures[gl->ntextures++];
209 }
210
211 bx::memSet(tex, 0, sizeof(*tex) );
212
213 return tex;
214 }
215
glnvg__findTexture(struct GLNVGcontext * gl,int id)216 static struct GLNVGtexture* glnvg__findTexture(struct GLNVGcontext* gl, int id)
217 {
218 int i;
219 for (i = 0; i < gl->ntextures; i++)
220 {
221 if (gl->textures[i].id.idx == id)
222 {
223 return &gl->textures[i];
224 }
225 }
226
227 return NULL;
228 }
229
glnvg__deleteTexture(struct GLNVGcontext * gl,int id)230 static int glnvg__deleteTexture(struct GLNVGcontext* gl, int id)
231 {
232 for (int ii = 0; ii < gl->ntextures; ii++)
233 {
234 if (gl->textures[ii].id.idx == id)
235 {
236 if (bgfx::isValid(gl->textures[ii].id)
237 && (gl->textures[ii].flags & NVG_IMAGE_NODELETE) == 0)
238 {
239 bgfx::destroy(gl->textures[ii].id);
240 }
241 bx::memSet(&gl->textures[ii], 0, sizeof(gl->textures[ii]) );
242 gl->textures[ii].id.idx = bgfx::kInvalidHandle;
243 return 1;
244 }
245 }
246
247 return 0;
248 }
249
nvgRenderCreate(void * _userPtr)250 static int nvgRenderCreate(void* _userPtr)
251 {
252 struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr;
253
254 bgfx::RendererType::Enum type = bgfx::getRendererType();
255 gl->prog = bgfx::createProgram(
256 bgfx::createEmbeddedShader(s_embeddedShaders, type, "vs_nanovg_fill")
257 , bgfx::createEmbeddedShader(s_embeddedShaders, type, "fs_nanovg_fill")
258 , true
259 );
260
261 const bgfx::Memory* mem = bgfx::alloc(4*4*4);
262 uint32_t* bgra8 = (uint32_t*)mem->data;
263 bx::memSet(bgra8, 0, 4*4*4);
264 gl->texMissing = bgfx::createTexture2D(4, 4, false, 1, bgfx::TextureFormat::BGRA8, 0, mem);
265
266 gl->u_scissorMat = bgfx::createUniform("u_scissorMat", bgfx::UniformType::Mat3);
267 gl->u_paintMat = bgfx::createUniform("u_paintMat", bgfx::UniformType::Mat3);
268 gl->u_innerCol = bgfx::createUniform("u_innerCol", bgfx::UniformType::Vec4);
269 gl->u_outerCol = bgfx::createUniform("u_outerCol", bgfx::UniformType::Vec4);
270 gl->u_viewSize = bgfx::createUniform("u_viewSize", bgfx::UniformType::Vec4);
271 gl->u_scissorExtScale = bgfx::createUniform("u_scissorExtScale", bgfx::UniformType::Vec4);
272 gl->u_extentRadius = bgfx::createUniform("u_extentRadius", bgfx::UniformType::Vec4);
273 gl->u_params = bgfx::createUniform("u_params", bgfx::UniformType::Vec4);
274 gl->s_tex = bgfx::createUniform("s_tex", bgfx::UniformType::Sampler);
275
276 if (bgfx::getRendererType() == bgfx::RendererType::Direct3D9)
277 {
278 gl->u_halfTexel = bgfx::createUniform("u_halfTexel", bgfx::UniformType::Vec4);
279 }
280 else
281 {
282 gl->u_halfTexel.idx = bgfx::kInvalidHandle;
283 }
284
285 s_nvgLayout
286 .begin()
287 .add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
288 .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
289 .end();
290
291 int align = 16;
292 gl->fragSize = sizeof(struct GLNVGfragUniforms) + align - sizeof(struct GLNVGfragUniforms) % align;
293
294 return 1;
295 }
296
nvgRenderCreateTexture(void * _userPtr,int _type,int _width,int _height,int _flags,const unsigned char * _rgba)297 static int nvgRenderCreateTexture(
298 void* _userPtr
299 , int _type
300 , int _width
301 , int _height
302 , int _flags
303 , const unsigned char* _rgba
304 )
305 {
306 struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr;
307 struct GLNVGtexture* tex = glnvg__allocTexture(gl);
308
309 if (tex == NULL)
310 {
311 return 0;
312 }
313
314 tex->width = _width;
315 tex->height = _height;
316 tex->type = _type;
317 tex->flags = _flags;
318
319 uint32_t bytesPerPixel = NVG_TEXTURE_RGBA == tex->type ? 4 : 1;
320 uint32_t pitch = tex->width * bytesPerPixel;
321
322 const bgfx::Memory* mem = NULL;
323 if (NULL != _rgba)
324 {
325 mem = bgfx::copy(_rgba, tex->height * pitch);
326 }
327
328 tex->id = bgfx::createTexture2D(
329 tex->width
330 , tex->height
331 , false
332 , 1
333 , NVG_TEXTURE_RGBA == _type ? bgfx::TextureFormat::RGBA8 : bgfx::TextureFormat::R8
334 , BGFX_SAMPLER_NONE
335 );
336
337 if (NULL != mem)
338 {
339 bgfx::updateTexture2D(
340 tex->id
341 , 0
342 , 0
343 , 0
344 , 0
345 , tex->width
346 , tex->height
347 , mem
348 );
349 }
350
351 return bgfx::isValid(tex->id) ? tex->id.idx : 0;
352 }
353
nvgRenderDeleteTexture(void * _userPtr,int image)354 static int nvgRenderDeleteTexture(void* _userPtr, int image)
355 {
356 struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr;
357 return glnvg__deleteTexture(gl, image);
358 }
359
nvgRenderUpdateTexture(void * _userPtr,int image,int x,int y,int w,int h,const unsigned char * data)360 static int nvgRenderUpdateTexture(void* _userPtr, int image, int x, int y, int w, int h, const unsigned char* data)
361 {
362 struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr;
363 struct GLNVGtexture* tex = glnvg__findTexture(gl, image);
364 if (tex == NULL)
365 {
366 return 0;
367 }
368
369 uint32_t bytesPerPixel = NVG_TEXTURE_RGBA == tex->type ? 4 : 1;
370 uint32_t pitch = tex->width * bytesPerPixel;
371
372 const bgfx::Memory* mem = bgfx::alloc(w * h * bytesPerPixel);
373 bx::gather(mem->data, // dst
374 data + y * pitch + x * bytesPerPixel, // src
375 pitch, // srcStride
376 w * bytesPerPixel, // stride
377 h); // num
378
379 bgfx::updateTexture2D(
380 tex->id
381 , 0
382 , 0
383 , x
384 , y
385 , w
386 , h
387 , mem
388 , UINT16_MAX
389 );
390
391 return 1;
392 }
393
nvgRenderGetTextureSize(void * _userPtr,int image,int * w,int * h)394 static int nvgRenderGetTextureSize(void* _userPtr, int image, int* w, int* h)
395 {
396 struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr;
397 struct GLNVGtexture* tex = glnvg__findTexture(gl, image);
398
399 if (NULL == tex
400 || !bgfx::isValid(tex->id) )
401 {
402 return 0;
403 }
404
405 *w = tex->width;
406 *h = tex->height;
407
408 return 1;
409 }
410
glnvg__xformToMat3x4(float * m3,float * t)411 static void glnvg__xformToMat3x4(float* m3, float* t)
412 {
413 m3[ 0] = t[0];
414 m3[ 1] = t[1];
415 m3[ 2] = 0.0f;
416 m3[ 3] = 0.0f;
417 m3[ 4] = t[2];
418 m3[ 5] = t[3];
419 m3[ 6] = 0.0f;
420 m3[ 7] = 0.0f;
421 m3[ 8] = t[4];
422 m3[ 9] = t[5];
423 m3[10] = 1.0f;
424 m3[11] = 0.0f;
425 }
426
glnvg__premulColor(NVGcolor c)427 static NVGcolor glnvg__premulColor(NVGcolor c)
428 {
429 c.r *= c.a;
430 c.g *= c.a;
431 c.b *= c.a;
432 return c;
433 }
434
glnvg__convertPaint(struct GLNVGcontext * gl,struct GLNVGfragUniforms * frag,struct NVGpaint * paint,struct NVGscissor * scissor,float width,float fringe)435 static int glnvg__convertPaint(
436 struct GLNVGcontext* gl
437 , struct GLNVGfragUniforms* frag
438 , struct NVGpaint* paint
439 , struct NVGscissor* scissor
440 , float width
441 , float fringe
442 )
443 {
444 struct GLNVGtexture* tex = NULL;
445 float invxform[6] = {};
446
447 bx::memSet(frag, 0, sizeof(*frag) );
448
449 frag->innerCol = glnvg__premulColor(paint->innerColor);
450 frag->outerCol = glnvg__premulColor(paint->outerColor);
451
452 if (scissor->extent[0] < -0.5f || scissor->extent[1] < -0.5f)
453 {
454 bx::memSet(frag->scissorMat, 0, sizeof(frag->scissorMat) );
455 frag->scissorExt[0] = 1.0f;
456 frag->scissorExt[1] = 1.0f;
457 frag->scissorScale[0] = 1.0f;
458 frag->scissorScale[1] = 1.0f;
459 }
460 else
461 {
462 nvgTransformInverse(invxform, scissor->xform);
463 glnvg__xformToMat3x4(frag->scissorMat, invxform);
464 frag->scissorExt[0] = scissor->extent[0];
465 frag->scissorExt[1] = scissor->extent[1];
466 frag->scissorScale[0] = sqrtf(scissor->xform[0]*scissor->xform[0] + scissor->xform[2]*scissor->xform[2]) / fringe;
467 frag->scissorScale[1] = sqrtf(scissor->xform[1]*scissor->xform[1] + scissor->xform[3]*scissor->xform[3]) / fringe;
468 }
469 bx::memCopy(frag->extent, paint->extent, sizeof(frag->extent) );
470 frag->strokeMult = (width*0.5f + fringe*0.5f) / fringe;
471
472 gl->th = gl->texMissing;
473 if (paint->image != 0)
474 {
475 tex = glnvg__findTexture(gl, paint->image);
476 if (tex == NULL)
477 {
478 return 0;
479 }
480 nvgTransformInverse(invxform, paint->xform);
481 frag->type = NSVG_SHADER_FILLIMG;
482
483 if (tex->type == NVG_TEXTURE_RGBA)
484 {
485 frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0.0f : 1.0f;
486 }
487 else
488 {
489 frag->texType = 2.0f;
490 }
491 gl->th = tex->id;
492 }
493 else
494 {
495 frag->type = NSVG_SHADER_FILLGRAD;
496 frag->radius = paint->radius;
497 frag->feather = paint->feather;
498 nvgTransformInverse(invxform, paint->xform);
499 }
500
501 glnvg__xformToMat3x4(frag->paintMat, invxform);
502
503 return 1;
504 }
505
glnvg__mat3(float * dst,float * src)506 static void glnvg__mat3(float* dst, float* src)
507 {
508 dst[0] = src[ 0];
509 dst[1] = src[ 1];
510 dst[2] = src[ 2];
511
512 dst[3] = src[ 4];
513 dst[4] = src[ 5];
514 dst[5] = src[ 6];
515
516 dst[6] = src[ 8];
517 dst[7] = src[ 9];
518 dst[8] = src[10];
519 }
520
nvg__fragUniformPtr(struct GLNVGcontext * gl,int i)521 static struct GLNVGfragUniforms* nvg__fragUniformPtr(struct GLNVGcontext* gl, int i)
522 {
523 return (struct GLNVGfragUniforms*)&gl->uniforms[i];
524 }
525
nvgRenderSetUniforms(struct GLNVGcontext * gl,int uniformOffset,int image)526 static void nvgRenderSetUniforms(struct GLNVGcontext* gl, int uniformOffset, int image)
527 {
528 struct GLNVGfragUniforms* frag = nvg__fragUniformPtr(gl, uniformOffset);
529 float tmp[9]; // Maybe there's a way to get rid of this...
530 glnvg__mat3(tmp, frag->scissorMat);
531 bgfx::setUniform(gl->u_scissorMat, tmp);
532 glnvg__mat3(tmp, frag->paintMat);
533 bgfx::setUniform(gl->u_paintMat, tmp);
534
535 bgfx::setUniform(gl->u_innerCol, frag->innerCol.rgba);
536 bgfx::setUniform(gl->u_outerCol, frag->outerCol.rgba);
537 bgfx::setUniform(gl->u_scissorExtScale, &frag->scissorExt[0]);
538 bgfx::setUniform(gl->u_extentRadius, &frag->extent[0]);
539 bgfx::setUniform(gl->u_params, &frag->feather);
540
541 bgfx::TextureHandle handle = gl->texMissing;
542
543 if (image != 0)
544 {
545 struct GLNVGtexture* tex = glnvg__findTexture(gl, image);
546 if (tex != NULL)
547 {
548 handle = tex->id;
549
550 if (bgfx::isValid(gl->u_halfTexel) )
551 {
552 float halfTexel[4] = { 0.5f / tex->width, 0.5f / tex->height };
553 bgfx::setUniform(gl->u_halfTexel, halfTexel);
554 }
555 }
556 }
557
558 gl->th = handle;
559 }
560
nvgRenderViewport(void * _userPtr,float width,float height,float devicePixelRatio)561 static void nvgRenderViewport(void* _userPtr, float width, float height, float devicePixelRatio)
562 {
563 struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr;
564 gl->view[0] = width;
565 gl->view[1] = height;
566 bgfx::setViewRect(gl->viewId, 0, 0, width * devicePixelRatio, height * devicePixelRatio);
567 }
568
fan(uint32_t _start,uint32_t _count)569 static void fan(uint32_t _start, uint32_t _count)
570 {
571 uint32_t numTris = _count-2;
572 bgfx::TransientIndexBuffer tib;
573 bgfx::allocTransientIndexBuffer(&tib, numTris*3);
574 uint16_t* data = (uint16_t*)tib.data;
575 for (uint32_t ii = 0; ii < numTris; ++ii)
576 {
577 data[ii*3+0] = _start;
578 data[ii*3+1] = _start + ii + 1;
579 data[ii*3+2] = _start + ii + 2;
580 }
581
582 bgfx::setIndexBuffer(&tib);
583 }
584
glnvg__fill(struct GLNVGcontext * gl,struct GLNVGcall * call)585 static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call)
586 {
587 struct GLNVGpath* paths = &gl->paths[call->pathOffset];
588 int i, npaths = call->pathCount;
589
590 // set bindpoint for solid loc
591 nvgRenderSetUniforms(gl, call->uniformOffset, 0);
592
593 for (i = 0; i < npaths; i++)
594 {
595 if (2 < paths[i].fillCount)
596 {
597 bgfx::setState(0);
598 bgfx::setStencil(0
599 | BGFX_STENCIL_TEST_ALWAYS
600 | BGFX_STENCIL_FUNC_RMASK(0xff)
601 | BGFX_STENCIL_OP_FAIL_S_KEEP
602 | BGFX_STENCIL_OP_FAIL_Z_KEEP
603 | BGFX_STENCIL_OP_PASS_Z_INCR
604 , 0
605 | BGFX_STENCIL_TEST_ALWAYS
606 | BGFX_STENCIL_FUNC_RMASK(0xff)
607 | BGFX_STENCIL_OP_FAIL_S_KEEP
608 | BGFX_STENCIL_OP_FAIL_Z_KEEP
609 | BGFX_STENCIL_OP_PASS_Z_DECR
610 );
611 bgfx::setVertexBuffer(0, &gl->tvb);
612 bgfx::setTexture(0, gl->s_tex, gl->th);
613 fan(paths[i].fillOffset, paths[i].fillCount);
614 bgfx::submit(gl->viewId, gl->prog);
615 }
616 }
617
618 // Draw aliased off-pixels
619 nvgRenderSetUniforms(gl, call->uniformOffset + gl->fragSize, call->image);
620
621 if (gl->edgeAntiAlias)
622 {
623 // Draw fringes
624 for (i = 0; i < npaths; i++)
625 {
626 bgfx::setState(gl->state
627 | BGFX_STATE_PT_TRISTRIP
628 );
629 bgfx::setStencil(0
630 | BGFX_STENCIL_TEST_EQUAL
631 | BGFX_STENCIL_FUNC_RMASK(0xff)
632 | BGFX_STENCIL_OP_FAIL_S_KEEP
633 | BGFX_STENCIL_OP_FAIL_Z_KEEP
634 | BGFX_STENCIL_OP_PASS_Z_KEEP
635 );
636 bgfx::setVertexBuffer(0, &gl->tvb, paths[i].strokeOffset, paths[i].strokeCount);
637 bgfx::setTexture(0, gl->s_tex, gl->th);
638 bgfx::submit(gl->viewId, gl->prog);
639 }
640 }
641
642 // Draw fill
643 bgfx::setState(gl->state);
644 bgfx::setVertexBuffer(0, &gl->tvb, call->vertexOffset, call->vertexCount);
645 bgfx::setTexture(0, gl->s_tex, gl->th);
646 bgfx::setStencil(0
647 | BGFX_STENCIL_TEST_NOTEQUAL
648 | BGFX_STENCIL_FUNC_RMASK(0xff)
649 | BGFX_STENCIL_OP_FAIL_S_ZERO
650 | BGFX_STENCIL_OP_FAIL_Z_ZERO
651 | BGFX_STENCIL_OP_PASS_Z_ZERO
652 );
653 bgfx::submit(gl->viewId, gl->prog);
654 }
655
glnvg__convexFill(struct GLNVGcontext * gl,struct GLNVGcall * call)656 static void glnvg__convexFill(struct GLNVGcontext* gl, struct GLNVGcall* call)
657 {
658 struct GLNVGpath* paths = &gl->paths[call->pathOffset];
659 int i, npaths = call->pathCount;
660
661 nvgRenderSetUniforms(gl, call->uniformOffset, call->image);
662
663 for (i = 0; i < npaths; i++)
664 {
665 if (paths[i].fillCount == 0) continue;
666 bgfx::setState(gl->state);
667 bgfx::setVertexBuffer(0, &gl->tvb);
668 bgfx::setTexture(0, gl->s_tex, gl->th);
669 fan(paths[i].fillOffset, paths[i].fillCount);
670 bgfx::submit(gl->viewId, gl->prog);
671 }
672
673 if (gl->edgeAntiAlias)
674 {
675 // Draw fringes
676 for (i = 0; i < npaths; i++)
677 {
678 bgfx::setState(gl->state
679 | BGFX_STATE_PT_TRISTRIP
680 );
681 bgfx::setVertexBuffer(0, &gl->tvb, paths[i].strokeOffset, paths[i].strokeCount);
682 bgfx::setTexture(0, gl->s_tex, gl->th);
683 bgfx::submit(gl->viewId, gl->prog);
684 }
685 }
686 }
687
glnvg__stroke(struct GLNVGcontext * gl,struct GLNVGcall * call)688 static void glnvg__stroke(struct GLNVGcontext* gl, struct GLNVGcall* call)
689 {
690 struct GLNVGpath* paths = &gl->paths[call->pathOffset];
691 int npaths = call->pathCount, i;
692
693 nvgRenderSetUniforms(gl, call->uniformOffset, call->image);
694
695 // Draw Strokes
696 for (i = 0; i < npaths; i++)
697 {
698 bgfx::setState(gl->state
699 | BGFX_STATE_PT_TRISTRIP
700 );
701 bgfx::setVertexBuffer(0, &gl->tvb, paths[i].strokeOffset, paths[i].strokeCount);
702 bgfx::setTexture(0, gl->s_tex, gl->th);
703 bgfx::submit(gl->viewId, gl->prog);
704 }
705 }
706
glnvg__triangles(struct GLNVGcontext * gl,struct GLNVGcall * call)707 static void glnvg__triangles(struct GLNVGcontext* gl, struct GLNVGcall* call)
708 {
709 if (3 <= call->vertexCount)
710 {
711 nvgRenderSetUniforms(gl, call->uniformOffset, call->image);
712
713 bgfx::setState(gl->state);
714 bgfx::setVertexBuffer(0, &gl->tvb, call->vertexOffset, call->vertexCount);
715 bgfx::setTexture(0, gl->s_tex, gl->th);
716 bgfx::submit(gl->viewId, gl->prog);
717 }
718 }
719
720 static const uint64_t s_blend[] =
721 {
722 BGFX_STATE_BLEND_ZERO,
723 BGFX_STATE_BLEND_ONE,
724 BGFX_STATE_BLEND_SRC_COLOR,
725 BGFX_STATE_BLEND_INV_SRC_COLOR,
726 BGFX_STATE_BLEND_DST_COLOR,
727 BGFX_STATE_BLEND_INV_DST_COLOR,
728 BGFX_STATE_BLEND_SRC_ALPHA,
729 BGFX_STATE_BLEND_INV_SRC_ALPHA,
730 BGFX_STATE_BLEND_DST_ALPHA,
731 BGFX_STATE_BLEND_INV_DST_ALPHA,
732 BGFX_STATE_BLEND_SRC_ALPHA_SAT,
733 };
734
glnvg_convertBlendFuncFactor(int factor)735 static uint64_t glnvg_convertBlendFuncFactor(int factor)
736 {
737 const uint32_t numtz = bx::uint32_cnttz(factor);
738 const uint32_t idx = bx::uint32_min(numtz, BX_COUNTOF(s_blend)-1);
739 return s_blend[idx];
740 }
741
glnvg__blendCompositeOperation(NVGcompositeOperationState op)742 static GLNVGblend glnvg__blendCompositeOperation(NVGcompositeOperationState op)
743 {
744 GLNVGblend blend;
745 blend.srcRGB = glnvg_convertBlendFuncFactor(op.srcRGB);
746 blend.dstRGB = glnvg_convertBlendFuncFactor(op.dstRGB);
747 blend.srcAlpha = glnvg_convertBlendFuncFactor(op.srcAlpha);
748 blend.dstAlpha = glnvg_convertBlendFuncFactor(op.dstAlpha);
749 if (blend.srcRGB == BGFX_STATE_NONE || blend.dstRGB == BGFX_STATE_NONE || blend.srcAlpha == BGFX_STATE_NONE || blend.dstAlpha == BGFX_STATE_NONE)
750 {
751 blend.srcRGB = BGFX_STATE_BLEND_ONE;
752 blend.dstRGB = BGFX_STATE_BLEND_INV_SRC_ALPHA;
753 blend.srcAlpha = BGFX_STATE_BLEND_ONE;
754 blend.dstAlpha = BGFX_STATE_BLEND_INV_SRC_ALPHA;
755 }
756 return blend;
757 }
758
nvgRenderFlush(void * _userPtr)759 static void nvgRenderFlush(void* _userPtr)
760 {
761 struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr;
762
763 if (gl->ncalls > 0)
764 {
765 bgfx::allocTransientVertexBuffer(&gl->tvb, gl->nverts, s_nvgLayout);
766
767 int allocated = gl->tvb.size/gl->tvb.stride;
768
769 if (allocated < gl->nverts)
770 {
771 gl->nverts = allocated;
772 BX_WARN(true, "Vertex number truncated due to transient vertex buffer overflow");
773 }
774
775 bx::memCopy(gl->tvb.data, gl->verts, gl->nverts * sizeof(struct NVGvertex) );
776
777 bgfx::setUniform(gl->u_viewSize, gl->view);
778
779 for (uint32_t ii = 0, num = gl->ncalls; ii < num; ++ii)
780 {
781 struct GLNVGcall* call = &gl->calls[ii];
782 const GLNVGblend* blend = &call->blendFunc;
783 gl->state = BGFX_STATE_BLEND_FUNC_SEPARATE(blend->srcRGB, blend->dstRGB, blend->srcAlpha, blend->dstAlpha)
784 | BGFX_STATE_WRITE_RGB
785 | BGFX_STATE_WRITE_A
786 ;
787 switch (call->type)
788 {
789 case GLNVG_FILL:
790 glnvg__fill(gl, call);
791 break;
792
793 case GLNVG_CONVEXFILL:
794 glnvg__convexFill(gl, call);
795 break;
796
797 case GLNVG_STROKE:
798 glnvg__stroke(gl, call);
799 break;
800
801 case GLNVG_TRIANGLES:
802 glnvg__triangles(gl, call);
803 break;
804 }
805 }
806 }
807
808 // Reset calls
809 gl->nverts = 0;
810 gl->npaths = 0;
811 gl->ncalls = 0;
812 gl->nuniforms = 0;
813 }
814
glnvg__maxVertCount(const struct NVGpath * paths,int npaths)815 static int glnvg__maxVertCount(const struct NVGpath* paths, int npaths)
816 {
817 int i, count = 0;
818 for (i = 0; i < npaths; i++)
819 {
820 count += paths[i].nfill;
821 count += paths[i].nstroke;
822 }
823 return count;
824 }
825
glnvg__maxi(int a,int b)826 static int glnvg__maxi(int a, int b) { return a > b ? a : b; }
827
glnvg__allocCall(struct GLNVGcontext * gl)828 static struct GLNVGcall* glnvg__allocCall(struct GLNVGcontext* gl)
829 {
830 struct GLNVGcall* ret = NULL;
831 if (gl->ncalls+1 > gl->ccalls)
832 {
833 gl->ccalls = gl->ccalls == 0 ? 32 : gl->ccalls * 2;
834 gl->calls = (struct GLNVGcall*)BX_REALLOC(gl->allocator, gl->calls, sizeof(struct GLNVGcall) * gl->ccalls);
835 }
836 ret = &gl->calls[gl->ncalls++];
837 bx::memSet(ret, 0, sizeof(struct GLNVGcall) );
838 return ret;
839 }
840
glnvg__allocPaths(struct GLNVGcontext * gl,int n)841 static int glnvg__allocPaths(struct GLNVGcontext* gl, int n)
842 {
843 int ret = 0;
844 if (gl->npaths + n > gl->cpaths) {
845 GLNVGpath* paths;
846 int cpaths = glnvg__maxi(gl->npaths + n, 128) + gl->cpaths / 2; // 1.5x Overallocate
847 paths = (GLNVGpath*)BX_REALLOC(gl->allocator, gl->paths, sizeof(GLNVGpath) * cpaths);
848 if (paths == NULL) return -1;
849 gl->paths = paths;
850 gl->cpaths = cpaths;
851 }
852 ret = gl->npaths;
853 gl->npaths += n;
854 return ret;
855 }
856
glnvg__allocVerts(GLNVGcontext * gl,int n)857 static int glnvg__allocVerts(GLNVGcontext* gl, int n)
858 {
859 int ret = 0;
860 if (gl->nverts+n > gl->cverts)
861 {
862 NVGvertex* verts;
863 int cverts = glnvg__maxi(gl->nverts + n, 4096) + gl->cverts/2; // 1.5x Overallocate
864 verts = (NVGvertex*)BX_REALLOC(gl->allocator, gl->verts, sizeof(NVGvertex) * cverts);
865 if (verts == NULL) return -1;
866 gl->verts = verts;
867 gl->cverts = cverts;
868 }
869 ret = gl->nverts;
870 gl->nverts += n;
871 return ret;
872 }
873
glnvg__allocFragUniforms(struct GLNVGcontext * gl,int n)874 static int glnvg__allocFragUniforms(struct GLNVGcontext* gl, int n)
875 {
876 int ret = 0, structSize = gl->fragSize;
877 if (gl->nuniforms+n > gl->cuniforms)
878 {
879 gl->cuniforms = gl->cuniforms == 0 ? glnvg__maxi(n, 32) : gl->cuniforms * 2;
880 gl->uniforms = (unsigned char*)BX_REALLOC(gl->allocator, gl->uniforms, gl->cuniforms * structSize);
881 }
882 ret = gl->nuniforms * structSize;
883 gl->nuniforms += n;
884 return ret;
885 }
886
glnvg__vset(struct NVGvertex * vtx,float x,float y,float u,float v)887 static void glnvg__vset(struct NVGvertex* vtx, float x, float y, float u, float v)
888 {
889 vtx->x = x;
890 vtx->y = y;
891 vtx->u = u;
892 vtx->v = v;
893 }
894
nvgRenderFill(void * _userPtr,NVGpaint * paint,NVGcompositeOperationState compositeOperation,NVGscissor * scissor,float fringe,const float * bounds,const NVGpath * paths,int npaths)895 static void nvgRenderFill(
896 void* _userPtr
897 , NVGpaint* paint
898 , NVGcompositeOperationState compositeOperation
899 , NVGscissor* scissor
900 , float fringe
901 , const float* bounds
902 , const NVGpath* paths
903 , int npaths
904 )
905 {
906 struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr;
907
908 struct GLNVGcall* call = glnvg__allocCall(gl);
909 struct NVGvertex* quad;
910 struct GLNVGfragUniforms* frag;
911 int i, maxverts, offset;
912
913 call->type = GLNVG_FILL;
914 call->pathOffset = glnvg__allocPaths(gl, npaths);
915 call->pathCount = npaths;
916 call->image = paint->image;
917 call->blendFunc = glnvg__blendCompositeOperation(compositeOperation);
918
919 if (npaths == 1 && paths[0].convex)
920 {
921 call->type = GLNVG_CONVEXFILL;
922 }
923
924 // Allocate vertices for all the paths.
925 maxverts = glnvg__maxVertCount(paths, npaths) + 6;
926 offset = glnvg__allocVerts(gl, maxverts);
927
928 for (i = 0; i < npaths; i++)
929 {
930 struct GLNVGpath* copy = &gl->paths[call->pathOffset + i];
931 const struct NVGpath* path = &paths[i];
932 bx::memSet(copy, 0, sizeof(struct GLNVGpath) );
933 if (path->nfill > 0)
934 {
935 copy->fillOffset = offset;
936 copy->fillCount = path->nfill;
937 bx::memCopy(&gl->verts[offset], path->fill, sizeof(struct NVGvertex) * path->nfill);
938 offset += path->nfill;
939 }
940
941 if (path->nstroke > 0)
942 {
943 copy->strokeOffset = offset;
944 copy->strokeCount = path->nstroke;
945 bx::memCopy(&gl->verts[offset], path->stroke, sizeof(struct NVGvertex) * path->nstroke);
946 offset += path->nstroke;
947 }
948 }
949
950 // Quad
951 call->vertexOffset = offset;
952 call->vertexCount = 6;
953 quad = &gl->verts[call->vertexOffset];
954 glnvg__vset(&quad[0], bounds[0], bounds[3], 0.5f, 1.0f);
955 glnvg__vset(&quad[1], bounds[2], bounds[3], 0.5f, 1.0f);
956 glnvg__vset(&quad[2], bounds[2], bounds[1], 0.5f, 1.0f);
957
958 glnvg__vset(&quad[3], bounds[0], bounds[3], 0.5f, 1.0f);
959 glnvg__vset(&quad[4], bounds[2], bounds[1], 0.5f, 1.0f);
960 glnvg__vset(&quad[5], bounds[0], bounds[1], 0.5f, 1.0f);
961
962 // Setup uniforms for draw calls
963 if (call->type == GLNVG_FILL)
964 {
965 call->uniformOffset = glnvg__allocFragUniforms(gl, 2);
966 // Simple shader for stencil
967 frag = nvg__fragUniformPtr(gl, call->uniformOffset);
968 bx::memSet(frag, 0, sizeof(*frag) );
969 frag->type = NSVG_SHADER_SIMPLE;
970 // Fill shader
971 glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset + gl->fragSize), paint, scissor, fringe, fringe);
972 }
973 else
974 {
975 call->uniformOffset = glnvg__allocFragUniforms(gl, 1);
976 // Fill shader
977 glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset), paint, scissor, fringe, fringe);
978 }
979 }
980
nvgRenderStroke(void * _userPtr,struct NVGpaint * paint,NVGcompositeOperationState compositeOperation,struct NVGscissor * scissor,float fringe,float strokeWidth,const struct NVGpath * paths,int npaths)981 static void nvgRenderStroke(
982 void* _userPtr
983 , struct NVGpaint* paint
984 , NVGcompositeOperationState compositeOperation
985 , struct NVGscissor* scissor
986 , float fringe
987 , float strokeWidth
988 , const struct NVGpath* paths
989 , int npaths
990 )
991 {
992 struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr;
993
994 struct GLNVGcall* call = glnvg__allocCall(gl);
995 int i, maxverts, offset;
996
997 call->type = GLNVG_STROKE;
998 call->pathOffset = glnvg__allocPaths(gl, npaths);
999 call->pathCount = npaths;
1000 call->image = paint->image;
1001 call->blendFunc = glnvg__blendCompositeOperation(compositeOperation);
1002
1003 // Allocate vertices for all the paths.
1004 maxverts = glnvg__maxVertCount(paths, npaths);
1005 offset = glnvg__allocVerts(gl, maxverts);
1006
1007 for (i = 0; i < npaths; i++)
1008 {
1009 struct GLNVGpath* copy = &gl->paths[call->pathOffset + i];
1010 const struct NVGpath* path = &paths[i];
1011 bx::memSet(copy, 0, sizeof(struct GLNVGpath) );
1012 if (path->nstroke)
1013 {
1014 copy->strokeOffset = offset;
1015 copy->strokeCount = path->nstroke;
1016 bx::memCopy(&gl->verts[offset], path->stroke, sizeof(struct NVGvertex) * path->nstroke);
1017 offset += path->nstroke;
1018 }
1019 }
1020
1021 // Fill shader
1022 call->uniformOffset = glnvg__allocFragUniforms(gl, 1);
1023 glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset), paint, scissor, strokeWidth, fringe);
1024 }
1025
nvgRenderTriangles(void * _userPtr,struct NVGpaint * paint,NVGcompositeOperationState compositeOperation,struct NVGscissor * scissor,const struct NVGvertex * verts,int nverts)1026 static void nvgRenderTriangles(void* _userPtr, struct NVGpaint* paint, NVGcompositeOperationState compositeOperation, struct NVGscissor* scissor,
1027 const struct NVGvertex* verts, int nverts)
1028 {
1029 struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr;
1030 struct GLNVGcall* call = glnvg__allocCall(gl);
1031 struct GLNVGfragUniforms* frag;
1032
1033 call->type = GLNVG_TRIANGLES;
1034 call->image = paint->image;
1035 call->blendFunc = glnvg__blendCompositeOperation(compositeOperation);
1036
1037 // Allocate vertices for all the paths.
1038 call->vertexOffset = glnvg__allocVerts(gl, nverts);
1039 call->vertexCount = nverts;
1040 bx::memCopy(&gl->verts[call->vertexOffset], verts, sizeof(struct NVGvertex) * nverts);
1041
1042 // Fill shader
1043 call->uniformOffset = glnvg__allocFragUniforms(gl, 1);
1044 frag = nvg__fragUniformPtr(gl, call->uniformOffset);
1045 glnvg__convertPaint(gl, frag, paint, scissor, 1.0f, 1.0f);
1046 frag->type = NSVG_SHADER_IMG;
1047 }
1048
nvgRenderDelete(void * _userPtr)1049 static void nvgRenderDelete(void* _userPtr)
1050 {
1051 struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr;
1052
1053 if (gl == NULL)
1054 {
1055 return;
1056 }
1057
1058 bgfx::destroy(gl->prog);
1059 bgfx::destroy(gl->texMissing);
1060
1061 bgfx::destroy(gl->u_scissorMat);
1062 bgfx::destroy(gl->u_paintMat);
1063 bgfx::destroy(gl->u_innerCol);
1064 bgfx::destroy(gl->u_outerCol);
1065 bgfx::destroy(gl->u_viewSize);
1066 bgfx::destroy(gl->u_scissorExtScale);
1067 bgfx::destroy(gl->u_extentRadius);
1068 bgfx::destroy(gl->u_params);
1069 bgfx::destroy(gl->s_tex);
1070
1071 if (bgfx::isValid(gl->u_halfTexel) )
1072 {
1073 bgfx::destroy(gl->u_halfTexel);
1074 }
1075
1076 for (uint32_t ii = 0, num = gl->ntextures; ii < num; ++ii)
1077 {
1078 if (bgfx::isValid(gl->textures[ii].id)
1079 && (gl->textures[ii].flags & NVG_IMAGE_NODELETE) == 0)
1080 {
1081 bgfx::destroy(gl->textures[ii].id);
1082 }
1083 }
1084
1085 BX_FREE(gl->allocator, gl->uniforms);
1086 BX_FREE(gl->allocator, gl->verts);
1087 BX_FREE(gl->allocator, gl->paths);
1088 BX_FREE(gl->allocator, gl->calls);
1089 BX_FREE(gl->allocator, gl->textures);
1090 BX_FREE(gl->allocator, gl);
1091 }
1092
1093 } // namespace
1094
nvgCreate(int32_t _edgeaa,bgfx::ViewId _viewId,bx::AllocatorI * _allocator)1095 NVGcontext* nvgCreate(int32_t _edgeaa, bgfx::ViewId _viewId, bx::AllocatorI* _allocator)
1096 {
1097 if (NULL == _allocator)
1098 {
1099 static bx::DefaultAllocator allocator;
1100 _allocator = &allocator;
1101 }
1102
1103 struct NVGparams params;
1104 struct NVGcontext* ctx = NULL;
1105 struct GLNVGcontext* gl = (struct GLNVGcontext*)BX_ALLOC(_allocator, sizeof(struct GLNVGcontext) );
1106 if (gl == NULL)
1107 {
1108 goto error;
1109 }
1110
1111 bx::memSet(gl, 0, sizeof(struct GLNVGcontext) );
1112
1113 bx::memSet(¶ms, 0, sizeof(params) );
1114 params.renderCreate = nvgRenderCreate;
1115 params.renderCreateTexture = nvgRenderCreateTexture;
1116 params.renderDeleteTexture = nvgRenderDeleteTexture;
1117 params.renderUpdateTexture = nvgRenderUpdateTexture;
1118 params.renderGetTextureSize = nvgRenderGetTextureSize;
1119 params.renderViewport = nvgRenderViewport;
1120 params.renderFlush = nvgRenderFlush;
1121 params.renderFill = nvgRenderFill;
1122 params.renderStroke = nvgRenderStroke;
1123 params.renderTriangles = nvgRenderTriangles;
1124 params.renderDelete = nvgRenderDelete;
1125 params.userPtr = gl;
1126 params.edgeAntiAlias = _edgeaa;
1127
1128 gl->allocator = _allocator;
1129 gl->edgeAntiAlias = _edgeaa;
1130 gl->viewId = _viewId;
1131
1132 ctx = nvgCreateInternal(¶ms);
1133 if (ctx == NULL) goto error;
1134
1135 return ctx;
1136
1137 error:
1138 // 'gl' is freed by nvgDeleteInternal.
1139 if (ctx != NULL)
1140 {
1141 nvgDeleteInternal(ctx);
1142 }
1143
1144 return NULL;
1145 }
1146
nvgCreate(int32_t _edgeaa,bgfx::ViewId _viewId)1147 NVGcontext* nvgCreate(int32_t _edgeaa, bgfx::ViewId _viewId) {
1148 return nvgCreate(_edgeaa, _viewId, NULL);
1149 }
1150
nvgDelete(NVGcontext * _ctx)1151 void nvgDelete(NVGcontext* _ctx)
1152 {
1153 nvgDeleteInternal(_ctx);
1154 }
1155
nvgSetViewId(NVGcontext * _ctx,bgfx::ViewId _viewId)1156 void nvgSetViewId(NVGcontext* _ctx, bgfx::ViewId _viewId)
1157 {
1158 struct NVGparams* params = nvgInternalParams(_ctx);
1159 struct GLNVGcontext* gl = (struct GLNVGcontext*)params->userPtr;
1160 gl->viewId = _viewId;
1161 }
1162
nvgGetViewId(struct NVGcontext * _ctx)1163 uint16_t nvgGetViewId(struct NVGcontext* _ctx)
1164 {
1165 struct NVGparams* params = nvgInternalParams(_ctx);
1166 struct GLNVGcontext* gl = (struct GLNVGcontext*)params->userPtr;
1167 return gl->viewId;
1168 }
1169
nvglImageHandle(NVGcontext * _ctx,int32_t _image)1170 bgfx::TextureHandle nvglImageHandle(NVGcontext* _ctx, int32_t _image)
1171 {
1172 GLNVGcontext* gl = (GLNVGcontext*)nvgInternalParams(_ctx)->userPtr;
1173 GLNVGtexture* tex = glnvg__findTexture(gl, _image);
1174 return tex->id;
1175 }
1176
nvgluCreateFramebuffer(NVGcontext * ctx,int32_t width,int32_t height,int32_t imageFlags,bgfx::ViewId viewId)1177 NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int32_t width, int32_t height, int32_t imageFlags, bgfx::ViewId viewId)
1178 {
1179 NVGLUframebuffer* framebuffer = nvgluCreateFramebuffer(ctx, width, height, imageFlags);
1180
1181 if (framebuffer != NULL)
1182 {
1183 nvgluSetViewFramebuffer(viewId, framebuffer);
1184 }
1185
1186 return framebuffer;
1187 }
1188
nvgluCreateFramebuffer(NVGcontext * _ctx,int32_t _width,int32_t _height,int32_t _imageFlags)1189 NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* _ctx, int32_t _width, int32_t _height, int32_t _imageFlags)
1190 {
1191 BX_UNUSED(_imageFlags);
1192 bgfx::TextureHandle textures[] =
1193 {
1194 bgfx::createTexture2D(_width, _height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_RT),
1195 bgfx::createTexture2D(_width, _height, false, 1, bgfx::TextureFormat::D24S8, BGFX_TEXTURE_RT | BGFX_TEXTURE_RT_WRITE_ONLY)
1196 };
1197 bgfx::FrameBufferHandle fbh = bgfx::createFrameBuffer(
1198 BX_COUNTOF(textures)
1199 , textures
1200 , true
1201 );
1202
1203 if (!bgfx::isValid(fbh) )
1204 {
1205 return NULL;
1206 }
1207
1208 struct NVGparams* params = nvgInternalParams(_ctx);
1209 struct GLNVGcontext* gl = (struct GLNVGcontext*)params->userPtr;
1210 struct GLNVGtexture* tex = glnvg__allocTexture(gl);
1211
1212 if (NULL == tex)
1213 {
1214 bgfx::destroy(fbh);
1215 return NULL;
1216 }
1217
1218 tex->width = _width;
1219 tex->height = _height;
1220 tex->type = NVG_TEXTURE_RGBA;
1221 tex->flags = _imageFlags | NVG_IMAGE_PREMULTIPLIED;
1222 tex->id = bgfx::getTexture(fbh);
1223
1224 NVGLUframebuffer* framebuffer = BX_NEW(gl->allocator, NVGLUframebuffer);
1225 framebuffer->ctx = _ctx;
1226 framebuffer->image = tex->id.idx;
1227 framebuffer->handle = fbh;
1228
1229 return framebuffer;
1230 }
1231
nvgluBindFramebuffer(NVGLUframebuffer * _framebuffer)1232 void nvgluBindFramebuffer(NVGLUframebuffer* _framebuffer)
1233 {
1234 static NVGcontext* s_prevCtx = NULL;
1235 static bgfx::ViewId s_prevViewId;
1236 if (_framebuffer != NULL)
1237 {
1238 s_prevCtx = _framebuffer->ctx;
1239 s_prevViewId = nvgGetViewId(_framebuffer->ctx);
1240 nvgSetViewId(_framebuffer->ctx, _framebuffer->viewId);
1241 }
1242 else if (s_prevCtx != NULL)
1243 {
1244 nvgSetViewId(s_prevCtx, s_prevViewId);
1245 }
1246 }
1247
nvgluDeleteFramebuffer(NVGLUframebuffer * _framebuffer)1248 void nvgluDeleteFramebuffer(NVGLUframebuffer* _framebuffer)
1249 {
1250 if (_framebuffer == NULL)
1251 {
1252 return;
1253 }
1254
1255 if (bgfx::isValid(_framebuffer->handle))
1256 {
1257 bgfx::destroy(_framebuffer->handle);
1258 }
1259
1260 struct NVGparams* params = nvgInternalParams(_framebuffer->ctx);
1261 struct GLNVGcontext* gl = (struct GLNVGcontext*)params->userPtr;
1262 glnvg__deleteTexture(gl, _framebuffer->image);
1263 BX_DELETE(gl->allocator, _framebuffer);
1264 }
1265
nvgluSetViewFramebuffer(bgfx::ViewId _viewId,NVGLUframebuffer * _framebuffer)1266 void nvgluSetViewFramebuffer(bgfx::ViewId _viewId, NVGLUframebuffer* _framebuffer)
1267 {
1268 _framebuffer->viewId = _viewId;
1269 bgfx::setViewFrameBuffer(_viewId, _framebuffer->handle);
1270 bgfx::setViewMode(_viewId, bgfx::ViewMode::Sequential);
1271 }
1272