Files
dusk/.claude/display-spritebatch.md
T
2026-06-16 12:29:36 -05:00

134 lines
3.6 KiB
Markdown

# Display -- SpriteBatch
Source: `src/dusk/display/spritebatch/`
See also: `.claude/display-mesh.md`, `.claude/display-texture.md`
---
## Overview
The SpriteBatch is the primary 2D rendering primitive. It accumulates
axis-aligned quads (sprites) into a shared vertex buffer and draws them
in batches. All 2D rendering in the engine -- UI frames, text, tilemaps,
HUD -- goes through the global `SPRITEBATCH`.
The batch flushes automatically when the per-flush limit is reached, or
explicitly via `spriteBatchFlush()`.
---
## Limits
| Constant | Value | Meaning |
|----------|-------|---------|
| `SPRITEBATCH_SPRITES_MAX` | 512 | Total sprites in the vertex buffer |
| `SPRITEBATCH_FLUSH_COUNT` | 16 | Number of auto-flush segments |
| `SPRITEBATCH_SPRITES_MAX_PER_FLUSH` | 32 | Sprites per auto-flush segment |
| `SPRITEBATCH_VERTEX_COUNT` | 3072 | Total vertices (512 * QUAD_VERTEX_COUNT) |
---
## Sprite structure
```c
typedef struct {
vec3 min; // minimum XYZ corner of the quad in world/screen space
vec3 max; // maximum XYZ corner of the quad in world/screen space
vec2 uvMin; // minimum UV (top-left in [0,1] texture space)
vec2 uvMax; // maximum UV (bottom-right in [0,1] texture space)
} spritebatchsprite_t;
```
Z in `min` and `max` controls draw depth (further from camera = higher Z
in a typical orthographic setup). For flat 2D, set `min.z = max.z = 0`.
---
## SpriteBatch struct
```c
typedef struct {
mesh_t mesh;
int32_t spriteCount;
int32_t spriteFlush;
shader_t *shader;
shadermaterial_t material;
} spritebatch_t;
extern spritebatch_t SPRITEBATCH;
extern meshvertex_t SPRITEBATCH_VERTICES[SPRITEBATCH_VERTEX_COUNT];
```
`SPRITEBATCH_VERTICES` is a separate global (not embedded in the struct)
for platform alignment requirements.
---
## API
```c
errorret_t spriteBatchInit();
errorret_t spriteBatchDispose();
// Clear the buffer and reset state. Call before starting a new batch.
void spriteBatchClear();
// Append sprites to the buffer. Flushes automatically when the per-flush
// segment fills. shader + material are used on the next flush.
errorret_t spriteBatchBuffer(
const spritebatchsprite_t *sprites,
const uint32_t count,
shader_t *shader,
const shadermaterial_t material
);
// Upload and draw all buffered sprites. Binds shader and applies
// material if set. No-op if the buffer is empty.
errorret_t spriteBatchFlush();
```
---
## Typical usage
```c
// Beginning of a 2D render pass:
spriteBatchClear();
// Build sprites (e.g. via tilesetTileGetUV, then fill spritebatchsprite_t):
spritebatchsprite_t s;
glm_vec3_copy((vec3){ x, y, 0 }, s.min);
glm_vec3_copy((vec3){ x + w, y + h, 0 }, s.max);
glm_vec2_copy(uvMin, s.uvMin);
glm_vec2_copy(uvMax, s.uvMax);
shadermaterial_t mat = { .unlit = { .texture = myTexture } };
spriteBatchBuffer(&s, 1, myShader, mat);
// End of pass -- flush remaining sprites:
spriteBatchFlush();
```
---
## Relationship to other systems
- **Text rendering** (`textDraw`) internally calls `spriteBatchBuffer`
for each glyph and requires a final `spriteBatchFlush()` after drawing.
- **UI frames** (`uiFrameDraw`) push 9 quads to the batch without
flushing -- the caller or `uitextboxDraw` is responsible for the flush.
- **ECS renderables** of type `ENTITY_RENDERABLE_TYPE_SPRITEBATCH` are
drawn via the spritebatch in the scene render pipeline.
---
## Notes
- `spriteBatchBuffer` changes the batch's `shader` and `material` fields.
If you mix different shaders or textures in one batch, add an explicit
`spriteBatchFlush()` call between groups to avoid draws with the wrong
material.
- The vertex buffer is a static global -- `SPRITEBATCH_VERTICES` must
not be written from multiple threads.