allow creation of non-atlas sprites

This commit is contained in:
jacob 2026-02-24 03:04:25 -06:00
parent 3fd910702f
commit 262d49fee8
3 changed files with 92 additions and 49 deletions

View File

@ -316,7 +316,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncFrameLaneCtx *base_async_lane_frame)
gpu_perm, cl,
G_Format_R8G8B8A8_Unorm_Srgb,
atlas->dims,
G_Layout_Simultaneous,
G_Layout_Simultaneous, // Simultaneous because atlas will be written asynchronously during regular reads
.name = Lit("Glyph atlas")
);
atlas->tex = G_PushTexture2DRef(gpu_perm, atlas->tex_res);

View File

@ -5,7 +5,22 @@ SPR_Ctx SPR = Zi;
void SPR_Bootstrap(void)
{
// FIXME: Initialize nil/unready sprite texture here
G_ArenaHandle gpu_perm = G_PermArena();
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct);
{
G_ResourceHandle unready_tex_res = G_PushTexture2D(
gpu_perm, cl,
G_Format_R8G8B8A8_Unorm,
VEC2I32(8, 8),
G_Layout_Common,
.flags = G_ResourceFlag_ZeroMemory,
.name = Lit("Sprite unready texture")
);
SPR.unready_tex = G_PushTexture2DRef(gpu_perm, unready_tex_res);
SPR.unready_tex_dims = Vec2FromVec(G_Count2D(unready_tex_res));
}
G_CommitCommandList(cl);
G_QueueSync(G_QueueMask_Direct, G_QueueMask_All);
OnAsyncTick(SPR_TickAsync);
}
@ -65,7 +80,7 @@ SPR_LayerKind SPR_LayerKindFromName(String name)
////////////////////////////////////////////////////////////
//~ Lookup
SPR_Sprite SPR_SpriteFromSheet(SPR_SheetKey sheet_key, SPR_SpanKey span_key, i64 frame_seq)
SPR_Sprite SPR_SpriteFromSheetEx(SPR_SheetKey sheet_key, SPR_SpanKey span_key, i64 frame_seq, SPR_SheetFlag flags)
{
//////////////////////////////
//- Fetch sheet
@ -77,7 +92,7 @@ SPR_Sprite SPR_SpriteFromSheet(SPR_SheetKey sheet_key, SPR_SpanKey span_key, i64
{
for (sheet = sheet_bin->first; sheet; sheet = sheet->next_in_bin)
{
if (sheet->key.r.v == sheet_key.r.v)
if (sheet->key.r.v == sheet_key.r.v && sheet->flags == flags)
{
break;
}
@ -107,6 +122,7 @@ SPR_Sprite SPR_SpriteFromSheet(SPR_SheetKey sheet_key, SPR_SpanKey span_key, i64
sheet = PushStruct(perm, SPR_SheetEntry);
SllStackPushN(sheet_bin->first, sheet, next_in_bin);
sheet->key = sheet_key;
sheet->flags = flags;
String sheet_data = DataFromResource(sheet->key.r);
String sheet_name = NameFromResource(sheet->key.r);
@ -344,6 +360,11 @@ SPR_Sprite SPR_SpriteFromSheet(SPR_SheetKey sheet_key, SPR_SpanKey span_key, i64
return result;
}
SPR_Sprite SPR_SpriteFromSheet(SPR_SheetKey sheet_key, SPR_SpanKey span_key, i64 frame_seq)
{
return SPR_SpriteFromSheetEx(sheet_key, span_key, frame_seq, SPR_SheetFlag_None);
}
////////////////////////////////////////////////////////////
//~ Async
@ -389,10 +410,6 @@ void SPR_TickAsync(WaveLaneCtx *lane, AsyncFrameLaneCtx *base_async_lane_frame)
SPR_SheetEntry *sheet = cmd->sheet;
ASE_Meta meta = sheet->meta;
// String encoded = DataFromResource(sheet->key.r);
// String name = NameFromResource(sheet->key.r);
// LogInfoF("Rasterizing sprite sheet %F \"%F\" (%F bytes)", FmtHandle(sheet->key.r), FmtString(name), FmtUint(encoded.len));
SPR_SliceEntry *slice = &sheet->slices[cmd->slice_idx];
Vec2 slice_dims = DimsFromRng2(slice->canvas_rect);
@ -421,49 +438,69 @@ void SPR_TickAsync(WaveLaneCtx *lane, AsyncFrameLaneCtx *base_async_lane_frame)
//////////////////////////////
//- Write atlas
// TODO: Use a more efficient atlas packing algorithm for less wasted space
SPR_Atlas *atlas = SPR.first_atlas;
b32 can_use_atlas = 0;
Vec2I32 atlas_pos = Zi;
while (can_use_atlas == 0)
SPR_Atlas *atlas = 0;
if (AnyBit(sheet->flags, SPR_SheetFlag_NoAtlas) && slice_dims.x > 0 && slice_dims.y > 0)
{
// Create atlas
if (!atlas)
atlas = PushStruct(perm, SPR_Atlas);
atlas->dims = Vec2I32FromVec(slice_dims);
{
atlas = PushStruct(perm, SPR_Atlas);
i32 atlas_size = MaxI32(1024, NextPow2U64(MaxI32(slice_dims.x, slice_dims.y)));
atlas->dims = VEC2I32(atlas_size, atlas_size);
G_ArenaHandle gpu_perm = G_PermArena();
atlas->tex_res = G_PushTexture2D(
gpu_perm, cl,
G_Format_R8G8B8A8_Unorm_Srgb,
atlas->dims,
G_Layout_Common,
.name = Lit("Isolated sprite texture")
);
atlas->tex = G_PushTexture2DRef(gpu_perm, atlas->tex_res);
}
}
else
{
// TODO: Use a more efficient atlas packing algorithm for less wasted space
atlas = SPR.first_atlas;
b32 can_use_atlas = 0;
while (can_use_atlas == 0)
{
// Create atlas
if (!atlas)
{
G_ArenaHandle gpu_perm = G_PermArena();
atlas->tex_res = G_PushTexture2D(
gpu_perm, cl,
G_Format_R8G8B8A8_Unorm_Srgb,
atlas->dims,
G_Layout_Simultaneous,
.name = Lit("Sprite atlas")
);
atlas->tex = G_PushTexture2DRef(gpu_perm, atlas->tex_res);
atlas = PushStruct(perm, SPR_Atlas);
i32 atlas_size = MaxI32(1024, NextPow2U64(MaxI32(slice_dims.x, slice_dims.y)));
atlas->dims = VEC2I32(atlas_size, atlas_size);
{
G_ArenaHandle gpu_perm = G_PermArena();
atlas->tex_res = G_PushTexture2D(
gpu_perm, cl,
G_Format_R8G8B8A8_Unorm_Srgb,
atlas->dims,
G_Layout_Simultaneous, // Simultaneous because atlas will be written asynchronously during regular reads
.name = StringF(perm, "Sprite atlas #%F", FmtSint(SPR.atlases_count))
);
atlas->tex = G_PushTexture2DRef(gpu_perm, atlas->tex_res);
}
SllStackPush(SPR.first_atlas, atlas);
++SPR.atlases_count;
}
if (atlas->cur_pos.x + slice_dims.x > atlas->dims.x)
{
atlas->cur_pos.x = 0;
atlas->cur_pos.y += atlas->cur_row_height;
atlas->cur_row_height = 0;
}
if (atlas->cur_pos.x + slice_dims.x <= atlas->dims.x && atlas->cur_pos.y + slice_dims.y <= atlas->dims.y)
{
atlas_pos = atlas->cur_pos;
atlas->cur_row_height = MaxI32(atlas->cur_row_height, slice_dims.y);
atlas->cur_pos.x += slice_dims.x;
can_use_atlas = 1;
}
else
{
// New atlas required
atlas = 0;
}
SllStackPush(SPR.first_atlas, atlas);
++SPR.atlases_count;
}
if (atlas->cur_pos.x + slice_dims.x > atlas->dims.x)
{
atlas->cur_pos.x = 0;
atlas->cur_pos.y += atlas->cur_row_height;
atlas->cur_row_height = 0;
}
if (atlas->cur_pos.x + slice_dims.x <= atlas->dims.x && atlas->cur_pos.y + slice_dims.y <= atlas->dims.y)
{
atlas_pos = atlas->cur_pos;
atlas->cur_row_height = MaxI32(atlas->cur_row_height, slice_dims.y);
atlas->cur_pos.x += slice_dims.x;
can_use_atlas = 1;
}
else
{
// New atlas required
atlas = 0;
}
}

View File

@ -13,7 +13,6 @@ Struct(SPR_SpanKey) { u64 v; };
Struct(SPR_Atlas)
{
SPR_Atlas *next;
Vec2I32 dims;
G_ResourceHandle tex_res;
G_Texture2DRef tex;
@ -47,7 +46,13 @@ Enum(SPR_LayerKind)
};
////////////////////////////////////////////////////////////
//~ Lookup result types
//~ Lookup types
Enum(SPR_SheetFlag)
{
SPR_SheetFlag_None = 0,
SPR_SheetFlag_NoAtlas = (1 << 0),
};
Struct(SPR_Ray)
{
@ -107,6 +112,7 @@ Struct(SPR_SheetEntry)
{
SPR_SheetEntry *next_in_bin;
SPR_SheetKey key;
SPR_SheetFlag flags;
i64 slices_count;
SPR_SliceEntry *slices;
@ -153,7 +159,6 @@ Struct(SPR_Ctx)
{
SPR_SheetBin sheet_bins[Kibi(16)];
// FIXME: Initialize this
G_Texture2DRef unready_tex;
Vec2 unready_tex_dims;
@ -194,6 +199,7 @@ SPR_LayerKind SPR_LayerKindFromName(String name);
////////////////////////////////////////////////////////////
//~ Lookup
SPR_Sprite SPR_SpriteFromSheetEx(SPR_SheetKey sheet_key, SPR_SpanKey span_key, i64 frame_seq, SPR_SheetFlag flags);
SPR_Sprite SPR_SpriteFromSheet(SPR_SheetKey sheet_key, SPR_SpanKey span_key, i64 frame_seq);
////////////////////////////////////////////////////////////