k3/src/k3batch.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();
}
}