gfx: Sprite: sort/draw sprites back-to-front always

Prior to this change sprite draw order was not something we could specify,
now we can by changing the Z value of sprites (sprites further away / with
greater Z values are drawn first), which is obviously desirable for layering
and alpha blending purposes.

The implementation here is rather naive: we sort all sprites each frame based
on their Z value; but its performance is quite good with ~half a million sprites
and so is good enough for now.

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
Stephen Gutekanst 2024-05-22 18:13:26 -07:00
parent 1237858359
commit b261a8177f

View file

@ -96,6 +96,31 @@ fn updatePipeline(
} }
} }
// Sort sprites back-to-front for draw order, alpha blending
const Context = struct {
transforms: []Mat4x4,
uv_transforms: []Mat3x3,
sizes: []Vec2,
pub fn lessThan(ctx: @This(), a: usize, b: usize) bool {
const a_z = ctx.transforms[a].translation().z();
const b_z = ctx.transforms[b].translation().z();
// Greater z values are further away, and thus should render/sort before those with lesser z values.
return a_z > b_z;
}
pub fn swap(ctx: @This(), a: usize, b: usize) void {
std.mem.swap(Mat4x4, &ctx.transforms[a], &ctx.transforms[b]);
std.mem.swap(Mat3x3, &ctx.uv_transforms[a], &ctx.uv_transforms[b]);
std.mem.swap(Vec2, &ctx.sizes[a], &ctx.sizes[b]);
}
};
std.sort.pdqContext(0, i, Context{
.transforms = gfx.SpritePipeline.cp_transforms[0..i],
.uv_transforms = gfx.SpritePipeline.cp_uv_transforms[0..i],
.sizes = gfx.SpritePipeline.cp_sizes[0..i],
});
// TODO: optimize by removing this component set call and instead use a .write() query // TODO: optimize by removing this component set call and instead use a .write() query
try sprite_pipeline.set(pipeline_id, .num_sprites, num_sprites); try sprite_pipeline.set(pipeline_id, .num_sprites, num_sprites);
if (num_sprites > 0) { if (num_sprites > 0) {