#include"k3batch.h" #include"gl.h" #include #include"k3_internal.h" struct S { struct k3RectF src; struct k3RectF dst; vec4 color; float rot; char additive; }; static struct k3Tex *activeTex; static float activeBorderRadius; static size_t SCount, SCapacity; static struct S *S; static struct k3GLSLP *coreProg; static GLuint coreVBO; static GLuint coreUResolution; static float ResolutionX; static float ResolutionY; void k3BatchInit() { if(k3IsCore) { coreProg = k3ProgramGLSL(k3ShaderGLSLV( "#version 330\n" "in vec2 a_pos;\n" "in vec2 a_uv;\n" "in vec4 a_color;\n" "in vec2 a_size;\n" "out vec2 v_uv;\n" "out vec4 v_color;\n" "out vec2 v_size;\n" "uniform vec2 u_resolution;\n" "void main() {\n" " v_uv = a_uv;\n" " v_color = a_color;\n" " v_size = a_size;\n" " gl_Position = vec4(vec2(a_pos.x / u_resolution.x, a_pos.y / u_resolution.y) * 2.0 - 1.0, 0.0, 1.0);\n" "}\n" , NULL), k3ShaderGLSLF( "#version 330\n" "uniform sampler2D u_tex;\n" "uniform float u_texuse;\n" "uniform float u_borderradius;\n" "in vec2 v_uv;\n" "in vec4 v_color;\n" "in vec2 v_size;\n" "out vec4 fragcolor;\n" "void main() {\n" " vec2 sz = v_size / 2.0;\n" " vec2 c = abs(v_uv * 2.0 - 1.0);\n" " c = c * (sz + u_borderradius);\n" " c = max(c - sz, 0.0);\n" " if(length(c) > u_borderradius) {\n" " discard;\n" " }\n" " fragcolor = mix(vec4(1, 1, 1, 1), texture2D(u_tex, v_uv), u_texuse) * v_color;\n" "}\n" , NULL), NULL); coreUResolution = k3ProgramGetUId(coreProg, "u_resolution"); glGenBuffers(1, &coreVBO); } } void k3BatchAdd(struct k3Tex *tex, struct k3RectF src, struct k3RectF dst, float rot, vec4 color, float borderRadius) { if(activeTex != tex || borderRadius != activeBorderRadius) { k3BatchFlush(); activeTex = tex; activeBorderRadius = borderRadius; } if(SCount == SCapacity) { struct S *new = _mm_malloc(sizeof(*S) * (SCapacity + 32), 16); if(S) { memcpy(new, S, sizeof(*S) * SCapacity); _mm_free(S); } S = new; SCapacity += 32; } S[SCount++] = (struct S) { .src = src, .dst = dst, .rot = rot, .color = {color[0], color[1], color[2], color[3]}, }; } void k3BatchFlush() { if(!S) return; if(!k3IsCore) { glDisable(GL_NORMALIZE); // Some drivers crash on glEnable(GL_LIGHTING) *AND* glDisable(GL_LIGHTING) for some reason // Just don't do it unless fixed-function is explicitly on glDisable(GL_LIGHTING); if(!GLAD_GL_ARB_shading_language_100) { } } glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); if(GLAD_GL_ARB_vertex_program) { glDisable(GL_VERTEX_PROGRAM_ARB); } if(GLAD_GL_ARB_fragment_program) { glDisable(GL_FRAGMENT_PROGRAM_ARB); } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glActiveTexture(GL_TEXTURE0); if(activeTex) { if(!k3IsCore) glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, *(GLuint*) activeTex); } else { if(!k3IsCore) glDisable(GL_TEXTURE_2D); } if(k3IsCore) { glUseProgram((GLuint) coreProg); glUniform2f(coreUResolution, ResolutionX, ResolutionY); float *farr = alloca(SCount * 60 * sizeof(*farr)); struct S *s = S; for(size_t i = 0; i < SCount; i++) { farr[i * 60 + 0] = s->dst.x; farr[i * 60 + 1] = s->dst.y; farr[i * 60 + 2] = s->src.x; farr[i * 60 + 3] = s->src.y + s->src.h; farr[i * 60 + 4] = s->color[0]; farr[i * 60 + 5] = s->color[1]; farr[i * 60 + 6] = s->color[2]; farr[i * 60 + 7] = s->color[3]; farr[i * 60 + 8] = s->dst.w; farr[i * 60 + 9] = s->dst.h; farr[i * 60 + 10] = s->dst.x + s->dst.w; farr[i * 60 + 11] = s->dst.y; farr[i * 60 + 12] = s->src.x + s->src.w; farr[i * 60 + 13] = s->src.y + s->src.h; farr[i * 60 + 14] = s->color[0]; farr[i * 60 + 15] = s->color[1]; farr[i * 60 + 16] = s->color[2]; farr[i * 60 + 17] = s->color[3]; farr[i * 60 + 18] = s->dst.w; farr[i * 60 + 19] = s->dst.h; farr[i * 60 + 20] = s->dst.x + s->dst.w; farr[i * 60 + 21] = s->dst.y + s->dst.h; farr[i * 60 + 22] = s->src.x + s->src.w; farr[i * 60 + 23] = s->src.y; farr[i * 60 + 24] = s->color[0]; farr[i * 60 + 25] = s->color[1]; farr[i * 60 + 26] = s->color[2]; farr[i * 60 + 27] = s->color[3]; farr[i * 60 + 28] = s->dst.w; farr[i * 60 + 29] = s->dst.h; farr[i * 60 + 30] = s->dst.x; farr[i * 60 + 31] = s->dst.y; farr[i * 60 + 32] = s->src.x; farr[i * 60 + 33] = s->src.y + s->src.h; farr[i * 60 + 34] = s->color[0]; farr[i * 60 + 35] = s->color[1]; farr[i * 60 + 36] = s->color[2]; farr[i * 60 + 37] = s->color[3]; farr[i * 60 + 38] = s->dst.w; farr[i * 60 + 39] = s->dst.h; farr[i * 60 + 40] = s->dst.x + s->dst.w; farr[i * 60 + 41] = s->dst.y + s->dst.h; farr[i * 60 + 42] = s->src.x + s->src.w; farr[i * 60 + 43] = s->src.y; farr[i * 60 + 44] = s->color[0]; farr[i * 60 + 45] = s->color[1]; farr[i * 60 + 46] = s->color[2]; farr[i * 60 + 47] = s->color[3]; farr[i * 60 + 48] = s->dst.w; farr[i * 60 + 49] = s->dst.h; farr[i * 60 + 50] = s->dst.x; farr[i * 60 + 51] = s->dst.y + s->dst.h; farr[i * 60 + 52] = s->src.x; farr[i * 60 + 53] = s->src.y; farr[i * 60 + 54] = s->color[0]; farr[i * 60 + 55] = s->color[1]; farr[i * 60 + 56] = s->color[2]; farr[i * 60 + 57] = s->color[3]; farr[i * 60 + 58] = s->dst.w; farr[i * 60 + 59] = s->dst.h; s++; } glBindBufferARB(GL_ARRAY_BUFFER_ARB, coreVBO); glBufferDataARB(GL_ARRAY_BUFFER_ARB, SCount * 60 * sizeof(*farr), farr, GL_DYNAMIC_DRAW); glUniform1f(glGetUniformLocation((GLuint) coreProg, "u_texuse"), !!activeTex); glUniform1f(glGetUniformLocation((GLuint) coreProg, "u_borderradius"), activeBorderRadius); GLint aPos = glGetAttribLocation((GLuint) coreProg, "a_pos"); GLint aUv = glGetAttribLocation((GLuint) coreProg, "a_uv"); GLint aColor = glGetAttribLocation((GLuint) coreProg, "a_color"); GLint aSize = glGetAttribLocation((GLuint) coreProg, "a_size"); glEnableVertexAttribArray(aPos); glEnableVertexAttribArray(aUv); glEnableVertexAttribArray(aColor); glEnableVertexAttribArray(aSize); glVertexAttribPointer(aPos, 2, GL_FLOAT, GL_FALSE, 40, (void*) 0); glVertexAttribPointer(aUv, 2, GL_FLOAT, GL_FALSE, 40, (void*) 8); glVertexAttribPointer(aColor, 4, GL_FLOAT, GL_FALSE, 40, (void*) 16); glVertexAttribPointer(aSize, 2, GL_FLOAT, GL_FALSE, 40, (void*) 32); glDrawArrays(GL_TRIANGLES, 0, SCount * 6); glDisableVertexAttribArray(aPos); glDisableVertexAttribArray(aUv); glDisableVertexAttribArray(aColor); glDisableVertexAttribArray(aSize); } else { if(GLAD_GL_ARB_shading_language_100) { glUseProgramObjectARB(0); } glBegin(GL_QUADS); struct S *s = S; for(size_t i = 0; i < SCount; i++) { glColor4f(s->color[0], s->color[1], s->color[2], s->color[3]); glTexCoord2f(s->src.x, s->src.y + s->src.h); glVertex2f(s->dst.x, s->dst.y); glTexCoord2f(s->src.x + s->src.w, s->src.y + s->src.h); glVertex2f(s->dst.x + s->dst.w, s->dst.y); glTexCoord2f(s->src.x + s->src.w, s->src.y); glVertex2f(s->dst.x + s->dst.w, s->dst.y + s->dst.h); glTexCoord2f(s->src.x, s->src.y); glVertex2f(s->dst.x, s->dst.y + s->dst.h); s++; } glEnd(); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } SCount = 0; } void k3BatchSetResolution(float w, float h) { ResolutionX = w; ResolutionY = h; if(!k3IsCore) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, ResolutionX, 0, ResolutionY, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } }