This commit is contained in:
2026-06-18 20:25:54 -05:00
parent 730a5b2b10
commit 57b2cdb9d1
111 changed files with 865 additions and 3328 deletions
@@ -0,0 +1,179 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "spritebatch.h"
#include "assert/assert.h"
#include "util/memory.h"
#include "util/math.h"
#include "display/shader/shadermaterial.h"
meshvertex_t SPRITEBATCH_VERTICES[SPRITEBATCH_VERTEX_COUNT];
spritebatch_t SPRITEBATCH;
errorret_t spriteBatchInit() {
memoryZero(&SPRITEBATCH, sizeof(spritebatch_t));
errorChain(meshInit(
&SPRITEBATCH.mesh,
QUAD_PRIMITIVE_TYPE,
SPRITEBATCH_VERTEX_COUNT,
SPRITEBATCH_VERTICES
));
errorOk();
}
errorret_t spriteBatchBuffer(
const spritebatchsprite_t *sprites,
const uint32_t count,
shader_t *shader,
const shadermaterial_t material
) {
assertNotNull(sprites, "Sprites cannot be null");
assertTrue(count > 0, "Count must be greater than zero");
assertNotNull(shader, "Shader cannot be null");
// Did the shader or material data change?
if(shader != SPRITEBATCH.shader) {
errorChain(spriteBatchFlush());
SPRITEBATCH.shader = shader;
SPRITEBATCH.material = material;
} else if(memoryCompare(
&material, &SPRITEBATCH.material, sizeof(shadermaterial_t)
) != 0) {
// Did the material data change?
errorChain(spriteBatchFlush());
SPRITEBATCH.shader = shader;
SPRITEBATCH.material = material;
}
// Buffer the vertices.
uint32_t remaining = count;
do {
uint32_t spritesBeforeFlush = (
SPRITEBATCH_SPRITES_MAX_PER_FLUSH - SPRITEBATCH.spriteCount
);
if(spritesBeforeFlush == 0) {
// Flush if we have no capacity before flushing.
errorChain(spriteBatchFlush());
spritesBeforeFlush = SPRITEBATCH_SPRITES_MAX_PER_FLUSH;
}
// Many we buffering?
const uint32_t batchCount = mathMin(
remaining,
spritesBeforeFlush
);
// Destination
meshvertex_t *v = &SPRITEBATCH_VERTICES[
(SPRITEBATCH.spriteCount + (SPRITEBATCH.spriteFlush *
SPRITEBATCH_SPRITES_MAX_PER_FLUSH)) * QUAD_VERTEX_COUNT
];
// Buffer to the mesh vertices.
spriteBatchBufferToMesh(
sprites, batchCount, v, batchCount * QUAD_VERTEX_COUNT
);
SPRITEBATCH.spriteCount += batchCount;
remaining -= batchCount;
} while(remaining > 0);
errorOk();
}
void spriteBatchBufferToMesh(
const spritebatchsprite_t *sprites,
const uint32_t count,
meshvertex_t *vertices,
const uint32_t verticesSize
) {
assertNotNull(sprites, "Sprites cannot be null");
assertTrue(count > 0, "Count must be greater than zero");
assertNotNull(vertices, "Vertices cannot be null");
assertTrue(
verticesSize >= count * QUAD_VERTEX_COUNT, "Vertices array too small"
);
for(uint32_t i = 0; i < count; i++ ){
spritebatchsprite_t sprite = sprites[i];
meshvertex_t *v = &vertices[i * QUAD_VERTEX_COUNT];
// Buffer the quad
v[0].pos[0] = sprite.min[0];
v[0].pos[1] = sprite.min[1];
v[0].pos[2] = sprite.min[2];
v[0].uv[0] = sprite.uvMin[0];
v[0].uv[1] = sprite.uvMin[1];
v[1].pos[0] = sprite.max[0];
v[1].pos[1] = sprite.min[1];
v[1].pos[2] = sprite.min[2];
v[1].uv[0] = sprite.uvMax[0];
v[1].uv[1] = sprite.uvMin[1];
v[2].pos[0] = sprite.max[0];
v[2].pos[1] = sprite.max[1];
v[2].pos[2] = sprite.max[2];
v[2].uv[0] = sprite.uvMax[0];
v[2].uv[1] = sprite.uvMax[1];
v[3].pos[0] = sprite.min[0];
v[3].pos[1] = sprite.min[1];
v[3].pos[2] = sprite.min[2];
v[3].uv[0] = sprite.uvMin[0];
v[3].uv[1] = sprite.uvMin[1];
v[4].pos[0] = sprite.max[0];
v[4].pos[1] = sprite.max[1];
v[4].pos[2] = sprite.max[2];
v[4].uv[0] = sprite.uvMax[0];
v[4].uv[1] = sprite.uvMax[1];
v[5].pos[0] = sprite.min[0];
v[5].pos[1] = sprite.max[1];
v[5].pos[2] = sprite.max[2];
v[5].uv[0] = sprite.uvMin[0];
v[5].uv[1] = sprite.uvMax[1];
}
}
void spriteBatchClear() {
SPRITEBATCH.spriteCount = 0;
SPRITEBATCH.spriteFlush = 0;
SPRITEBATCH.shader = NULL;
memoryZero(&SPRITEBATCH.material, sizeof(shadermaterial_t));
}
errorret_t spriteBatchFlush() {
if(SPRITEBATCH.spriteCount == 0) {
errorOk();
}
size_t vertexCount = QUAD_VERTEX_COUNT * SPRITEBATCH.spriteCount;
size_t vertexOffset = (
SPRITEBATCH.spriteFlush * SPRITEBATCH_SPRITES_MAX_PER_FLUSH *
QUAD_VERTEX_COUNT
);
errorChain(shaderBind(SPRITEBATCH.shader));
errorChain(shaderSetMaterial(SPRITEBATCH.shader, &SPRITEBATCH.material));
errorChain(meshFlush(&SPRITEBATCH.mesh, vertexOffset, vertexCount));
errorChain(meshDraw(&SPRITEBATCH.mesh, vertexOffset, vertexCount));
SPRITEBATCH.spriteFlush++;
if(SPRITEBATCH.spriteFlush >= SPRITEBATCH_FLUSH_COUNT) {
SPRITEBATCH.spriteFlush = 0;
}
SPRITEBATCH.spriteCount = 0;
errorOk();
}
errorret_t spriteBatchDispose() {
errorChain(meshDispose(&SPRITEBATCH.mesh));
errorOk();
}