animation wip

This commit is contained in:
jacob 2026-01-30 05:27:47 -06:00
parent d44a845a8d
commit b7e2fafc85
11 changed files with 615 additions and 1515 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,132 @@
// DEFLATE decoder based on Handmade Hero's png parser ////////////////////////////////////////////////////////////
//~ Aseprite decode types
// https://github.com/aseprite/aseprite/blob/main/docs/ase-file-specs.md
Packed(Struct(ASE_Header)
{
u32 file_size;
u16 magic;
u16 frames_count;
u16 width;
u16 height;
u16 color_depth;
u32 flags;
u16 speed;
u8 _0[8];
u8 palette_entry;
u8 _1[3];
u16 colors_count;
u8 pixel_width;
u8 pixel_height;
i16 grid_x;
i16 grid_y;
u16 grid_width;
u16 grid_height;
u8 _2[84];
});
Packed(Struct(ASE_FrameHeader)
{
u32 bytes_count;
u16 magic;
u16 chunks_count0;
u16 frame_duration_ms;
u8 _[2];
u32 chunks_count1;
});
Enum(ASE_EncodedChunkKind)
{
ASE_EncodedChunkKind_OldPalette1 = 0x0004,
ASE_EncodedChunkKind_OldPalette2 = 0x0011,
ASE_EncodedChunkKind_Layer = 0x2004,
ASE_EncodedChunkKind_Cel = 0x2005,
ASE_EncodedChunkKind_CelExtra = 0x2006,
ASE_EncodedChunkKind_ColorProfile = 0x2007,
ASE_EncodedChunkKind_ExternalFiles = 0x2008,
ASE_EncodedChunkKind_Mask = 0x2016,
ASE_EncodedChunkKind_Path = 0x2017,
ASE_EncodedChunkKind_Tags = 0x2018,
ASE_EncodedChunkKind_Palette = 0x2019,
ASE_EncodedChunkKind_Userdata = 0x2020,
ASE_EncodedChunkKind_Slice = 0x2022,
ASE_EncodedChunkKind_Tileset = 0x2023
};
Enum(ASE_ChunkKind)
{
ASE_ChunkKind_Layer,
ASE_ChunkKind_Cel,
ASE_ChunkKind_Tag,
};
Enum(ASE_LayerKind)
{
ASE_LayerKind_Normal,
ASE_LayerKind_Group,
ASE_LayerKind_Tilemap,
};
Enum(ASE_LayerFlag)
{
ASE_LayerFlag_None = 0,
ASE_LayerFlag_Visible = (1 << 0),
ASE_LayerFlag_Editable = (1 << 1),
ASE_LayerFlag_LockMovement = (1 << 2),
ASE_LayerFlag_Background = (1 << 3),
ASE_LayerFlag_PreferLinkedCels = (1 << 4),
ASE_LayerFlag_Collapsed = (1 << 5),
ASE_LayerFlag_ReferenceLayer = (1 << 6),
};
Enum(ASE_CelKind)
{
ASE_CelKind_Raw = 0,
ASE_CelKind_Linked = 1,
ASE_CelKind_CompressedImage = 2,
ASE_CelKind_CompressedTilemap = 3,
};
Struct(ASE_Chunk)
{
ASE_Chunk *next;
ASE_ChunkKind kind;
//- Common
f32 opacity;
String name;
i64 chunk_layer_idx;
//- Layer
struct
{
ASE_LayerKind kind;
ASE_LayerFlag flags;
ASE_Chunk **cel_chunks;
struct ASE_Layer *final;
} layer;
//- Cel
struct
{
ASE_CelKind kind;
i64 frame_idx;
i64 linked_frame_idx;
Rng2 bounds;
String encoded;
} cel;
//- Tag
struct
{
i64 from;
i64 to;
} tag;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Inflate types //~ Inflate types
@ -138,21 +266,23 @@ Struct(ASE_Span)
ASE_Span *prev; ASE_Span *prev;
String name; String name;
i64 start; i64 from;
i64 end; i64 to;
}; };
Struct(ASE_Meta) Struct(ASE_Meta)
{ {
i64 frames_count; i64 frames_count;
i64 layers_count;
ASE_Layer *first_layer;
ASE_Layer *last_layer;
i64 spans_count; i64 spans_count;
ASE_Span *first_span; ASE_Span *first_span;
ASE_Span *last_span; ASE_Span *last_span;
i64 layers_count; b32 ok;
ASE_Layer *first_layer;
ASE_Layer *last_layer;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -184,7 +314,7 @@ u16 ASE_DecodeHuffDict(ASE_HuffDict *huffman, ASE_Bitbuff *bb);
void ASE_Inflate(u8 *dst, u8 *encoded); void ASE_Inflate(u8 *dst, u8 *encoded);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Meta //~ Decode
ASE_Meta ASE_DecodeMeta(Arena *arena, String encoded); ASE_Meta ASE_DecodeMeta(Arena *arena, String encoded);
@ -199,286 +329,3 @@ ASE_Image ASE_DecompressImageFromCel(Arena *arena, ASE_Cel *cel);
u32 ASE_BlendPixel(u32 src, u32 dst, u8 opacity); u32 ASE_BlendPixel(u32 src, u32 dst, u8 opacity);
void ASE_BlendImage(ASE_Image src_img, ASE_Image dst_img); void ASE_BlendImage(ASE_Image src_img, ASE_Image dst_img);
// ////////////////////////////////////////////////////////////
// //~ Query
// u32 ASE_FirstPixelFromCel(ASE_Cel *cel);
// ////////////////////////////////////////////////////////////
// //~ Rasterize
// void ASE_RasterizeCel(ASE_Cel *cel, u32 *dst_pixels, Vec2 dst_dims);
// ////////////////////////////////////////////////////////////
// //~ Sheet types
// Struct(ASE_Slice)
// {
// u32 start;
// Rng2I32 rect;
// ASE_Slice *next;
// };
// Struct(ASE_Span)
// {
// String name;
// u32 start;
// u32 end;
// ASE_Span *next;
// };
// Struct(ASE_Frame)
// {
// u32 index;
// Rng2I32 rect;
// f64 duration;
// ASE_Frame *next;
// };
// Struct(ASE_SliceKey)
// {
// String name;
// u32 slices_count;
// ASE_Slice *first_slice;
// ASE_SliceKey *next;
// };
// ////////////////////////////////////////////////////////////
// //~ Decoder result types
// Struct(ASE_Error)
// {
// String msg;
// ASE_Error *next;
// };
// Struct(ASE_ErrorList)
// {
// u64 count;
// ASE_Error *first;
// ASE_Error *last;
// };
// Struct(ASE_DecodedImage)
// {
// u32 width;
// u32 height;
// u32 *pixels; // Array of [width * height] pixels
// ASE_ErrorList errors;
// b32 ok;
// };
// Struct(ASE_DecodedSheet)
// {
// Vec2 image_size;
// Vec2 frame_size;
// u32 frames_count;
// u32 spans_count;
// u32 slice_keys_count;
// ASE_Frame *first_frame;
// ASE_Span *first_span;
// ASE_SliceKey *first_slice_key;
// ASE_ErrorList errors;
// b32 ok;
// };
// ////////////////////////////////////////////////////////////
// //~ Inflator types
// #define ASE_HuffBitCount 16
// Struct(ASE_Bitbuff)
// {
// u8 *data;
// u64 cur_bit;
// };
// Enum(ASE_BlockType)
// {
// ASE_BlockType_Uncompressed = 0,
// ASE_BlockType_CompressedFixed = 1,
// ASE_BlockType_CompressedDynamic = 2,
// ASE_BlockType_Reserved = 3
// };
// Struct(ASE_HuffEntry)
// {
// u16 symbol;
// u16 bits_used;
// };
// Struct(ASE_HuffDict)
// {
// u32 max_code_bits;
// u32 entries_count;
// ASE_HuffEntry *entries;
// };
// ////////////////////////////////////////////////////////////
// //~ Header types
// Packed(Struct(ASE_Header)
// {
// u32 file_size;
// u16 magic;
// u16 frames;
// u16 width;
// u16 height;
// u16 color_depth;
// u32 flags;
// u16 speed;
// u32 _1;
// u32 _2;
// u8 palette_entry;
// u8 _3[3];
// u16 colors_count;
// u8 pixel_width;
// u8 pixel_height;
// i16 grid_x;
// i16 grid_y;
// u16 grid_width;
// u16 grid_height;
// u8 _4[84];
// });
// Packed(Struct(ASE_FrameHeader)
// {
// u32 bytes;
// u16 magic;
// u16 chunks_old;
// u16 frame_duration_ms;
// u8 _[2];
// u32 chunks_new;
// });
// ////////////////////////////////////////////////////////////
// //~ Image decoder types
// Enum(ASE_ChunkKind)
// {
// ASE_ChunkKind_OldPalette1 = 0x0004,
// ASE_ChunkKind_OldPalette2 = 0x0011,
// ASE_ChunkKind_Layer = 0x2004,
// ASE_ChunkKind_Cel = 0x2005,
// ASE_ChunkKind_CelExtra = 0x2006,
// ASE_ChunkKind_ColorProfile = 0x2007,
// ASE_ChunkKind_ExternalFiles = 0x2008,
// ASE_ChunkKind_Mask = 0x2016,
// ASE_ChunkKind_Path = 0x2017,
// ASE_ChunkKind_Tags = 0x2018,
// ASE_ChunkKind_Palette = 0x2019,
// ASE_ChunkKind_Userdata = 0x2020,
// ASE_ChunkKind_Slice = 0x2022,
// ASE_ChunkKind_Tileset = 0x2023
// };
// Enum(ASE_CelKind)
// {
// ASE_CelKind_RawImage = 0,
// ASE_CelKind_Linked = 1,
// ASE_CelKind_CompressedImage = 2,
// ASE_CelKind_CompressedTilemap = 3
// };
// Struct(ASE_Layer)
// {
// u16 flags;
// u16 type;
// u16 child_level;
// u16 blend_mode;
// u8 opacity;
// String name;
// u32 tileset_index;
// u32 index;
// ASE_Layer *next;
// };
// Struct(ASE_Cel)
// {
// u16 layer_index;
// i16 x_pos;
// i16 y_pos;
// u8 opacity;
// ASE_CelKind type;
// i16 z_index;
// // Linked cel
// u16 frame_pos;
// // Compressed image
// u32 width;
// u32 height;
// u32 *pixels;
// u16 frame_index;
// ASE_Cel *next;
// };
// ////////////////////////////////////////////////////////////
// //~ Ase bitbuff helpers
// u32 ASE_PeekBits(ASE_Bitbuff *bb, u32 nbits);
// u32 ASE_ConsumeBits(ASE_Bitbuff *bb, u32 nbits);
// void ASE_SkipBits(ASE_Bitbuff *bb, u32 nbits);
// ////////////////////////////////////////////////////////////
// //~ Inflate
// u32 ASE_ReverseBits(u32 v, u32 bit_count);
// ASE_HuffDict ASE_InitHuffDict(Arena *arena, u32 max_code_bits, u32 *bl_counts, u32 bl_counts_count);
// u16 ASE_DecodeHuffDict(ASE_HuffDict *huffman, ASE_Bitbuff *bb);
// void ASE_Inflate(u8 *dst, u8 *encoded);
// ////////////////////////////////////////////////////////////
// //~ Error helpers
// void ASE_PushError(Arena *arena, ASE_ErrorList *list, String msg_src);
// ////////////////////////////////////////////////////////////
// //~ Decode helpers
// u32 ASE_Blend(u32 src, u32 dst, u8 opacity);
// void ASE_MakeDimensionsSquareish(ASE_Header *header, u32 *frames_x, u32 *frames_y, u64 *image_width, u64 *image_height);
// ////////////////////////////////////////////////////////////
// //~ Decode image
// ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded);
// ////////////////////////////////////////////////////////////
// //~ Decode sheet
// ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded);

View File

@ -372,7 +372,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
PushStringToList(perm, &cp.warnings_msvc, Lit("-W4")); PushStringToList(perm, &cp.warnings_msvc, Lit("-W4"));
PushStringToList(perm, &cp.warnings_msvc, Lit("-WX")); PushStringToList(perm, &cp.warnings_msvc, Lit("-WX"));
// PushStringToList(perm, &cp.warnings_msvc, Lit("-we4013")); // function undefined; assuming extern returning int // PushStringToList(perm, &cp.warnings_msvc, Lit("-we4013")); // function undefined; assuming extern returning int
PushStringToList(perm, &cp.warnings_msvc, Lit("-we4668")); // 'X' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' PushStringToList(perm, &cp.warnings_msvc, Lit("-we4668")); // X is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
// Disable warnings // Disable warnings
PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4244")); // 'function': conversion from 'int' to 'f32', possible loss of data PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4244")); // 'function': conversion from 'int' to 'f32', possible loss of data

View File

@ -4265,6 +4265,7 @@ void V_TickForever(WaveLaneCtx *lane)
} }
V_TileDesc tile_desc = Zi; V_TileDesc tile_desc = Zi;
{ {
tile_desc.tex_slice_uv = tile_slice.tex_rect_uv;
tile_desc.tex = tile_slice.tex; tile_desc.tex = tile_slice.tex;
} }
params.tile_descs[tile_kind] = tile_desc; params.tile_descs[tile_kind] = tile_desc;

View File

@ -493,7 +493,7 @@ ComputeShader2D(V_ShadeCS, 8, 8)
Texture2D<P_TileKind> tiles = G_Dereference<P_TileKind>(params.tiles); Texture2D<P_TileKind> tiles = G_Dereference<P_TileKind>(params.tiles);
RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains); RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains);
RWTexture2D<f32> drynesses = G_Dereference<f32>(params.drynesses); RWTexture2D<f32> drynesses = G_Dereference<f32>(params.drynesses);
SamplerState wrap_sampler = G_Dereference(params.pt_wrap_sampler); SamplerState clamp_sampler = G_Dereference(params.pt_clamp_sampler);
Vec2 shade_pos = SV_DispatchThreadID + Vec2(0.5, 0.5); Vec2 shade_pos = SV_DispatchThreadID + Vec2(0.5, 0.5);
Vec2 world_pos = mul(params.af.shade_to_world, Vec3(shade_pos, 1)); Vec2 world_pos = mul(params.af.shade_to_world, Vec3(shade_pos, 1));
@ -548,7 +548,8 @@ ComputeShader2D(V_ShadeCS, 8, 8)
{ {
V_TileDesc tile_desc = params.tile_descs[tile]; V_TileDesc tile_desc = params.tile_descs[tile];
Texture2D<Vec4> tile_tex = G_Dereference<Vec4>(tile_desc.tex); Texture2D<Vec4> tile_tex = G_Dereference<Vec4>(tile_desc.tex);
tile_color = tile_tex.SampleLevel(wrap_sampler, world_pos, 0); Vec2 tile_samp_uv = lerp(tile_desc.tex_slice_uv.p0, tile_desc.tex_slice_uv.p1, frac(world_pos));
tile_color = tile_tex.SampleLevel(clamp_sampler, tile_samp_uv, 0);
} }
// Checkered grid // Checkered grid
else if (tile == P_TileKind_Empty) else if (tile == P_TileKind_Empty)

View File

@ -48,6 +48,7 @@ Struct(V_Affines)
Struct(V_TileDesc) Struct(V_TileDesc)
{ {
Rng2 tex_slice_uv;
G_Texture2DRef tex; G_Texture2DRef tex;
}; };

View File

@ -108,6 +108,7 @@ SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet_key, SPR_SpanKey span_key, i64 f
{ {
SPR_SliceEntry *slice = &sheet->slices[slice_idx]; SPR_SliceEntry *slice = &sheet->slices[slice_idx];
slice->bounds = Rng2Empty; slice->bounds = Rng2Empty;
Atomic64Set(&slice->atlas_copy_completion_target, I64Max);
for (SPR_RayKind ray_kind = 0; ray_kind < SPR_RayKind_COUNT; ++ray_kind) for (SPR_RayKind ray_kind = 0; ray_kind < SPR_RayKind_COUNT; ++ray_kind)
{ {
slice->rays[ray_kind] = XformIdentity; slice->rays[ray_kind] = XformIdentity;
@ -204,33 +205,46 @@ SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet_key, SPR_SpanKey span_key, i64 f
} }
//- Init spans //- Init spans
sheet->span_bins_count = 256;
sheet->span_bins = PushStructs(perm, SPR_SpanBin, sheet->span_bins_count);
for (ASE_Span *ase_span = sheet->meta.first_span; ase_span; ase_span = ase_span->next)
{ {
SPR_SpanKey new_span_key = { .v = HashString(ase_span->name) }; sheet->span_bins_count = MaxI64(1, NextPow2U64(sheet->meta.spans_count * 4));
SPR_SpanBin *span_bin = &sheet->span_bins[new_span_key.v % sheet->span_bins_count]; sheet->span_bins = PushStructs(perm, SPR_SpanBin, sheet->span_bins_count);
SPR_SpanEntry *span = 0; for (ASE_Span *ase_span = sheet->meta.first_span; ase_span; ase_span = ase_span->next)
for (span = span_bin->first; span; span = span->next_in_bin)
{ {
if (span->key.v == new_span_key.v) SPR_SpanKey new_span_key = { .v = HashString(ase_span->name) };
SPR_SpanBin *span_bin = &sheet->span_bins[new_span_key.v % sheet->span_bins_count];
SPR_SpanEntry *span = 0;
for (span = span_bin->first; span; span = span->next_in_bin)
{ {
break; if (span->key.v == new_span_key.v)
{
break;
}
}
if (!span)
{
span = PushStruct(perm, SPR_SpanEntry);
SllQueuePush(sheet->first_span, sheet->last_span, span);
SllStackPushN(span_bin->first, span, next_in_bin);
span->key = new_span_key;
span->from = ase_span->from;
span->to = ase_span->to;
} }
} }
if (!span)
// Insert nil span
{ {
span = PushStruct(perm, SPR_SpanEntry); SPR_SpanBin *span_bin = &sheet->span_bins[0];
SPR_SpanEntry *span = PushStruct(perm, SPR_SpanEntry);
SllQueuePush(sheet->first_span, sheet->last_span, span); SllQueuePush(sheet->first_span, sheet->last_span, span);
SllStackPushN(span_bin->first, span, next_in_bin); SllStackPushN(span_bin->first, span, next_in_bin);
span->key = new_span_key; span->key = SPR_NilSpanKey;
span->start = ase_span->start; span->from = 0;
span->end = ase_span->end; span->to = sheet->slices_count;
} }
} }
// TODO: Proper validation // TODO: More rigorous validation
sheet->ok = 1; sheet->ok = sheet->meta.ok;
} }
} }
Unlock(&sheet_bin_lock); Unlock(&sheet_bin_lock);
@ -263,8 +277,8 @@ SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet_key, SPR_SpanKey span_key, i64 f
} }
if (span) if (span)
{ {
span_start = span->start; span_start = span->from;
span_end = span->end; span_end = span->to;
} }
} }

View File

@ -86,8 +86,8 @@ Struct(SPR_SpanEntry)
SPR_SpanEntry *next_in_bin; SPR_SpanEntry *next_in_bin;
SPR_SpanKey key; SPR_SpanKey key;
i64 start; i64 from;
i64 end; i64 to;
}; };
Struct(SPR_SpanBin) Struct(SPR_SpanBin)

View File

@ -29,8 +29,6 @@
@IncludeG ui_gpu.gh @IncludeG ui_gpu.gh
@Bootstrap UI_Bootstrap
////////////////////////////// //////////////////////////////
//- Impl //- Impl

View File

@ -1,12 +1,5 @@
UI_Ctx UI = Zi; UI_Ctx UI = Zi;
////////////////////////////////////////////////////////////
//~ Bootstrap
void UI_Bootstrap(void)
{
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Key helpers //~ Key helpers
@ -537,13 +530,11 @@ void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Rng2 uv)
UI_BoxReports UI_ReportsFromKey(UI_Key key) UI_BoxReports UI_ReportsFromKey(UI_Key key)
{ {
UI_BoxReports result = Zi; UI_BoxReports result = Zi;
UI_Box *box = UI_BoxFromKey(key); UI_Box *box = UI_BoxFromKey(key);
if (box) if (box)
{ {
result = box->reports; result = box->reports;
} }
return result; return result;
} }
@ -629,11 +620,11 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags)
{ {
ControllerEventsArray controller_events = frame->window_frame.controller_events; ControllerEventsArray controller_events = frame->window_frame.controller_events;
// Locate boxes //- Locate boxes
UI_Box *top_hovered_box = 0; UI_Box *top_hovered_box = 0;
UI_Box *active_box = UI_BoxFromKey(prev_frame->active_box); UI_Box *active_box = UI_BoxFromKey(prev_frame->active_box);
// Update cursor pos //- Update cursor pos
for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index) for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index)
{ {
ControllerEvent cev = controller_events.events[cev_index]; ControllerEvent cev = controller_events.events[cev_index];
@ -643,7 +634,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags)
} }
} }
// Init box reports //- Init box reports
for (u64 pre_index = UI.boxes_count; pre_index-- > 0;) for (u64 pre_index = UI.boxes_count; pre_index-- > 0;)
{ {
UI_Box *box = prev_frame->boxes_pre[pre_index]; UI_Box *box = prev_frame->boxes_pre[pre_index];
@ -690,7 +681,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags)
report->m3.presses = 0; report->m3.presses = 0;
} }
// Update state from controller events //- Update state from controller events
i32 mouse_downs = 0; i32 mouse_downs = 0;
for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index) for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index)
{ {
@ -788,7 +779,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags)
hot_box = top_hovered_box; hot_box = top_hovered_box;
} }
// Update box reports //- Update box reports
{ {
f32 lower_target = TweakFloat("UI lower blend target", -0.05, -1, 0); f32 lower_target = TweakFloat("UI lower blend target", -0.05, -1, 0);
f32 upper_target = TweakFloat("UI upper blend target", 1.05, 1, 10); f32 upper_target = TweakFloat("UI upper blend target", 1.05, 1, 10);
@ -804,9 +795,6 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags)
f32 target_active = box == active_box ? Inf : lower_target; f32 target_active = box == active_box ? Inf : lower_target;
f64 target_misc = box->desc.misc; f64 target_misc = box->desc.misc;
// TODO: Configurable per-box blend rates // TODO: Configurable per-box blend rates
f32 exists_blend_rate = (30 * frame->dt); f32 exists_blend_rate = (30 * frame->dt);
f32 hot_blend_rate = (15 * frame->dt); f32 hot_blend_rate = (15 * frame->dt);
@ -896,7 +884,6 @@ GC_Run UI_ScaleRun(Arena *arena, GC_Run unscaled_run, Vec2 scale)
{ {
GC_RunRect *src = &unscaled_run.rects[rect_idx]; GC_RunRect *src = &unscaled_run.rects[rect_idx];
GC_RunRect *dst = &result.rects[rect_idx]; GC_RunRect *dst = &result.rects[rect_idx];
*dst = *src; *dst = *src;
dst->bounds = MulRng2Vec2(dst->bounds, scale); dst->bounds = MulRng2Vec2(dst->bounds, scale);
dst->advance *= scale.x; dst->advance *= scale.x;
@ -923,121 +910,116 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
Rng2 draw_scissor = RNG2(VEC2(0, 0), VEC2(draw_size.x, draw_size.y)); Rng2 draw_scissor = RNG2(VEC2(0, 0), VEC2(draw_size.x, draw_size.y));
////////////////////////////// //////////////////////////////
//- Process commands //- Create boxes from build cmds
for (UI_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{ {
////////////////////////////// UI_Cmd cmd = cmd_node->cmd;
//- Create boxes from build cmds if (cmd.kind == UI_CmdKind_BuildBox)
for (UI_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{ {
UI_Cmd cmd = cmd_node->cmd; UI_Key key = cmd.box.key;
if (cmd.kind == UI_CmdKind_BuildBox) UI_Box *box = 0;
{ {
UI_Key key = cmd.box.key; UI_BoxBin *bin = &UI.box_bins[key.v % countof(UI.box_bins)];
UI_Box *box = 0; for (box = bin->first; box; box = box->next_in_bin)
{ {
UI_BoxBin *bin = &UI.box_bins[key.v % countof(UI.box_bins)]; if (UI_MatchKey(box->key, key))
for (box = bin->first; box; box = box->next_in_bin)
{ {
if (UI_MatchKey(box->key, key)) break;
{
break;
}
} }
}
// Allocate new box
if (box == 0)
{
// Allocate new box // Allocate new box
if (box == 0) box = UI.first_free_box;
i64 old_gen = 0;
if (box)
{ {
// Allocate new box old_gen = box->gen;
box = UI.first_free_box; SllStackPop(UI.first_free_box);
i64 old_gen = 0; ZeroStruct(box);
if (box)
{
old_gen = box->gen;
SllStackPop(UI.first_free_box);
ZeroStruct(box);
}
else
{
box = PushStruct(UI.box_arena, UI_Box);
}
box->key = key;
box->old_gen = old_gen;
box->gen = old_gen + 1;
DllQueuePushNP(bin->first, bin->last, box, next_in_bin, prev_in_bin);
++UI.boxes_count;
} }
else
{
box = PushStruct(UI.box_arena, UI_Box);
}
box->key = key;
box->old_gen = old_gen;
box->gen = old_gen + 1;
DllQueuePushNP(bin->first, bin->last, box, next_in_bin, prev_in_bin);
++UI.boxes_count;
} }
} }
} }
}
////////////////////////////// //////////////////////////////
//- Update boxes from cmds //- Update boxes from cmds
for (UI_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next) for (UI_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{
UI_Cmd cmd = cmd_node->cmd;
switch (cmd.kind)
{ {
UI_Cmd cmd = cmd_node->cmd; case UI_CmdKind_BuildBox:
switch (cmd.kind)
{ {
case UI_CmdKind_BuildBox: UI_Key key = cmd.box.key;
if (UI_MatchKey(key, UI_NilKey))
{ {
UI_Key key = cmd.box.key; key = UI_RandKey();
if (UI_MatchKey(key, UI_NilKey)) }
{ UI_Box *box = UI_BoxFromKey(key);
key = UI_RandKey();
}
UI_Box *box = UI_BoxFromKey(key);
UI_Box *parent = 0; UI_Box *parent = 0;
if (box != UI.root_box) if (box != UI.root_box)
{
parent = UI_BoxFromKey(cmd.box.parent);
}
// Update parent
if (box->parent)
{
// Remove from old parent
DllQueueRemove(box->parent->first, box->parent->last, box);
--box->parent->count;
}
if (parent)
{
// Add to new parent
DllQueuePush(parent->first, parent->last, box);
++parent->count;
}
box->parent = parent;
// Update box from cmd
{
box->desc = cmd.box;
String32 codepoints = Zi;
if (box->desc.icon != UI_Icon_None)
{
codepoints.len = 1;
codepoints.text = (u32 *)&box->desc.icon;
}
else
{
codepoints = String32FromString(scratch.arena, box->desc.text);
}
box->glyph_run = GC_RunFromString32(frame->arena, codepoints, box->desc.font, box->desc.font_size);
}
box->last_build_tick = frame->tick;
} break;
case UI_CmdKind_SetRawTexture:
{ {
UI_Key key = cmd.set_raw_texture.key; parent = UI_BoxFromKey(cmd.box.parent);
UI_Box *box = UI_BoxFromKey(key); }
if (box)
// Update parent
if (box->parent)
{
// Remove from old parent
DllQueueRemove(box->parent->first, box->parent->last, box);
--box->parent->count;
}
if (parent)
{
// Add to new parent
DllQueuePush(parent->first, parent->last, box);
++parent->count;
}
box->parent = parent;
// Update box from cmd
{
box->desc = cmd.box;
String32 codepoints = Zi;
if (box->desc.icon != UI_Icon_None)
{ {
box->raw_texture = cmd.set_raw_texture.tex; codepoints.len = 1;
box->raw_texture_slice_uv = cmd.set_raw_texture.slice_uv; codepoints.text = (u32 *)&box->desc.icon;
} }
} break; else
} {
codepoints = String32FromString(scratch.arena, box->desc.text);
}
box->glyph_run = GC_RunFromString32(frame->arena, codepoints, box->desc.font, box->desc.font_size);
}
box->last_build_tick = frame->tick;
} break;
case UI_CmdKind_SetRawTexture:
{
UI_Key key = cmd.set_raw_texture.key;
UI_Box *box = UI_BoxFromKey(key);
if (box)
{
box->raw_texture = cmd.set_raw_texture.tex;
box->raw_texture_slice_uv = cmd.set_raw_texture.slice_uv;
}
} break;
} }
} }

View File

@ -420,11 +420,6 @@ Struct(UI_Ctx)
extern UI_Ctx UI; extern UI_Ctx UI;
////////////////////////////////////////////////////////////
//~ Bootstrap
void UI_Bootstrap(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Key helpers //~ Key helpers