283 lines
7.5 KiB
C
283 lines
7.5 KiB
C
#include"k3batch.h"
|
|
|
|
#include"gl.h"
|
|
#include<string.h>
|
|
#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();
|
|
}
|
|
}
|