prog
This commit is contained in:
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user