|  |  | @@ -60,8 +60,8 @@ void nvgDeleteGL3(struct NVGcontext* ctx); | 
		
	
		
			
			|  |  |  | #include "nanovg.h" | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | enum GLNVGuniformLoc { | 
		
	
		
			
			|  |  |  | GLNVG_LOC_UBOVIEW, | 
		
	
		
			
			|  |  |  | GLNVG_LOC_UBOFRAG, | 
		
	
		
			
			|  |  |  | GLNVG_LOC_VIEW, | 
		
	
		
			
			|  |  |  | GLNVG_LOC_FRAG, | 
		
	
		
			
			|  |  |  | GLNVG_MAX_LOCS | 
		
	
		
			
			|  |  |  | }; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
				|  |  | @@ -73,8 +73,8 @@ enum GLNVGshaderType { | 
		
	
		
			
			|  |  |  | }; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | enum GLNVGuniformBindings { | 
		
	
		
			
			|  |  |  | GLNVG_UBO_VIEW_BINDING = 0, | 
		
	
		
			
			|  |  |  | GLNVG_UBO_FRAG_BINDING = 1, | 
		
	
		
			
			|  |  |  | GLNVG_VIEW_BINDING = 0, | 
		
	
		
			
			|  |  |  | GLNVG_FRAG_BINDING = 1, | 
		
	
		
			
			|  |  |  | }; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | struct GLNVGshader { | 
		
	
	
		
			
				|  |  | @@ -100,14 +100,12 @@ enum GLNVGcallType { | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | struct GLNVGcall { | 
		
	
		
			
			|  |  |  | int type; | 
		
	
		
			
			|  |  |  | int image; | 
		
	
		
			
			|  |  |  | int pathOffset; | 
		
	
		
			
			|  |  |  | int pathCount; | 
		
	
		
			
			|  |  |  | struct NVGpaint paint; | 
		
	
		
			
			|  |  |  | struct NVGscissor scissor; | 
		
	
		
			
			|  |  |  | float strokeWidth; | 
		
	
		
			
			|  |  |  | int triangleOffset; | 
		
	
		
			
			|  |  |  | int triangleCount; | 
		
	
		
			
			|  |  |  | int uboOffset; | 
		
	
		
			
			|  |  |  | int uniformOffset; | 
		
	
		
			
			|  |  |  | }; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | struct GLNVGpath { | 
		
	
	
		
			
				|  |  | @@ -117,7 +115,7 @@ struct GLNVGpath { | 
		
	
		
			
			|  |  |  | int strokeCount; | 
		
	
		
			
			|  |  |  | }; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | struct GLNVGuboFrag { | 
		
	
		
			
			|  |  |  | struct GLNVGfragUniforms { | 
		
	
		
			
			|  |  |  | float scissorMat[12]; // matrices are actually 3 vec4s | 
		
	
		
			
			|  |  |  | float paintMat[12]; | 
		
	
		
			
			|  |  |  | float innerCol[4]; | 
		
	
	
		
			
				|  |  | @@ -141,11 +139,12 @@ struct GLNVGcontext { | 
		
	
		
			
			|  |  |  | int textureId; | 
		
	
		
			
			|  |  |  | GLuint vertArr; | 
		
	
		
			
			|  |  |  | GLuint vertBuf; | 
		
	
		
			
			|  |  |  | GLuint uboViewBuf; | 
		
	
		
			
			|  |  |  | GLuint uboFragBuf; | 
		
	
		
			
			|  |  |  | int uboPosAlignment; | 
		
	
		
			
			|  |  |  | GLuint viewBuf; | 
		
	
		
			
			|  |  |  | GLuint fragBuf; | 
		
	
		
			
			|  |  |  | int fragSize; | 
		
	
		
			
			|  |  |  | int edgeAntiAlias; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Per frame buffers | 
		
	
		
			
			|  |  |  | struct GLNVGcall* calls; | 
		
	
		
			
			|  |  |  | int ccalls; | 
		
	
		
			
			|  |  |  | int ncalls; | 
		
	
	
		
			
				|  |  | @@ -155,6 +154,9 @@ struct GLNVGcontext { | 
		
	
		
			
			|  |  |  | struct NVGvertex* verts; | 
		
	
		
			
			|  |  |  | int cverts; | 
		
	
		
			
			|  |  |  | int nverts; | 
		
	
		
			
			|  |  |  | unsigned char* uniforms; | 
		
	
		
			
			|  |  |  | int cuniforms; | 
		
	
		
			
			|  |  |  | int nuniforms; | 
		
	
		
			
			|  |  |  | }; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
				|  |  | @@ -237,18 +239,23 @@ static int glnvg__checkError(const char* str) | 
		
	
		
			
			|  |  |  | return 0; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static int glnvg__createShader(struct GLNVGshader* shader, const char* name, const char* vshader, const char* fshader) | 
		
	
		
			
			|  |  |  | static int glnvg__createShader(struct GLNVGshader* shader, const char* name, const char* header, const char* opts, const char* vshader, const char* fshader) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | GLint status; | 
		
	
		
			
			|  |  |  | GLuint prog, vert, frag; | 
		
	
		
			
			|  |  |  | const char* str[3]; | 
		
	
		
			
			|  |  |  | str[0] = header; | 
		
	
		
			
			|  |  |  | str[1] = opts != NULL ? opts : ""; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | memset(shader, 0, sizeof(*shader)); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | prog = glCreateProgram(); | 
		
	
		
			
			|  |  |  | vert = glCreateShader(GL_VERTEX_SHADER); | 
		
	
		
			
			|  |  |  | frag = glCreateShader(GL_FRAGMENT_SHADER); | 
		
	
		
			
			|  |  |  | glShaderSource(vert, 1, &vshader, 0); | 
		
	
		
			
			|  |  |  | glShaderSource(frag, 1, &fshader, 0); | 
		
	
		
			
			|  |  |  | str[2] = vshader; | 
		
	
		
			
			|  |  |  | glShaderSource(vert, 3, str, 0); | 
		
	
		
			
			|  |  |  | str[2] = fshader; | 
		
	
		
			
			|  |  |  | glShaderSource(frag, 3, str, 0); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | glCompileShader(vert); | 
		
	
		
			
			|  |  |  | glGetShaderiv(vert, GL_COMPILE_STATUS, &status); | 
		
	
	
		
			
				|  |  | @@ -296,22 +303,25 @@ static void glnvg__deleteShader(struct GLNVGshader* shader) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static void glnvg__getUniforms(struct GLNVGshader* shader) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | shader->loc[GLNVG_LOC_UBOVIEW] = glGetUniformBlockIndex(shader->prog, "uboView"); | 
		
	
		
			
			|  |  |  | shader->loc[GLNVG_LOC_UBOFRAG] = glGetUniformBlockIndex(shader->prog, "uboFrag"); | 
		
	
		
			
			|  |  |  | shader->loc[GLNVG_LOC_VIEW] = glGetUniformBlockIndex(shader->prog, "view"); | 
		
	
		
			
			|  |  |  | shader->loc[GLNVG_LOC_FRAG] = glGetUniformBlockIndex(shader->prog, "frag"); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static int glnvg__renderCreate(void* uptr) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; | 
		
	
		
			
			|  |  |  | int align = 1; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static const char* fillVertShader = | 
		
	
		
			
			|  |  |  | static const char* shaderHeader = | 
		
	
		
			
			|  |  |  | #ifdef NANOVG_GLES3 | 
		
	
		
			
			|  |  |  | "#version 300 es\n" | 
		
	
		
			
			|  |  |  | "precision mediump float;\n" | 
		
	
		
			
			|  |  |  | "precision mediump float;\n"; | 
		
	
		
			
			|  |  |  | #else | 
		
	
		
			
			|  |  |  | "#version 150 core\n" | 
		
	
		
			
			|  |  |  | "#version 150 core\n"; | 
		
	
		
			
			|  |  |  | #endif | 
		
	
		
			
			|  |  |  | "layout(std140) uniform uboView {\n" | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static const char* fillVertShader = | 
		
	
		
			
			|  |  |  | "layout(std140) uniform view {\n" | 
		
	
		
			
			|  |  |  | "   vec2 viewSize;\n" | 
		
	
		
			
			|  |  |  | "};\n" | 
		
	
		
			
			|  |  |  | "in vec2 vertex;\n" | 
		
	
	
		
			
				|  |  | @@ -325,13 +335,7 @@ static int glnvg__renderCreate(void* uptr) | 
		
	
		
			
			|  |  |  | "}\n"; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static const char* fillFragShaderEdgeAA = | 
		
	
		
			
			|  |  |  | #ifdef NANOVG_GLES3 | 
		
	
		
			
			|  |  |  | "#version 300 es\n" | 
		
	
		
			
			|  |  |  | "precision mediump float;\n" | 
		
	
		
			
			|  |  |  | #else | 
		
	
		
			
			|  |  |  | "#version 150 core\n" | 
		
	
		
			
			|  |  |  | #endif | 
		
	
		
			
			|  |  |  | "layout(std140) uniform uboFrag {\n" | 
		
	
		
			
			|  |  |  | "layout(std140) uniform frag {\n" | 
		
	
		
			
			|  |  |  | "	mat3 scissorMat;\n" | 
		
	
		
			
			|  |  |  | "	mat3 paintMat;\n" | 
		
	
		
			
			|  |  |  | "	vec4 innerCol;\n" | 
		
	
	
		
			
				|  |  | @@ -362,16 +366,21 @@ static int glnvg__renderCreate(void* uptr) | 
		
	
		
			
			|  |  |  | "	sc = vec2(0.5,0.5) - sc * scissorScale;\n" | 
		
	
		
			
			|  |  |  | "	return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);\n" | 
		
	
		
			
			|  |  |  | "}\n" | 
		
	
		
			
			|  |  |  | "\n" | 
		
	
		
			
			|  |  |  | "#ifdef EDGE_AA\n" | 
		
	
		
			
			|  |  |  | "// Stroke - from [0..1] to clipped pyramid, where the slope is 1px.\n" | 
		
	
		
			
			|  |  |  | "float strokeMask() {\n" | 
		
	
		
			
			|  |  |  | "	return min(1.0, (1.0-abs(ftcoord.x*2.0-1.0))*strokeMult) * ftcoord.y;\n" | 
		
	
		
			
			|  |  |  | "}\n" | 
		
	
		
			
			|  |  |  | "#endif\n" | 
		
	
		
			
			|  |  |  | "\n" | 
		
	
		
			
			|  |  |  | "void main(void) {\n" | 
		
	
		
			
			|  |  |  | "	if (type == 0) {			// Gradient\n" | 
		
	
		
			
			|  |  |  | "		float scissor = scissorMask(fpos);\n" | 
		
	
		
			
			|  |  |  | "#ifdef EDGE_AA\n" | 
		
	
		
			
			|  |  |  | "		float strokeAlpha = strokeMask();\n" | 
		
	
		
			
			|  |  |  | "#else\n" | 
		
	
		
			
			|  |  |  | "		float strokeAlpha = 1.0f;\n" | 
		
	
		
			
			|  |  |  | "#endif\n" | 
		
	
		
			
			|  |  |  | "		// Calculate gradient color using box gradient\n" | 
		
	
		
			
			|  |  |  | "		vec2 pt = (paintMat * vec3(fpos,1.0)).xy;\n" | 
		
	
		
			
			|  |  |  | "		float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0);\n" | 
		
	
	
		
			
				|  |  | @@ -381,7 +390,11 @@ static int glnvg__renderCreate(void* uptr) | 
		
	
		
			
			|  |  |  | "		outColor = color;\n" | 
		
	
		
			
			|  |  |  | "	} else if (type == 1) {		// Image\n" | 
		
	
		
			
			|  |  |  | "		float scissor = scissorMask(fpos);\n" | 
		
	
		
			
			|  |  |  | "#ifdef EDGE_AA\n" | 
		
	
		
			
			|  |  |  | "		float strokeAlpha = strokeMask();\n" | 
		
	
		
			
			|  |  |  | "#else\n" | 
		
	
		
			
			|  |  |  | "		float strokeAlpha = 1.0f;\n" | 
		
	
		
			
			|  |  |  | "#endif\n" | 
		
	
		
			
			|  |  |  | "		// Calculate color fron texture\n" | 
		
	
		
			
			|  |  |  | "		vec2 pt = (paintMat * vec3(fpos,1.0)).xy / extent;\n" | 
		
	
		
			
			|  |  |  | "		vec4 color = texture(tex, pt);\n" | 
		
	
	
		
			
				|  |  | @@ -392,75 +405,10 @@ static int glnvg__renderCreate(void* uptr) | 
		
	
		
			
			|  |  |  | "	} else if (type == 2) {		// Stencil fill\n" | 
		
	
		
			
			|  |  |  | "		outColor = vec4(1,1,1,1);\n" | 
		
	
		
			
			|  |  |  | "	} else if (type == 3) {		// Textured tris\n" | 
		
	
		
			
			|  |  |  | "		vec4 color = texture(tex, ftcoord);\n" | 
		
	
		
			
			|  |  |  | "   	color = texType == 0 ? color : vec4(1,1,1,color.x);\n" | 
		
	
		
			
			|  |  |  | "		outColor = color * innerCol;\n" | 
		
	
		
			
			|  |  |  | "	}\n" | 
		
	
		
			
			|  |  |  | "}\n"; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static const char* fillFragShader = | 
		
	
		
			
			|  |  |  | #ifdef NANOVG_GLES3 | 
		
	
		
			
			|  |  |  | "#version 300 es\n" | 
		
	
		
			
			|  |  |  | "precision mediump float;\n" | 
		
	
		
			
			|  |  |  | #else | 
		
	
		
			
			|  |  |  | "#version 150 core\n" | 
		
	
		
			
			|  |  |  | #endif | 
		
	
		
			
			|  |  |  | "layout(std140) uniform uboFrag {\n" | 
		
	
		
			
			|  |  |  | "	mat3 scissorMat;\n" | 
		
	
		
			
			|  |  |  | "	mat3 paintMat;\n" | 
		
	
		
			
			|  |  |  | "	vec4 innerCol;\n" | 
		
	
		
			
			|  |  |  | "	vec4 outerCol;\n" | 
		
	
		
			
			|  |  |  | "	vec2 scissorExt;\n" | 
		
	
		
			
			|  |  |  | "	vec2 scissorScale;\n" | 
		
	
		
			
			|  |  |  | "	vec2 extent;\n" | 
		
	
		
			
			|  |  |  | "	float radius;\n" | 
		
	
		
			
			|  |  |  | "	float feather;\n" | 
		
	
		
			
			|  |  |  | "	float strokeMult;\n" | 
		
	
		
			
			|  |  |  | "	int texType;\n" | 
		
	
		
			
			|  |  |  | "	int type;\n" | 
		
	
		
			
			|  |  |  | "};\n" | 
		
	
		
			
			|  |  |  | "uniform sampler2D tex;\n" | 
		
	
		
			
			|  |  |  | "in vec2 ftcoord;\n" | 
		
	
		
			
			|  |  |  | "in vec2 fpos;\n" | 
		
	
		
			
			|  |  |  | "out vec4 outColor;\n" | 
		
	
		
			
			|  |  |  | "\n" | 
		
	
		
			
			|  |  |  | "float sdroundrect(vec2 pt, vec2 ext, float rad) {\n" | 
		
	
		
			
			|  |  |  | "	vec2 ext2 = ext - vec2(rad,rad);\n" | 
		
	
		
			
			|  |  |  | "	vec2 d = abs(pt) - ext2;\n" | 
		
	
		
			
			|  |  |  | "	return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rad;\n" | 
		
	
		
			
			|  |  |  | "}\n" | 
		
	
		
			
			|  |  |  | "\n" | 
		
	
		
			
			|  |  |  | "// Scissoring\n" | 
		
	
		
			
			|  |  |  | "float scissorMask(vec2 p) {\n" | 
		
	
		
			
			|  |  |  | "	vec2 sc = (abs((scissorMat * vec3(p,1.0)).xy) - scissorExt);\n" | 
		
	
		
			
			|  |  |  | "	sc = vec2(0.5,0.5) - sc * scissorScale;\n" | 
		
	
		
			
			|  |  |  | "	return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);\n" | 
		
	
		
			
			|  |  |  | "}\n" | 
		
	
		
			
			|  |  |  | "\n" | 
		
	
		
			
			|  |  |  | "void main(void) {\n" | 
		
	
		
			
			|  |  |  | "	if (type == 0) {			// Gradient\n" | 
		
	
		
			
			|  |  |  | "		float scissor = scissorMask(fpos);\n" | 
		
	
		
			
			|  |  |  | "		// Calculate gradient color using box gradient\n" | 
		
	
		
			
			|  |  |  | "		vec2 pt = (paintMat * vec3(fpos,1.0)).xy;\n" | 
		
	
		
			
			|  |  |  | "		float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0);\n" | 
		
	
		
			
			|  |  |  | "		vec4 color = mix(innerCol,outerCol,d);\n" | 
		
	
		
			
			|  |  |  | "		// Combine alpha\n" | 
		
	
		
			
			|  |  |  | "		color.w *= scissor;\n" | 
		
	
		
			
			|  |  |  | "		outColor = color;\n" | 
		
	
		
			
			|  |  |  | "	} else if (type == 1) {		// Image\n" | 
		
	
		
			
			|  |  |  | "		float scissor = scissorMask(fpos);\n" | 
		
	
		
			
			|  |  |  | "		// Calculate color fron texture\n" | 
		
	
		
			
			|  |  |  | "		vec2 pt = (paintMat * vec3(fpos,1.0)).xy / extent;\n" | 
		
	
		
			
			|  |  |  | "		vec4 color = texture(tex, pt);\n" | 
		
	
		
			
			|  |  |  | "   	color = texType == 0 ? color : vec4(1,1,1,color.x);\n" | 
		
	
		
			
			|  |  |  | "		// Combine alpha\n" | 
		
	
		
			
			|  |  |  | "		color.w *= scissor;\n" | 
		
	
		
			
			|  |  |  | "		outColor = color;\n" | 
		
	
		
			
			|  |  |  | "	} else if (type == 2) {		// Stencil fill\n" | 
		
	
		
			
			|  |  |  | "		outColor = vec4(1,1,1,1);\n" | 
		
	
		
			
			|  |  |  | "	} else if (type == 3) {		// Textured tris\n" | 
		
	
		
			
			|  |  |  | "		vec4 color = texture(tex, ftcoord);\n" | 
		
	
		
			
			|  |  |  | "   	color = texType == 0 ? color : vec4(1,1,1,color.x);\n" | 
		
	
		
			
			|  |  |  | "		color.w *= scissor;\n" | 
		
	
		
			
			|  |  |  | "		outColor = color * innerCol;\n" | 
		
	
		
			
			|  |  |  | "	}\n" | 
		
	
		
			
			|  |  |  | "}\n"; | 
		
	
	
		
			
				|  |  | @@ -468,10 +416,10 @@ static int glnvg__renderCreate(void* uptr) | 
		
	
		
			
			|  |  |  | glnvg__checkError("init"); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (gl->edgeAntiAlias) { | 
		
	
		
			
			|  |  |  | if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShaderEdgeAA) == 0) | 
		
	
		
			
			|  |  |  | if (glnvg__createShader(&gl->shader, "shader", shaderHeader, "#define EDGE_AA 1\n", fillVertShader, fillFragShaderEdgeAA) == 0) | 
		
	
		
			
			|  |  |  | return 0; | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShader) == 0) | 
		
	
		
			
			|  |  |  | if (glnvg__createShader(&gl->shader, "shader", shaderHeader, NULL, fillVertShader, fillFragShaderEdgeAA) == 0) | 
		
	
		
			
			|  |  |  | return 0; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
				|  |  | @@ -483,12 +431,12 @@ static int glnvg__renderCreate(void* uptr) | 
		
	
		
			
			|  |  |  | glGenBuffers(1, &gl->vertBuf); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Create UBOs | 
		
	
		
			
			|  |  |  | glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_UBOVIEW], GLNVG_UBO_VIEW_BINDING); | 
		
	
		
			
			|  |  |  | glGenBuffers(1, &gl->uboViewBuf); | 
		
	
		
			
			|  |  |  | glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_UBOFRAG], GLNVG_UBO_FRAG_BINDING); | 
		
	
		
			
			|  |  |  | glGenBuffers(1, &gl->uboFragBuf); | 
		
	
		
			
			|  |  |  | glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &gl->uboPosAlignment); | 
		
	
		
			
			|  |  |  | gl->uboPosAlignment = sizeof(struct GLNVGuboFrag) + gl->uboPosAlignment - sizeof(struct GLNVGuboFrag) % gl->uboPosAlignment; | 
		
	
		
			
			|  |  |  | glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_VIEW], GLNVG_VIEW_BINDING); | 
		
	
		
			
			|  |  |  | glGenBuffers(1, &gl->viewBuf); | 
		
	
		
			
			|  |  |  | glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_FRAG], GLNVG_FRAG_BINDING); | 
		
	
		
			
			|  |  |  | glGenBuffers(1, &gl->fragBuf); | 
		
	
		
			
			|  |  |  | glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &align); | 
		
	
		
			
			|  |  |  | gl->fragSize = sizeof(struct GLNVGfragUniforms) + align - sizeof(struct GLNVGfragUniforms) % align; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | glnvg__checkError("done"); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
				|  |  | @@ -613,60 +561,55 @@ static void glnvg__xformToMat3x4(float* m3, float* t) | 
		
	
		
			
			|  |  |  | m3[11] = 0.0f; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static int glnvg__setupPaintUBO(struct GLNVGcontext* gl, struct NVGpaint* paint, struct NVGscissor* scissor, float width, struct GLNVGuboFrag* uboBuff) | 
		
	
		
			
			|  |  |  | static int glnvg__convertPaint(struct GLNVGcontext* gl, struct GLNVGfragUniforms* frag, struct NVGpaint* paint, struct NVGscissor* scissor, float width) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | struct GLNVGuboFrag ubo; | 
		
	
		
			
			|  |  |  | glnvg__toFloatColor(ubo.innerCol, paint->innerColor); | 
		
	
		
			
			|  |  |  | glnvg__toFloatColor(ubo.outerCol, paint->outerColor); | 
		
	
		
			
			|  |  |  | struct GLNVGtexture* tex = NULL; | 
		
	
		
			
			|  |  |  | float invxform[6]; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | glnvg__toFloatColor(frag->innerCol, paint->innerColor); | 
		
	
		
			
			|  |  |  | glnvg__toFloatColor(frag->outerCol, paint->outerColor); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | glnvg__xformInverse(invxform, paint->xform); | 
		
	
		
			
			|  |  |  | glnvg__xformToMat3x4(ubo.paintMat, invxform); | 
		
	
		
			
			|  |  |  | glnvg__xformToMat3x4(frag->paintMat, invxform); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (scissor->extent[0] < 0.5f || scissor->extent[1] < 0.5f) { | 
		
	
		
			
			|  |  |  | memset(ubo.scissorMat, 0, sizeof(ubo.scissorMat)); | 
		
	
		
			
			|  |  |  | ubo.scissorExt[0] = 1.0f; | 
		
	
		
			
			|  |  |  | ubo.scissorExt[1] = 1.0f; | 
		
	
		
			
			|  |  |  | ubo.scissorScale[0] = 1.0f; | 
		
	
		
			
			|  |  |  | ubo.scissorScale[1] = 1.0f; | 
		
	
		
			
			|  |  |  | memset(frag->scissorMat, 0, sizeof(frag->scissorMat)); | 
		
	
		
			
			|  |  |  | frag->scissorExt[0] = 1.0f; | 
		
	
		
			
			|  |  |  | frag->scissorExt[1] = 1.0f; | 
		
	
		
			
			|  |  |  | frag->scissorScale[0] = 1.0f; | 
		
	
		
			
			|  |  |  | frag->scissorScale[1] = 1.0f; | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | glnvg__xformInverse(invxform, scissor->xform); | 
		
	
		
			
			|  |  |  | glnvg__xformToMat3x4(ubo.scissorMat, invxform); | 
		
	
		
			
			|  |  |  | ubo.scissorExt[0] = scissor->extent[0]; | 
		
	
		
			
			|  |  |  | ubo.scissorExt[1] = scissor->extent[1]; | 
		
	
		
			
			|  |  |  | ubo.scissorScale[0] = sqrtf(scissor->xform[0]*scissor->xform[0] + scissor->xform[2]*scissor->xform[2]); | 
		
	
		
			
			|  |  |  | ubo.scissorScale[1] = sqrtf(scissor->xform[1]*scissor->xform[1] + scissor->xform[3]*scissor->xform[3]); | 
		
	
		
			
			|  |  |  | glnvg__xformToMat3x4(frag->scissorMat, invxform); | 
		
	
		
			
			|  |  |  | frag->scissorExt[0] = scissor->extent[0]; | 
		
	
		
			
			|  |  |  | frag->scissorExt[1] = scissor->extent[1]; | 
		
	
		
			
			|  |  |  | frag->scissorScale[0] = sqrtf(scissor->xform[0]*scissor->xform[0] + scissor->xform[2]*scissor->xform[2]); | 
		
	
		
			
			|  |  |  | frag->scissorScale[1] = sqrtf(scissor->xform[1]*scissor->xform[1] + scissor->xform[3]*scissor->xform[3]); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | memcpy( ubo.extent, paint->extent, sizeof( ubo.extent ) ); | 
		
	
		
			
			|  |  |  | ubo.strokeMult = width*0.5f + 0.5f; | 
		
	
		
			
			|  |  |  | memcpy(frag->extent, paint->extent, sizeof(frag->extent)); | 
		
	
		
			
			|  |  |  | frag->strokeMult = width*0.5f + 0.5f; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (paint->image != 0) { | 
		
	
		
			
			|  |  |  | tex = glnvg__findTexture(gl, paint->image); | 
		
	
		
			
			|  |  |  | if (tex == NULL) return 0; | 
		
	
		
			
			|  |  |  | ubo.type = NSVG_SHADER_FILLIMG; | 
		
	
		
			
			|  |  |  | ubo.texType = tex->type == NVG_TEXTURE_RGBA ? 0 : 1; | 
		
	
		
			
			|  |  |  | glnvg__checkError("tex paint loc"); | 
		
	
		
			
			|  |  |  | frag->type = NSVG_SHADER_FILLIMG; | 
		
	
		
			
			|  |  |  | frag->texType = tex->type == NVG_TEXTURE_RGBA ? 0 : 1; | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | ubo.type = NSVG_SHADER_FILLGRAD; | 
		
	
		
			
			|  |  |  | ubo.radius = paint->radius; | 
		
	
		
			
			|  |  |  | ubo.feather = paint->feather; | 
		
	
		
			
			|  |  |  | glnvg__checkError("grad paint loc"); | 
		
	
		
			
			|  |  |  | frag->type = NSVG_SHADER_FILLGRAD; | 
		
	
		
			
			|  |  |  | frag->radius = paint->radius; | 
		
	
		
			
			|  |  |  | frag->feather = paint->feather; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | *uboBuff = ubo; | 
		
	
		
			
			|  |  |  | return 1; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static int glnvg__setupPaint(struct GLNVGcontext* gl, struct NVGpaint* paint, int uboOffset) | 
		
	
		
			
			|  |  |  | static void glnvg__setUniforms(struct GLNVGcontext* gl, int uniformOffset, int image) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_UBO_FRAG_BINDING, gl->uboFragBuf, uboOffset, sizeof(struct GLNVGuboFrag)); | 
		
	
		
			
			|  |  |  | if (paint->image != 0) { | 
		
	
		
			
			|  |  |  | struct GLNVGtexture* tex = glnvg__findTexture(gl, paint->image); | 
		
	
		
			
			|  |  |  | if (tex == NULL) return 0; | 
		
	
		
			
			|  |  |  | glBindTexture(GL_TEXTURE_2D, tex->tex); | 
		
	
		
			
			|  |  |  | glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_FRAG_BINDING, gl->fragBuf, uniformOffset, sizeof(struct GLNVGfragUniforms)); | 
		
	
		
			
			|  |  |  | if (image != 0) { | 
		
	
		
			
			|  |  |  | struct GLNVGtexture* tex = glnvg__findTexture(gl, image); | 
		
	
		
			
			|  |  |  | glBindTexture(GL_TEXTURE_2D, tex != NULL ? tex->tex : 0); | 
		
	
		
			
			|  |  |  | glnvg__checkError("tex paint tex"); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return 1; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static void glnvg__renderViewport(void* uptr, int width, int height) | 
		
	
	
		
			
				|  |  | @@ -679,7 +622,7 @@ static void glnvg__renderViewport(void* uptr, int width, int height) | 
		
	
		
			
			|  |  |  | static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | struct GLNVGpath* paths = &gl->paths[call->pathOffset]; | 
		
	
		
			
			|  |  |  | int npaths = call->pathCount, i; | 
		
	
		
			
			|  |  |  | int i, npaths = call->pathCount; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Draw shapes | 
		
	
		
			
			|  |  |  | glDisable(GL_BLEND); | 
		
	
	
		
			
				|  |  | @@ -689,8 +632,8 @@ static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call) | 
		
	
		
			
			|  |  |  | glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // set bindpoint for solid loc | 
		
	
		
			
			|  |  |  | glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_UBO_FRAG_BINDING, gl->uboFragBuf, call->uboOffset, sizeof(struct GLNVGuboFrag)); | 
		
	
		
			
			|  |  |  | glnvg__checkError("fill solid loc"); | 
		
	
		
			
			|  |  |  | glnvg__setUniforms(gl, call->uniformOffset, 0); | 
		
	
		
			
			|  |  |  | glnvg__checkError("fill simple"); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); | 
		
	
		
			
			|  |  |  | glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); | 
		
	
	
		
			
				|  |  | @@ -703,7 +646,8 @@ static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call) | 
		
	
		
			
			|  |  |  | glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | 
		
	
		
			
			|  |  |  | glEnable(GL_BLEND); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | glnvg__setupPaint(gl, &call->paint, call->uboOffset + gl->uboPosAlignment); | 
		
	
		
			
			|  |  |  | glnvg__setUniforms(gl, call->uniformOffset + gl->fragSize, call->image); | 
		
	
		
			
			|  |  |  | glnvg__checkError("fill fill"); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (gl->edgeAntiAlias) { | 
		
	
		
			
			|  |  |  | glStencilFunc(GL_EQUAL, 0x00, 0xff); | 
		
	
	
		
			
				|  |  | @@ -724,9 +668,10 @@ static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call) | 
		
	
		
			
			|  |  |  | static void glnvg__convexFill(struct GLNVGcontext* gl, struct GLNVGcall* call) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | struct GLNVGpath* paths = &gl->paths[call->pathOffset]; | 
		
	
		
			
			|  |  |  | int npaths = call->pathCount, i; | 
		
	
		
			
			|  |  |  | int i, npaths = call->pathCount; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | glnvg__setupPaint(gl, &call->paint, call->uboOffset); | 
		
	
		
			
			|  |  |  | glnvg__setUniforms(gl, call->uniformOffset, call->image); | 
		
	
		
			
			|  |  |  | glnvg__checkError("convex fill"); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | for (i = 0; i < npaths; i++) | 
		
	
		
			
			|  |  |  | glDrawArrays(GL_TRIANGLE_FAN, paths[i].fillOffset, paths[i].fillCount); | 
		
	
	
		
			
				|  |  | @@ -742,7 +687,8 @@ static void glnvg__stroke(struct GLNVGcontext* gl, struct GLNVGcall* call) | 
		
	
		
			
			|  |  |  | struct GLNVGpath* paths = &gl->paths[call->pathOffset]; | 
		
	
		
			
			|  |  |  | int npaths = call->pathCount, i; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | glnvg__setupPaint(gl, &call->paint, call->uboOffset); | 
		
	
		
			
			|  |  |  | glnvg__setUniforms(gl, call->uniformOffset, call->image); | 
		
	
		
			
			|  |  |  | glnvg__checkError("stroke fill"); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Draw Strokes | 
		
	
		
			
			|  |  |  | for (i = 0; i < npaths; i++) | 
		
	
	
		
			
				|  |  | @@ -751,57 +697,25 @@ static void glnvg__stroke(struct GLNVGcontext* gl, struct GLNVGcall* call) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static void glnvg__triangles(struct GLNVGcontext* gl, struct GLNVGcall* call) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | struct GLNVGtexture* tex = glnvg__findTexture(gl, call->paint.image); | 
		
	
		
			
			|  |  |  | if (tex != NULL) | 
		
	
		
			
			|  |  |  | glBindTexture(GL_TEXTURE_2D, tex->tex); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_UBO_FRAG_BINDING, gl->uboFragBuf, call->uboOffset, sizeof(struct GLNVGuboFrag)); | 
		
	
		
			
			|  |  |  | glnvg__setUniforms(gl, call->uniformOffset, call->image); | 
		
	
		
			
			|  |  |  | glnvg__checkError("triangles fill"); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | glnvg__checkError("tris solid img loc"); | 
		
	
		
			
			|  |  |  | glDrawArrays(GL_TRIANGLES, call->triangleOffset, call->triangleCount); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static void glnvg__renderFlush(void* uptr) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; | 
		
	
		
			
			|  |  |  | int i, offset; | 
		
	
		
			
			|  |  |  | char* buff; | 
		
	
		
			
			|  |  |  | int i; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (gl->ncalls > 0) { | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | glUseProgram(gl->shader.prog); | 
		
	
		
			
			|  |  |  | glEnable(GL_CULL_FACE); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // upload ubo for frag shaders - maximum ubos is 2x num calls | 
		
	
		
			
			|  |  |  | glBindBuffer(GL_UNIFORM_BUFFER, gl->uboFragBuf); | 
		
	
		
			
			|  |  |  | glBufferData(GL_UNIFORM_BUFFER, 2 * gl->ncalls * gl->uboPosAlignment, 0, GL_STREAM_DRAW); | 
		
	
		
			
			|  |  |  | buff = (char*)glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY); | 
		
	
		
			
			|  |  |  | offset = 0; | 
		
	
		
			
			|  |  |  | for (i = 0; i < gl->ncalls; i++) { | 
		
	
		
			
			|  |  |  | struct GLNVGcall* call = &gl->calls[i]; | 
		
	
		
			
			|  |  |  | struct GLNVGuboFrag* ubo = (struct GLNVGuboFrag*)&buff[offset]; | 
		
	
		
			
			|  |  |  | call->uboOffset = offset; | 
		
	
		
			
			|  |  |  | if (call->type == GLNVG_FILL) { | 
		
	
		
			
			|  |  |  | ubo->type = NSVG_SHADER_SIMPLE; | 
		
	
		
			
			|  |  |  | offset += gl->uboPosAlignment; | 
		
	
		
			
			|  |  |  | ubo = (struct GLNVGuboFrag*)&buff[offset]; | 
		
	
		
			
			|  |  |  | glnvg__setupPaintUBO(gl, &call->paint, &call->scissor, 1.0001f, ubo); | 
		
	
		
			
			|  |  |  | offset += gl->uboPosAlignment; | 
		
	
		
			
			|  |  |  | } else if (call->type == GLNVG_CONVEXFILL) { | 
		
	
		
			
			|  |  |  | glnvg__setupPaintUBO(gl, &call->paint, &call->scissor, 1.0001f, ubo); | 
		
	
		
			
			|  |  |  | offset += gl->uboPosAlignment; | 
		
	
		
			
			|  |  |  | } else if (call->type == GLNVG_STROKE) { | 
		
	
		
			
			|  |  |  | glnvg__setupPaintUBO(gl, &call->paint, &call->scissor, call->strokeWidth, ubo); | 
		
	
		
			
			|  |  |  | offset += gl->uboPosAlignment; | 
		
	
		
			
			|  |  |  | } else if (call->type == GLNVG_TRIANGLES) { | 
		
	
		
			
			|  |  |  | struct GLNVGtexture* tex = glnvg__findTexture(gl, call->paint.image); | 
		
	
		
			
			|  |  |  | glnvg__toFloatColor(ubo->innerCol, call->paint.innerColor); | 
		
	
		
			
			|  |  |  | ubo->texType = tex->type == NVG_TEXTURE_RGBA ? 0 : 1; | 
		
	
		
			
			|  |  |  | ubo->type = NSVG_SHADER_IMG; | 
		
	
		
			
			|  |  |  | offset += gl->uboPosAlignment; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | glUnmapBuffer(GL_UNIFORM_BUFFER); | 
		
	
		
			
			|  |  |  | // Upload ubo for frag shaders | 
		
	
		
			
			|  |  |  | glBindBuffer(GL_UNIFORM_BUFFER, gl->fragBuf); | 
		
	
		
			
			|  |  |  | glBufferData(GL_UNIFORM_BUFFER, gl->nuniforms * gl->fragSize, gl->uniforms, GL_STREAM_DRAW); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Upload vertex data | 
		
	
		
			
			|  |  |  | glBindVertexArray(gl->vertArr); | 
		
	
	
		
			
				|  |  | @@ -813,12 +727,12 @@ static void glnvg__renderFlush(void* uptr) | 
		
	
		
			
			|  |  |  | glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(0 + 2*sizeof(float))); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // once per frame set ubo for view | 
		
	
		
			
			|  |  |  | glBindBuffer(GL_UNIFORM_BUFFER, gl->uboViewBuf); | 
		
	
		
			
			|  |  |  | glBindBuffer(GL_UNIFORM_BUFFER, gl->viewBuf); | 
		
	
		
			
			|  |  |  | glBufferData(GL_UNIFORM_BUFFER, sizeof(gl->view), 0, GL_STREAM_DRAW); | 
		
	
		
			
			|  |  |  | glBufferData(GL_UNIFORM_BUFFER, sizeof(gl->view), gl->view, GL_STREAM_DRAW); | 
		
	
		
			
			|  |  |  | glBindBufferBase(GL_UNIFORM_BUFFER, GLNVG_UBO_VIEW_BINDING, gl->uboViewBuf); | 
		
	
		
			
			|  |  |  | glBindBufferBase(GL_UNIFORM_BUFFER, GLNVG_VIEW_BINDING, gl->viewBuf); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | glBindBuffer(GL_UNIFORM_BUFFER, gl->uboFragBuf); | 
		
	
		
			
			|  |  |  | glBindBuffer(GL_UNIFORM_BUFFER, gl->fragBuf); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | for (i = 0; i < gl->ncalls; i++) { | 
		
	
		
			
			|  |  |  | struct GLNVGcall* call = &gl->calls[i]; | 
		
	
	
		
			
				|  |  | @@ -841,6 +755,7 @@ static void glnvg__renderFlush(void* uptr) | 
		
	
		
			
			|  |  |  | gl->nverts = 0; | 
		
	
		
			
			|  |  |  | gl->npaths = 0; | 
		
	
		
			
			|  |  |  | gl->ncalls = 0; | 
		
	
		
			
			|  |  |  | gl->nuniforms = 0; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static int glnvg__maxVertCount(const struct NVGpath* paths, int npaths) | 
		
	
	
		
			
				|  |  | @@ -891,6 +806,23 @@ static int glnvg__allocVerts(struct GLNVGcontext* gl, int n) | 
		
	
		
			
			|  |  |  | return ret; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static int glnvg__allocFragUniforms(struct GLNVGcontext* gl, int n) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | int ret = 0, structSize = gl->fragSize; | 
		
	
		
			
			|  |  |  | if (gl->nuniforms+n > gl->cuniforms) { | 
		
	
		
			
			|  |  |  | gl->cuniforms = gl->cuniforms == 0 ? glnvg__maxi(n, 32) : gl->cuniforms * 2; | 
		
	
		
			
			|  |  |  | gl->uniforms = (unsigned char*)realloc(gl->uniforms, gl->cuniforms * structSize); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | ret = gl->nuniforms * structSize; | 
		
	
		
			
			|  |  |  | gl->nuniforms += n; | 
		
	
		
			
			|  |  |  | return ret; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static struct GLNVGfragUniforms* nvg__fragUniformPtr(struct GLNVGcontext* gl, int i) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | return (struct GLNVGfragUniforms*)&gl->uniforms[i]; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static void glnvg__vset(struct NVGvertex* vtx, float x, float y, float u, float v) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | vtx->x = x; | 
		
	
	
		
			
				|  |  | @@ -905,41 +837,41 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis | 
		
	
		
			
			|  |  |  | struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; | 
		
	
		
			
			|  |  |  | struct GLNVGcall* call = glnvg__allocCall(gl); | 
		
	
		
			
			|  |  |  | struct NVGvertex* quad; | 
		
	
		
			
			|  |  |  | int i, maxverts, vertsoff; | 
		
	
		
			
			|  |  |  | struct GLNVGfragUniforms* frag; | 
		
	
		
			
			|  |  |  | int i, maxverts, offset; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | call->type = GLNVG_FILL; | 
		
	
		
			
			|  |  |  | call->pathOffset = glnvg__allocPaths(gl, npaths); | 
		
	
		
			
			|  |  |  | call->pathCount = npaths; | 
		
	
		
			
			|  |  |  | call->paint = *paint; | 
		
	
		
			
			|  |  |  | call->scissor = *scissor; | 
		
	
		
			
			|  |  |  | call->image = paint->image; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (npaths == 1 && paths[0].convex) | 
		
	
		
			
			|  |  |  | call->type = GLNVG_CONVEXFILL; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Allocate vertices for all the paths. | 
		
	
		
			
			|  |  |  | maxverts = glnvg__maxVertCount(paths, npaths); | 
		
	
		
			
			|  |  |  | vertsoff = glnvg__allocVerts(gl, maxverts + 6); | 
		
	
		
			
			|  |  |  | offset = glnvg__allocVerts(gl, maxverts + 6); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | for (i = 0; i < npaths; i++) { | 
		
	
		
			
			|  |  |  | struct GLNVGpath* copy = &gl->paths[call->pathOffset + i]; | 
		
	
		
			
			|  |  |  | const struct NVGpath* path = &paths[i]; | 
		
	
		
			
			|  |  |  | memset(copy, 0, sizeof(struct GLNVGpath)); | 
		
	
		
			
			|  |  |  | if (path->nfill) { | 
		
	
		
			
			|  |  |  | copy->fillOffset = vertsoff; | 
		
	
		
			
			|  |  |  | copy->fillOffset = offset; | 
		
	
		
			
			|  |  |  | copy->fillCount = path->nfill; | 
		
	
		
			
			|  |  |  | memcpy(&gl->verts[vertsoff], path->fill, sizeof(struct NVGvertex) * path->nfill); | 
		
	
		
			
			|  |  |  | vertsoff += path->nfill; | 
		
	
		
			
			|  |  |  | memcpy(&gl->verts[offset], path->fill, sizeof(struct NVGvertex) * path->nfill); | 
		
	
		
			
			|  |  |  | offset += path->nfill; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | if (path->nstroke) { | 
		
	
		
			
			|  |  |  | copy->strokeOffset = vertsoff; | 
		
	
		
			
			|  |  |  | copy->strokeOffset = offset; | 
		
	
		
			
			|  |  |  | copy->strokeCount = path->nstroke; | 
		
	
		
			
			|  |  |  | memcpy(&gl->verts[vertsoff], path->stroke, sizeof(struct NVGvertex) * path->nstroke); | 
		
	
		
			
			|  |  |  | vertsoff += path->nstroke; | 
		
	
		
			
			|  |  |  | memcpy(&gl->verts[offset], path->stroke, sizeof(struct NVGvertex) * path->nstroke); | 
		
	
		
			
			|  |  |  | offset += path->nstroke; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Quad | 
		
	
		
			
			|  |  |  | call->triangleOffset = vertsoff; | 
		
	
		
			
			|  |  |  | call->triangleOffset = offset; | 
		
	
		
			
			|  |  |  | call->triangleCount = 6; | 
		
	
		
			
			|  |  |  | quad = &gl->verts[call->triangleOffset]; | 
		
	
		
			
			|  |  |  | glnvg__vset(&quad[0], bounds[0], bounds[3], 0.5f, 1.0f); | 
		
	
	
		
			
				|  |  | @@ -949,37 +881,53 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis | 
		
	
		
			
			|  |  |  | glnvg__vset(&quad[3], bounds[0], bounds[3], 0.5f, 1.0f); | 
		
	
		
			
			|  |  |  | glnvg__vset(&quad[4], bounds[2], bounds[1], 0.5f, 1.0f); | 
		
	
		
			
			|  |  |  | glnvg__vset(&quad[5], bounds[0], bounds[1], 0.5f, 1.0f); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Setup uniforms for draw calls | 
		
	
		
			
			|  |  |  | if (call->type == GLNVG_FILL) { | 
		
	
		
			
			|  |  |  | call->uniformOffset = glnvg__allocFragUniforms(gl, 2); | 
		
	
		
			
			|  |  |  | // Simple shader for stencil | 
		
	
		
			
			|  |  |  | frag = nvg__fragUniformPtr(gl, call->uniformOffset); | 
		
	
		
			
			|  |  |  | frag->type = NSVG_SHADER_SIMPLE; | 
		
	
		
			
			|  |  |  | // Fill shader | 
		
	
		
			
			|  |  |  | glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset + gl->fragSize), paint, scissor, 1.0001f); | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | call->uniformOffset = glnvg__allocFragUniforms(gl, 1); | 
		
	
		
			
			|  |  |  | // Fill shader | 
		
	
		
			
			|  |  |  | glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset), paint, scissor, 1.0001f); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, | 
		
	
		
			
			|  |  |  | float width, const struct NVGpath* paths, int npaths) | 
		
	
		
			
			|  |  |  | float strokeWidth, const struct NVGpath* paths, int npaths) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; | 
		
	
		
			
			|  |  |  | struct GLNVGcall* call = glnvg__allocCall(gl); | 
		
	
		
			
			|  |  |  | int i, maxverts, vertsoff; | 
		
	
		
			
			|  |  |  | int i, maxverts, offset; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | call->type = GLNVG_STROKE; | 
		
	
		
			
			|  |  |  | call->pathOffset = glnvg__allocPaths(gl, npaths); | 
		
	
		
			
			|  |  |  | call->pathCount = npaths; | 
		
	
		
			
			|  |  |  | call->paint = *paint; | 
		
	
		
			
			|  |  |  | call->scissor = *scissor; | 
		
	
		
			
			|  |  |  | call->strokeWidth = width; | 
		
	
		
			
			|  |  |  | call->image = paint->image; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Allocate vertices for all the paths. | 
		
	
		
			
			|  |  |  | maxverts = glnvg__maxVertCount(paths, npaths); | 
		
	
		
			
			|  |  |  | vertsoff = glnvg__allocVerts(gl, maxverts + 6); | 
		
	
		
			
			|  |  |  | offset = glnvg__allocVerts(gl, maxverts + 6); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | for (i = 0; i < npaths; i++) { | 
		
	
		
			
			|  |  |  | struct GLNVGpath* copy = &gl->paths[call->pathOffset + i]; | 
		
	
		
			
			|  |  |  | const struct NVGpath* path = &paths[i]; | 
		
	
		
			
			|  |  |  | memset(copy, 0, sizeof(struct GLNVGpath)); | 
		
	
		
			
			|  |  |  | if (path->nstroke) { | 
		
	
		
			
			|  |  |  | copy->strokeOffset = vertsoff; | 
		
	
		
			
			|  |  |  | copy->strokeOffset = offset; | 
		
	
		
			
			|  |  |  | copy->strokeCount = path->nstroke; | 
		
	
		
			
			|  |  |  | memcpy(&gl->verts[vertsoff], path->stroke, sizeof(struct NVGvertex) * path->nstroke); | 
		
	
		
			
			|  |  |  | vertsoff += path->nstroke; | 
		
	
		
			
			|  |  |  | memcpy(&gl->verts[offset], path->stroke, sizeof(struct NVGvertex) * path->nstroke); | 
		
	
		
			
			|  |  |  | offset += path->nstroke; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Fill shader | 
		
	
		
			
			|  |  |  | call->uniformOffset = glnvg__allocFragUniforms(gl, 1); | 
		
	
		
			
			|  |  |  | glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset), paint, scissor, strokeWidth); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, | 
		
	
	
		
			
				|  |  | @@ -987,15 +935,21 @@ static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NV | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; | 
		
	
		
			
			|  |  |  | struct GLNVGcall* call = glnvg__allocCall(gl); | 
		
	
		
			
			|  |  |  | struct GLNVGfragUniforms* frag; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | call->type = GLNVG_TRIANGLES; | 
		
	
		
			
			|  |  |  | call->paint = *paint; | 
		
	
		
			
			|  |  |  | call->scissor = *scissor; | 
		
	
		
			
			|  |  |  | call->image = paint->image; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Allocate vertices for all the paths. | 
		
	
		
			
			|  |  |  | call->triangleOffset = glnvg__allocVerts(gl, nverts); | 
		
	
		
			
			|  |  |  | call->triangleCount = nverts; | 
		
	
		
			
			|  |  |  | memcpy(&gl->verts[call->triangleOffset], verts, sizeof(struct NVGvertex) * nverts); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Fill shader | 
		
	
		
			
			|  |  |  | call->uniformOffset = glnvg__allocFragUniforms(gl, 1); | 
		
	
		
			
			|  |  |  | frag = nvg__fragUniformPtr(gl, call->uniformOffset); | 
		
	
		
			
			|  |  |  | glnvg__convertPaint(gl, frag, paint, scissor, 1.0f); | 
		
	
		
			
			|  |  |  | frag->type = NSVG_SHADER_IMG; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static void glnvg__renderDelete(void* uptr) | 
		
	
	
		
			
				|  |  | @@ -1006,6 +960,15 @@ static void glnvg__renderDelete(void* uptr) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | glnvg__deleteShader(&gl->shader); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (gl->vertArr != 0) | 
		
	
		
			
			|  |  |  | glDeleteVertexArrays(1, &gl->vertArr); | 
		
	
		
			
			|  |  |  | if (gl->vertBuf != 0) | 
		
	
		
			
			|  |  |  | glDeleteBuffers(1, &gl->vertBuf); | 
		
	
		
			
			|  |  |  | if (gl->viewBuf != 0) | 
		
	
		
			
			|  |  |  | glDeleteBuffers(1, &gl->viewBuf); | 
		
	
		
			
			|  |  |  | if (gl->fragBuf != 0) | 
		
	
		
			
			|  |  |  | glDeleteBuffers(1, &gl->fragBuf); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | for (i = 0; i < gl->ntextures; i++) { | 
		
	
		
			
			|  |  |  | if (gl->textures[i].tex != 0) | 
		
	
		
			
			|  |  |  | glDeleteTextures(1, &gl->textures[i].tex); | 
		
	
	
		
			
				|  |  | 
 |