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(&params, 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(&params);
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