diff --git a/src/glyph_cache/glyph_cache.c b/src/glyph_cache/glyph_cache.c index f0de7b5d..f2fb0c69 100644 --- a/src/glyph_cache/glyph_cache.c +++ b/src/glyph_cache/glyph_cache.c @@ -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); diff --git a/src/sprite/sprite.c b/src/sprite/sprite.c index 902d61ad..e770dff7 100644 --- a/src/sprite/sprite.c +++ b/src/sprite/sprite.c @@ -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; } } diff --git a/src/sprite/sprite.h b/src/sprite/sprite.h index 2c6bf81f..0d88504f 100644 --- a/src/sprite/sprite.h +++ b/src/sprite/sprite.h @@ -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); ////////////////////////////////////////////////////////////