155 lines
3.8 KiB
C
155 lines
3.8 KiB
C
/**
|
|
* 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.
|
|
for(uint32_t i = 0; i < count; i++ ){
|
|
spritebatchsprite_t sprite = sprites[i];
|
|
|
|
meshvertex_t *v = &SPRITEBATCH_VERTICES[
|
|
(SPRITEBATCH.spriteCount + (SPRITEBATCH.spriteFlush *
|
|
SPRITEBATCH_SPRITES_MAX_PER_FLUSH)) * 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];
|
|
|
|
// Do we need to flush?
|
|
SPRITEBATCH.spriteCount++;
|
|
if(SPRITEBATCH.spriteCount >= SPRITEBATCH_SPRITES_MAX_PER_FLUSH) {
|
|
errorChain(spriteBatchFlush());
|
|
}
|
|
}
|
|
|
|
errorOk();
|
|
}
|
|
|
|
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();
|
|
}
|