glyph cache progress
This commit is contained in:
parent
ad359c8495
commit
e9e8dcc04d
@ -94,20 +94,15 @@ void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
|
||||
{
|
||||
Assert(align > 0);
|
||||
|
||||
void *result = 0;
|
||||
u8 *base = ArenaFirst(arena, u8);
|
||||
|
||||
/* Check to avoid aligning when size = 0 */
|
||||
if (size > 0)
|
||||
{
|
||||
u64 aligned_start_pos = (arena->pos + (align - 1));
|
||||
aligned_start_pos -= aligned_start_pos % align;
|
||||
u64 start_pos = AlignU64(arena->pos, align);
|
||||
u64 end_pos = start_pos + size;
|
||||
|
||||
u64 new_pos = aligned_start_pos + size;
|
||||
if (new_pos > arena->committed)
|
||||
{
|
||||
/* Commit new block(s) */
|
||||
u64 blocks_needed = (new_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize;
|
||||
if (end_pos > arena->committed)
|
||||
{
|
||||
u64 blocks_needed = (end_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize;
|
||||
u64 commit_bytes = blocks_needed * ArenaBlockSize;
|
||||
u64 new_capacity = arena->committed + commit_bytes;
|
||||
if (new_capacity > arena->reserved)
|
||||
@ -126,14 +121,9 @@ void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
|
||||
AsanPoison(commit_address, commit_bytes);
|
||||
}
|
||||
|
||||
result = base + aligned_start_pos;
|
||||
AsanUnpoison(result, new_pos - aligned_start_pos);
|
||||
arena->pos = new_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = base + arena->pos;
|
||||
}
|
||||
void *result = base + start_pos;
|
||||
AsanUnpoison(result, end_pos - start_pos);
|
||||
arena->pos = end_pos;
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -147,28 +137,8 @@ void *PushBytes(Arena *arena, u64 size, u64 align)
|
||||
|
||||
void *PushAlign(Arena *arena, u64 align)
|
||||
{
|
||||
void *result = 0;
|
||||
if (align > 0)
|
||||
{
|
||||
u64 aligned_start_pos = (arena->pos + (align - 1));
|
||||
aligned_start_pos -= aligned_start_pos % align;
|
||||
u64 align_bytes = aligned_start_pos - (u64)arena->pos;
|
||||
if (align_bytes > 0)
|
||||
{
|
||||
result = (void *)PushStructsNoZero(arena, u8, align_bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = (void *)(ArenaFirst(arena, u8) + arena->pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 0 alignment */
|
||||
Assert(0);
|
||||
result = (void *)(ArenaFirst(arena, u8) + arena->pos);
|
||||
}
|
||||
return result;
|
||||
u64 push_count = AlignU64(arena->pos, align) - arena->pos;
|
||||
return PushStructsNoZero(arena, u8, push_count);
|
||||
}
|
||||
|
||||
void PopTo(Arena *arena, u64 pos)
|
||||
@ -198,17 +168,13 @@ void PopBytes(Arena *arena, u64 size, void *copy_dst)
|
||||
|
||||
void *ArenaFirst_(Arena *arena, u64 align)
|
||||
{
|
||||
u64 aligned_start_pos = align - 1;
|
||||
aligned_start_pos -= aligned_start_pos % align;
|
||||
void *result = ((u8 *)arena + ArenaHeaderSize) + aligned_start_pos;
|
||||
void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize, align);
|
||||
return result;
|
||||
}
|
||||
|
||||
void *ArenaNext_(Arena *arena, u64 align)
|
||||
{
|
||||
u64 aligned_start_pos = (arena->pos + (align - 1));
|
||||
aligned_start_pos -= aligned_start_pos % align;
|
||||
void *result = ((u8 *)arena + ArenaHeaderSize) + aligned_start_pos;
|
||||
void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize + arena->pos, align);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -233,7 +199,7 @@ void EndTempArena(TempArena temp)
|
||||
|
||||
TempArena BeginScratch(Arena *potential_conflict)
|
||||
{
|
||||
/* This function is currently hard-coded to search through 2 scratch arenas */
|
||||
/* This function is currently hard-coded for 2 thread-local scratch arenas */
|
||||
StaticAssert(ScratchArenasPerCtx == 2);
|
||||
|
||||
/* Use `BeginScratchNoConflict` if no conflicts are present */
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/* TODO: Elminiate meta arena. Just store levels in first 4096 bytes of buddy arena, and then zone header data at the beginning of each allocation. */
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Buddy ctx
|
||||
//~ Buddy context
|
||||
|
||||
BuddyCtx *AcquireBuddyCtx(u64 reserve)
|
||||
{
|
||||
@ -31,105 +31,7 @@ void ReleaseBuddyCtx(BuddyCtx *ctx)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Block acquire / release
|
||||
|
||||
BuddyBlock *AcquireBuddyBlock(BuddyCtx *ctx, u64 size)
|
||||
{
|
||||
if (size > 0x00FFFFFFFFFFFFFFULL)
|
||||
{
|
||||
/* TODO: Error */
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
/* TODO: Minimum block size */
|
||||
|
||||
/* TODO: Faster MSB calculation */
|
||||
|
||||
u64 desired_block_size = 1;
|
||||
u64 desired_level_tier = 0;
|
||||
while (desired_block_size < size && desired_level_tier < 64)
|
||||
{
|
||||
desired_block_size <<= 1;
|
||||
++desired_level_tier;
|
||||
}
|
||||
|
||||
BuddyBlock *block = GetUnusedBuddyBlock(ctx, &ctx->levels[desired_level_tier]);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
void ReleaseBuddyBlock(BuddyBlock *block)
|
||||
{
|
||||
block->is_used = 0;
|
||||
BuddyLevel *level = block->level;
|
||||
BuddyBlock *parent = block->parent;
|
||||
BuddyBlock *sibling = block->sibling;
|
||||
if (!sibling->is_used && parent != 0)
|
||||
{
|
||||
/* Merge siblings */
|
||||
BuddyCtx *ctx = level->ctx;
|
||||
PopBuddyBlock(ctx, level, block);
|
||||
PopBuddyBlock(ctx, level, sibling);
|
||||
/* Release parent */
|
||||
ReleaseBuddyBlock(parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (level->first_unused_block)
|
||||
{
|
||||
block->next = level->first_unused_block;
|
||||
level->first_unused_block->prev = block;
|
||||
}
|
||||
level->first_unused_block = block;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Block push / pop
|
||||
|
||||
//- Push
|
||||
BuddyBlock *PushBuddyBlock(BuddyCtx *ctx)
|
||||
{
|
||||
BuddyBlock *block;
|
||||
if (ctx->first_free_block)
|
||||
{
|
||||
block = ctx->first_free_block;
|
||||
ctx->first_free_block = block->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
block = PushStructNoZero(ctx->meta_arena, BuddyBlock);
|
||||
}
|
||||
ZeroStruct(block);
|
||||
return block;
|
||||
}
|
||||
|
||||
//- Pop
|
||||
void PopBuddyBlock(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block)
|
||||
{
|
||||
/* Remove from unused list */
|
||||
{
|
||||
BuddyBlock *prev = block->prev;
|
||||
BuddyBlock *next = block->next;
|
||||
if (prev)
|
||||
{
|
||||
prev->next = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
level->first_unused_block = next;
|
||||
}
|
||||
if (next)
|
||||
{
|
||||
next->prev = prev;
|
||||
}
|
||||
}
|
||||
block->next = ctx->first_free_block;
|
||||
ctx->first_free_block = block;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Get unused block
|
||||
//~ Buddy block
|
||||
|
||||
BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level)
|
||||
{
|
||||
@ -212,3 +114,93 @@ BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level)
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
BuddyBlock *PushBuddyBlock(BuddyCtx *ctx)
|
||||
{
|
||||
BuddyBlock *block;
|
||||
if (ctx->first_free_block)
|
||||
{
|
||||
block = ctx->first_free_block;
|
||||
ctx->first_free_block = block->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
block = PushStructNoZero(ctx->meta_arena, BuddyBlock);
|
||||
}
|
||||
ZeroStruct(block);
|
||||
return block;
|
||||
}
|
||||
|
||||
void PopBuddyBlock(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block)
|
||||
{
|
||||
/* Remove from unused list */
|
||||
{
|
||||
BuddyBlock *prev = block->prev;
|
||||
BuddyBlock *next = block->next;
|
||||
if (prev)
|
||||
{
|
||||
prev->next = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
level->first_unused_block = next;
|
||||
}
|
||||
if (next)
|
||||
{
|
||||
next->prev = prev;
|
||||
}
|
||||
}
|
||||
block->next = ctx->first_free_block;
|
||||
ctx->first_free_block = block;
|
||||
}
|
||||
|
||||
BuddyBlock *AcquireBuddyBlock(BuddyCtx *ctx, u64 size)
|
||||
{
|
||||
if (size > 0x00FFFFFFFFFFFFFFULL)
|
||||
{
|
||||
/* TODO: Error */
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
/* TODO: Minimum block size */
|
||||
|
||||
/* TODO: Faster MSB calculation */
|
||||
|
||||
u64 desired_block_size = 1;
|
||||
u64 desired_level_tier = 0;
|
||||
while (desired_block_size < size && desired_level_tier < 64)
|
||||
{
|
||||
desired_block_size <<= 1;
|
||||
++desired_level_tier;
|
||||
}
|
||||
|
||||
BuddyBlock *block = GetUnusedBuddyBlock(ctx, &ctx->levels[desired_level_tier]);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
void ReleaseBuddyBlock(BuddyBlock *block)
|
||||
{
|
||||
block->is_used = 0;
|
||||
BuddyLevel *level = block->level;
|
||||
BuddyBlock *parent = block->parent;
|
||||
BuddyBlock *sibling = block->sibling;
|
||||
if (!sibling->is_used && parent != 0)
|
||||
{
|
||||
/* Merge siblings */
|
||||
BuddyCtx *ctx = level->ctx;
|
||||
PopBuddyBlock(ctx, level, block);
|
||||
PopBuddyBlock(ctx, level, sibling);
|
||||
/* Release parent */
|
||||
ReleaseBuddyBlock(parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (level->first_unused_block)
|
||||
{
|
||||
block->next = level->first_unused_block;
|
||||
level->first_unused_block->prev = block;
|
||||
}
|
||||
level->first_unused_block = block;
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,13 +44,13 @@ void ReleaseBuddyCtx(BuddyCtx *ctx);
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Buddy block
|
||||
|
||||
//- Acquire / release
|
||||
BuddyBlock *AcquireBuddyBlock(BuddyCtx *ctx, u64 size);
|
||||
void ReleaseBuddyBlock(BuddyBlock *block);
|
||||
//- Get unused
|
||||
BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level);
|
||||
|
||||
//- Push / pop
|
||||
BuddyBlock *PushBuddyBlock(BuddyCtx *ctx);
|
||||
void PopBuddyBlock(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block);
|
||||
|
||||
//- Get unused
|
||||
BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level);
|
||||
//- Acquire / release
|
||||
BuddyBlock *AcquireBuddyBlock(BuddyCtx *ctx, u64 size);
|
||||
void ReleaseBuddyBlock(BuddyBlock *block);
|
||||
|
||||
@ -1148,6 +1148,43 @@ u32 U32FromVec4(Vec4 v)
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Range
|
||||
|
||||
Vec2 DimsFromRng2(Rng2 r)
|
||||
{
|
||||
Vec2 result = ZI;
|
||||
result.x = r.p1.x - r.p0.x;
|
||||
result.y = r.p1.y - r.p0.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
Rng2 UnionRng2(Rng2 a, Rng2 b)
|
||||
{
|
||||
Rng2 result = ZI;
|
||||
result.p0.x = MinF32(a.p0.x, b.p0.x);
|
||||
result.p0.y = MinF32(a.p0.y, b.p0.y);
|
||||
result.p1.x = MaxF32(a.p1.x, b.p1.x);
|
||||
result.p1.y = MaxF32(a.p1.y, b.p1.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
Rng2 AddRng2Vec2(Rng2 r, Vec2 v)
|
||||
{
|
||||
Rng2 result = ZI;
|
||||
result.p0 = AddVec2(result.p0, v);
|
||||
result.p1 = AddVec2(result.p1, v);
|
||||
return result;
|
||||
}
|
||||
|
||||
Rng2 DivRng2Vec2(Rng2 r, Vec2 v)
|
||||
{
|
||||
Rng2 result = ZI;
|
||||
result.p0 = DivVec2Vec2(result.p0, v);
|
||||
result.p1 = DivVec2Vec2(result.p1, v);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Xform
|
||||
|
||||
|
||||
@ -385,6 +385,15 @@ Vec2I32 SubVec2I32(Vec2I32 a, Vec2I32 b);
|
||||
Vec4 Vec4FromU32(u32 v);
|
||||
u32 U32FromVec4(Vec4 v);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Range
|
||||
|
||||
Vec2 DimsFromRng2(Rng2 r);
|
||||
Rng2 UnionRng2(Rng2 a, Rng2 b);
|
||||
|
||||
Rng2 AddRng2Vec2(Rng2 r, Vec2 v);
|
||||
Rng2 DivRng2Vec2(Rng2 a, Vec2 v);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Xform
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Math types
|
||||
//~ Base math types
|
||||
|
||||
#define Pi ((f32)3.14159265358979323846)
|
||||
#define Tau ((f32)6.28318530717958647693)
|
||||
@ -21,6 +21,21 @@ typedef float4 Aabb;
|
||||
typedef float4 Quad;
|
||||
typedef float4x4 Mat4x4;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Range types
|
||||
|
||||
Struct(Rng) { f32 min; f32 max; };
|
||||
Struct(RngI32) { i32 min; i32 max; };
|
||||
Struct(RngU32) { u32 min; u32 max; };
|
||||
|
||||
Struct(Rng2) { Vec2 p0; Vec2 p1; };
|
||||
Struct(Rng2I32) { Vec2I32 p0; Vec2I32 p1; };
|
||||
Struct(Rng2U32) { Vec2U32 p0; Vec2U32 p1; };
|
||||
|
||||
Struct(Rng3) { Vec3 p0; Vec3 p1; };
|
||||
Struct(Rng3I32) { Vec3I32 p0; Vec3I32 p1; };
|
||||
Struct(Rng3U32) { Vec3U32 p0; Vec3U32 p1; };
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Countof
|
||||
|
||||
|
||||
@ -69,7 +69,7 @@
|
||||
|
||||
#define FLOOD_DEBUG 0
|
||||
|
||||
#define GPU_DEBUG 1
|
||||
#define GPU_DEBUG 0
|
||||
#define GPU_DEBUG_VALIDATION 0
|
||||
|
||||
#define GPU_SHADER_PRINT 1
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
/* TODO: Use default font texture handle */
|
||||
Readonly GC_RunRect GC_NilRunRect = {
|
||||
0
|
||||
};
|
||||
GC_State GC = ZI;
|
||||
|
||||
Readonly GC_Run GC_NilRun = {
|
||||
.count = 1,
|
||||
.rects = &GC_NilRunRect
|
||||
};
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Bootstrap
|
||||
|
||||
void GC_BootStrap(void)
|
||||
{
|
||||
// OnAsync(GC_AsyncTick);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Key helpers
|
||||
@ -18,22 +18,119 @@ GC_FontKey GC_FontKeyFromResource(ResourceKey resource)
|
||||
return result;
|
||||
}
|
||||
|
||||
u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc)
|
||||
{
|
||||
return RandU64FromSeeds(desc.font.v, ((u64)desc.codepoint << 32) | *(u32 *)&desc.font_size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Run
|
||||
|
||||
GC_Run *GC_RunFromString(Arena *arena, GC_FontKey key, String str)
|
||||
/* TODO: Thread-local cache */
|
||||
GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size)
|
||||
{
|
||||
/* TODO */
|
||||
GC_Run *result = PushStruct(arena, GC_Run);
|
||||
GC_Run result = ZI;
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
|
||||
GC_RunRect *rr = PushStruct(arena, GC_RunRect);
|
||||
rr->advance = 1;
|
||||
result->rects = rr;
|
||||
result->count = 1;
|
||||
String32 codepoints = String32FromString(scratch.arena, str);
|
||||
|
||||
String32 uncached_codepoints = ZI;
|
||||
uncached_codepoints.text = PushStructsNoZero(scratch.arena, u32, codepoints.len);
|
||||
|
||||
u64 ready_glyphs_count = 0;
|
||||
GC_Glyph **ready_glyphs = PushStructsNoZero(scratch.arena, GC_Glyph *, str.len);
|
||||
{
|
||||
if (codepoints.len > 0)
|
||||
{
|
||||
Lock lock = LockS(&GC.glyphs_mutex);
|
||||
for (u64 codepoint_idx = 0; codepoint_idx < codepoints.len; ++codepoint_idx)
|
||||
{
|
||||
u32 codepoint = codepoints.text[codepoint_idx];
|
||||
|
||||
GC_GlyphDesc desc = ZI;
|
||||
desc.font = font;
|
||||
desc.font_size = font_size;
|
||||
desc.codepoint = codepoint;
|
||||
|
||||
u64 hash = GC_HashFromGlyphDesc(desc);
|
||||
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
|
||||
|
||||
GC_Glyph *glyph = bin->first;
|
||||
for (; glyph; glyph = glyph->next)
|
||||
{
|
||||
if (glyph->hash == hash)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (glyph == 0)
|
||||
{
|
||||
uncached_codepoints.text[uncached_codepoints.len] = codepoint;
|
||||
uncached_codepoints.len += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ready_glyphs[ready_glyphs_count] = glyph;
|
||||
ready_glyphs_count += 1;
|
||||
}
|
||||
}
|
||||
Unlock(&lock);
|
||||
}
|
||||
}
|
||||
|
||||
f32 baseline_pos = 0;
|
||||
result.rects = PushStructs(arena, GC_RunRect, ready_glyphs_count);
|
||||
result.rects_count = ready_glyphs_count;
|
||||
for (u64 glyph_idx = 0; glyph_idx < ready_glyphs_count; ++glyph_idx)
|
||||
{
|
||||
GC_Glyph *glyph = ready_glyphs[glyph_idx];
|
||||
GC_RunRect *rect = &result.rects[glyph_idx];
|
||||
|
||||
rect->tex = glyph->tex_ref;
|
||||
rect->tex_uv = glyph->tex_uv;
|
||||
rect->tex_rect = glyph->tex_rect;
|
||||
|
||||
rect->baseline_pos = baseline_pos;
|
||||
rect->advance = glyph->advance;
|
||||
|
||||
rect->bounds.p0 = glyph->baseline_offset;
|
||||
rect->bounds.p1 = AddVec2(rect->bounds.p0, DimsFromRng2(glyph->tex_rect));
|
||||
|
||||
if (glyph_idx == 0)
|
||||
{
|
||||
result.bounds = rect->bounds;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.bounds = UnionRng2(result.bounds, rect->bounds);
|
||||
}
|
||||
|
||||
baseline_pos += rect->advance;
|
||||
result.baseline_length = MaxF32(result.baseline_length, baseline_pos);
|
||||
}
|
||||
|
||||
if (ready_glyphs_count > 0)
|
||||
{
|
||||
GC_Glyph *glyph = ready_glyphs[0];
|
||||
result.font_size = glyph->font_size;
|
||||
result.font_ascent = glyph->font_ascent;
|
||||
result.font_descent = glyph->font_descent;
|
||||
result.font_cap = glyph->font_cap;
|
||||
}
|
||||
|
||||
result.ready = uncached_codepoints.len == 0;
|
||||
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Async tick
|
||||
|
||||
void GC_AsyncTick(WaveLaneCtx *lane)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -6,50 +6,102 @@ Struct(GC_FontKey)
|
||||
u64 v;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Glyph types
|
||||
|
||||
Struct(GC_GlyphDesc)
|
||||
{
|
||||
GC_FontKey font;
|
||||
f32 font_size;
|
||||
u32 codepoint;
|
||||
};
|
||||
|
||||
Struct(GC_Glyph)
|
||||
{
|
||||
GC_Glyph *next;
|
||||
u64 hash;
|
||||
|
||||
/* Layout info */
|
||||
Vec2 baseline_offset;
|
||||
f32 advance;
|
||||
|
||||
/* Atlas info */
|
||||
G_Texture2DRef tex_ref;
|
||||
Rng2 tex_uv;
|
||||
Rng2 tex_rect;
|
||||
|
||||
/* Font info */
|
||||
f32 font_size;
|
||||
f32 font_ascent;
|
||||
f32 font_descent;
|
||||
f32 font_cap;
|
||||
};
|
||||
|
||||
Struct(GC_GlyphBin)
|
||||
{
|
||||
GC_Glyph *first;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Run types
|
||||
|
||||
Struct(GC_RunRect)
|
||||
{
|
||||
Vec2 offset; /* Vector from baseline offset to top left of glyph rect */
|
||||
f32 pos; /* Horizontal distance from start of baseline */
|
||||
Rng2 bounds; /* Visual bounds in relation to the baseline */
|
||||
f32 baseline_pos; /* Horizontal distance from start of baseline */
|
||||
f32 advance;
|
||||
|
||||
Vec2 size;
|
||||
G_Texture2DRef tex;
|
||||
Rng2 uv;
|
||||
Rng2 tex_uv;
|
||||
Rng2 tex_rect;
|
||||
};
|
||||
|
||||
Struct(GC_Run)
|
||||
{
|
||||
/* Run data */
|
||||
Vec2 p0; /* Start of baseline to top-left-most rect */
|
||||
Vec2 p1; /* Start of baseline to bottom-right-most rect corner */
|
||||
u32 count;
|
||||
Rng2 bounds; /* Visual bounds of the run in relation to the baseline */
|
||||
f32 baseline_length;
|
||||
u64 rects_count;
|
||||
GC_RunRect *rects;
|
||||
|
||||
/* Font stats */
|
||||
f32 size;
|
||||
f32 ascent;
|
||||
f32 descent;
|
||||
f32 cap;
|
||||
/* Font info */
|
||||
f32 font_size;
|
||||
f32 font_ascent;
|
||||
f32 font_descent;
|
||||
f32 font_cap;
|
||||
|
||||
b32 loaded;
|
||||
b32 ready;
|
||||
};
|
||||
|
||||
extern Readonly GC_RunRect GC_NilRunRect;
|
||||
extern Readonly GC_Run GC_NilRun;
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ State
|
||||
|
||||
Struct(GC_State)
|
||||
{
|
||||
Mutex glyphs_mutex;
|
||||
GC_GlyphBin glyph_bins[16384];
|
||||
} extern GC;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Bootstrap
|
||||
|
||||
void GC_Bootstrap(void);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Key helpers
|
||||
|
||||
GC_FontKey GC_FontKeyFromResource(ResourceKey resource);
|
||||
u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Run
|
||||
|
||||
GC_Run *GC_RunFromString(Arena *arena, GC_FontKey key, String str);
|
||||
GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Async tick
|
||||
|
||||
void GC_AsyncTick(WaveLaneCtx *lane);
|
||||
|
||||
|
||||
|
||||
|
||||
@ -317,6 +317,7 @@ void G_Bootstrap(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
@ -249,7 +249,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
/* TODO: Don't rely on ui report for draw size since it introduces one frame of delay when resizing */
|
||||
UI_Report vis_rep = UI_ReportFromKey(vis_box);
|
||||
draw_size = Vec2I32FromFields(SubVec2(vis_rep.screen_p1, vis_rep.screen_p0));
|
||||
draw_size = Vec2I32FromVec(DimsFromRng2(vis_rep.screen_rect));
|
||||
}
|
||||
draw_size.x = MaxI32(draw_size.x, 1);
|
||||
draw_size.y = MaxI32(draw_size.y, 1);
|
||||
@ -624,9 +624,11 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
G_DumbMemoryLayoutSync(frame->cl, draw_target, G_Layout_DirectQueue_ShaderRead);
|
||||
{
|
||||
Vec2 uv0 = DivVec2Vec2(Vec2FromVec(viewport.p0), Vec2FromVec(window_frame.monitor_size));
|
||||
Vec2 uv1 = DivVec2Vec2(Vec2FromVec(viewport.p1), Vec2FromVec(window_frame.monitor_size));
|
||||
UI_SetRawTexture(vis_box, draw_target_ro, uv0, uv1);
|
||||
Rng2 uv = ZI;
|
||||
uv.p0 = Vec2FromVec(viewport.p0);
|
||||
uv.p1 = Vec2FromVec(viewport.p1);
|
||||
uv = DivRng2Vec2(uv, Vec2FromVec(window_frame.monitor_size));
|
||||
UI_SetRawTexture(vis_box, draw_target_ro, uv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@ PixelShader(V_DQuadPS, V_DQuadPSOutput, V_DQuadPSInput input)
|
||||
Vec4 final_color = 0;
|
||||
|
||||
V_DQuadPSOutput output;
|
||||
output.SV_Target0 = final_color;
|
||||
output.sv_target0 = final_color;
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -85,6 +85,6 @@ VertexShader(V_DVertVS, V_DVertPSInput)
|
||||
PixelShader(V_DVertPS, V_DVertPSOutput, V_DVertPSInput input)
|
||||
{
|
||||
V_DVertPSOutput output;
|
||||
output.SV_Target0 = input.color_lin;
|
||||
output.sv_target0 = input.color_lin;
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ Struct(V_DQuadPSInput)
|
||||
|
||||
Struct(V_DQuadPSOutput)
|
||||
{
|
||||
Semantic(Vec4, SV_Target0);
|
||||
Semantic(Vec4, sv_target0);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -24,7 +24,7 @@ Struct(V_DVertPSInput)
|
||||
|
||||
Struct(V_DVertPSOutput)
|
||||
{
|
||||
Semantic(Vec4, SV_Target0);
|
||||
Semantic(Vec4, sv_target0);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -31,7 +31,7 @@ Struct(PT_BlitPSInput)
|
||||
|
||||
Struct(PT_BlitPSOutput)
|
||||
{
|
||||
Semantic(Vec4, SV_Target0);
|
||||
Semantic(Vec4, sv_target0);
|
||||
};
|
||||
|
||||
//////////////////////////////
|
||||
@ -68,6 +68,6 @@ PixelShader(PT_BlitPS, PT_BlitPSOutput, PT_BlitPSInput input)
|
||||
result.r = (f32)noise_val / (f32)U16Max;
|
||||
|
||||
PT_BlitPSOutput output;
|
||||
output.SV_Target0 = result;
|
||||
output.sv_target0 = result;
|
||||
return output;
|
||||
}
|
||||
|
||||
181
src/ui/ui_core.c
181
src/ui/ui_core.c
@ -150,15 +150,15 @@ void UI_PushDefaults(void)
|
||||
case UI_StyleKind_Font: { desc.style.Font = UI_GetDefaultFont(); } break;
|
||||
|
||||
u8 prefetch[127] = ZI;
|
||||
for (u64 i = 0; i < countof(prefetch); ++i)
|
||||
for (u64 idx = 0; idx < countof(prefetch); ++idx)
|
||||
{
|
||||
prefetch[i] = i;
|
||||
prefetch[idx] = idx;
|
||||
}
|
||||
case UI_StyleKind_FontSize: { desc.style.FontSize = 16.0f; } break;
|
||||
case UI_StyleKind_Tint: { desc.style.Tint = Color_White; } break;
|
||||
case UI_StyleKind_Tag: { desc.style.Tag = HashFnv64(Fnv64Basis, Lit("root")); } break;
|
||||
case UI_StyleKind_DebugColor: { desc.style.DebugColor = Rgba(1, 0, 1, 0.5); } break;
|
||||
case UI_StyleKind_BackgroundTextureUv1: { desc.style.BackgroundTextureUv1 = VEC2(1, 1); } break;
|
||||
case UI_StyleKind_BackgroundTextureSliceUv: { desc.style.BackgroundTextureSliceUv = RNG2(VEC2(0, 0), VEC2(1, 1)); } break;
|
||||
};
|
||||
UI_PushStyle(desc);
|
||||
}
|
||||
@ -411,7 +411,7 @@ UI_Key UI_BuildBoxEx(UI_Key key)
|
||||
}
|
||||
|
||||
|
||||
void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Vec2 uv0, Vec2 uv1)
|
||||
void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Rng2 uv)
|
||||
{
|
||||
UI_Frame *frame = UI_CurrentFrame();
|
||||
UI_CmdNode *n = PushStruct(frame->arena, UI_CmdNode);
|
||||
@ -419,8 +419,7 @@ void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Vec2 uv0, Vec2 uv1)
|
||||
{
|
||||
n->cmd.set_raw_texture.key = key;
|
||||
n->cmd.set_raw_texture.tex = tex;
|
||||
n->cmd.set_raw_texture.uv0 = uv0;
|
||||
n->cmd.set_raw_texture.uv1 = uv1;
|
||||
n->cmd.set_raw_texture.slice_uv = uv;
|
||||
}
|
||||
++frame->cmds_count;
|
||||
SllQueuePush(frame->first_cmd_node, frame->last_cmd_node, n);
|
||||
@ -547,8 +546,8 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
||||
b32 is_cursor_in_box = 0;
|
||||
{
|
||||
/* TODO: More efficient test. This logic is just copied from the renderer's SDF function for now. */
|
||||
Vec2 p0 = box->p0;
|
||||
Vec2 p1 = box->p1;
|
||||
Vec2 p0 = box->rect.p0;
|
||||
Vec2 p1 = box->rect.p1;
|
||||
Vec2 point = frame->cursor_pos;
|
||||
b32 is_corner = 0;
|
||||
f32 non_corner_edge_dist = MinF32(MinF32(point.x - p0.x, p1.x - point.x), MinF32(point.y - p0.y, p1.y - point.y));
|
||||
@ -597,7 +596,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
||||
{
|
||||
++hovered_box->report.m1_downs;
|
||||
hovered_box->report.m1_held = 1;
|
||||
hovered_box->report.last_m1_offset = SubVec2(frame->cursor_pos, hovered_box->p0);
|
||||
hovered_box->report.last_m1_offset = SubVec2(frame->cursor_pos, hovered_box->rect.p0);
|
||||
active_box = hovered_box;
|
||||
}
|
||||
}
|
||||
@ -642,8 +641,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
||||
report->active = LerpF32(report->active, target_active, active_blend_rate);
|
||||
report->hovered = LerpF32(report->hovered, target_hovered, hovered_blend_rate);
|
||||
|
||||
report->screen_p0 = box->p0;
|
||||
report->screen_p1 = box->p1;
|
||||
report->screen_rect = box->rect;
|
||||
}
|
||||
|
||||
frame->hovered_box = hovered_box ? hovered_box->key : UI_NilKey;
|
||||
@ -789,10 +787,9 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
}
|
||||
|
||||
/* Fetch run */
|
||||
box->glyph_run = &GC_NilRun;
|
||||
if (box->desc.text.len > 0)
|
||||
{
|
||||
box->glyph_run = GC_RunFromString(frame->arena, box->desc.font, box->desc.text);
|
||||
box->glyph_run = GC_RunFromString(frame->arena, box->desc.text, box->desc.font, box->desc.font_size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -809,8 +806,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
if (box)
|
||||
{
|
||||
box->raw_texture = cmd.set_raw_texture.tex;
|
||||
box->raw_texture_uv0 = cmd.set_raw_texture.uv0;
|
||||
box->raw_texture_uv1 = cmd.set_raw_texture.uv1;
|
||||
box->raw_texture_slice_uv = cmd.set_raw_texture.slice_uv;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@ -908,13 +904,11 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
f32 text_size = 0;
|
||||
if (axis == Axis_X)
|
||||
{
|
||||
GC_RunRect rr = box->glyph_run->rects[box->glyph_run->count - 1];
|
||||
f32 baseline_length = rr.pos + rr.advance;
|
||||
text_size = baseline_length;
|
||||
text_size = box->glyph_run.baseline_length;
|
||||
}
|
||||
else
|
||||
{
|
||||
text_size = box->glyph_run->ascent + box->glyph_run->descent;
|
||||
text_size = box->glyph_run.font_ascent + box->glyph_run.font_descent;
|
||||
}
|
||||
box->solved_dims[axis] = text_size + (pref_size.v * 2);
|
||||
}
|
||||
@ -1107,16 +1101,16 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
if (AnyBit(box->desc.flags, UI_BoxFlag_Floating))
|
||||
{
|
||||
Vec2 offset = box->desc.floating_pos;
|
||||
final_pos = AddVec2(parent->p0, offset);
|
||||
final_pos = AddVec2(parent->rect.p0, offset);
|
||||
if (!AnyBit(box->desc.flags, UI_BoxFlag_NoFloatingClamp))
|
||||
{
|
||||
{
|
||||
f32 overshoot = MaxF32(0, (final_pos.x + dims_vec.x) - parent->p1.x);
|
||||
final_pos.x = MaxF32(parent->p0.x, final_pos.x - overshoot);
|
||||
f32 overshoot = MaxF32(0, (final_pos.x + dims_vec.x) - parent->rect.p1.x);
|
||||
final_pos.x = MaxF32(parent->rect.p0.x, final_pos.x - overshoot);
|
||||
}
|
||||
{
|
||||
f32 overshoot = MaxF32((final_pos.y + dims_vec.y) - parent->p1.y, 0);
|
||||
final_pos.y = MaxF32(parent->p0.y, final_pos.y - overshoot);
|
||||
f32 overshoot = MaxF32((final_pos.y + dims_vec.y) - parent->rect.p1.y, 0);
|
||||
final_pos.y = MaxF32(parent->rect.p0.y, final_pos.y - overshoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1151,22 +1145,22 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
} break;
|
||||
}
|
||||
}
|
||||
final_pos.x = parent->p0.x + offset[0];
|
||||
final_pos.y = parent->p0.y + offset[1];
|
||||
final_pos.x = parent->rect.p0.x + offset[0];
|
||||
final_pos.y = parent->rect.p0.y + offset[1];
|
||||
parent->layout_cursor += dims_arr[parent->desc.child_layout_axis];
|
||||
}
|
||||
|
||||
/* Submit position */
|
||||
Vec2 floored_final_pos = FloorVec2(final_pos);
|
||||
Vec2 ceiled_dims = CeilVec2(dims_vec);
|
||||
box->p0 = FloorVec2(floored_final_pos);
|
||||
box->p1 = AddVec2(floored_final_pos, ceiled_dims);
|
||||
box->rect.p0 = FloorVec2(floored_final_pos);
|
||||
box->rect.p1 = AddVec2(floored_final_pos, ceiled_dims);
|
||||
}
|
||||
|
||||
/* Rounding */
|
||||
{
|
||||
UI_Round rounding = box->desc.rounding;
|
||||
Vec2 half_dims = MulVec2(SubVec2(box->p1, box->p0), 0.5);
|
||||
Vec2 half_dims = MulVec2(SubVec2(box->rect.p1, box->rect.p0), 0.5);
|
||||
f32 min_half_dims = MinF32(half_dims.x, half_dims.y);
|
||||
f32 final_rounding_tl = 0;
|
||||
f32 final_rounding_tr = 0;
|
||||
@ -1194,10 +1188,10 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
|
||||
if (parent && !AllBits(box->desc.flags, UI_BoxFlag_Floating | UI_BoxFlag_NoFloatingClamp))
|
||||
{
|
||||
Vec2 vtl = SubVec2(VEC2(parent->p0.x, parent->p0.y), VEC2(box->p0.x, box->p0.y));
|
||||
Vec2 vtr = SubVec2(VEC2(parent->p1.x, parent->p0.y), VEC2(box->p1.x, box->p0.y));
|
||||
Vec2 vbr = SubVec2(VEC2(parent->p1.x, parent->p1.y), VEC2(box->p1.x, box->p1.y));
|
||||
Vec2 vbl = SubVec2(VEC2(parent->p0.x, parent->p1.y), VEC2(box->p0.x, box->p1.y));
|
||||
Vec2 vtl = SubVec2(VEC2(parent->rect.p0.x, parent->rect.p0.y), VEC2(box->rect.p0.x, box->rect.p0.y));
|
||||
Vec2 vtr = SubVec2(VEC2(parent->rect.p1.x, parent->rect.p0.y), VEC2(box->rect.p1.x, box->rect.p0.y));
|
||||
Vec2 vbr = SubVec2(VEC2(parent->rect.p1.x, parent->rect.p1.y), VEC2(box->rect.p1.x, box->rect.p1.y));
|
||||
Vec2 vbl = SubVec2(VEC2(parent->rect.p0.x, parent->rect.p1.y), VEC2(box->rect.p0.x, box->rect.p1.y));
|
||||
final_rounding_tl = MaxF32(final_rounding_tl, parent->rounding_tl - Vec2Len(vtl));
|
||||
final_rounding_tr = MaxF32(final_rounding_tr, parent->rounding_tr - Vec2Len(vtr));
|
||||
final_rounding_br = MaxF32(final_rounding_br, parent->rounding_br - Vec2Len(vbr));
|
||||
@ -1226,18 +1220,15 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
UI_Box *box = boxes_pre[pre_index];
|
||||
b32 is_visible = 1;
|
||||
is_visible = is_visible && (box->desc.tint.w != 0);
|
||||
is_visible = is_visible && (box->p1.x > box->p0.x);
|
||||
is_visible = is_visible && (box->p1.y > box->p0.y);
|
||||
is_visible = is_visible && (box->rect.p1.x > box->rect.p0.x);
|
||||
is_visible = is_visible && (box->rect.p1.y > box->rect.p0.y);
|
||||
if (is_visible || AnyBit(frame->frame_flags, UI_FrameFlag_Debug))
|
||||
{
|
||||
|
||||
/* Box rect */
|
||||
{
|
||||
UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect);
|
||||
rect->p0 = box->p0;
|
||||
rect->p1 = box->p1;
|
||||
rect->tex_uv0 = VEC2(0, 0);
|
||||
rect->tex_uv1 = VEC2(1, 1);
|
||||
rect->bounds = box->rect;
|
||||
rect->background_lin = LinearFromSrgb(box->desc.background_color);
|
||||
rect->border_lin = LinearFromSrgb(box->desc.border_color);
|
||||
rect->debug_lin = LinearFromSrgb(box->desc.debug_color);
|
||||
@ -1248,55 +1239,55 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
rect->br_rounding = box->rounding_br;
|
||||
rect->bl_rounding = box->rounding_bl;
|
||||
rect->tex = box->raw_texture;
|
||||
rect->tex_uv0 = box->raw_texture_uv0;
|
||||
rect->tex_uv1 = box->raw_texture_uv1;
|
||||
rect->tex_slice_uv = box->raw_texture_slice_uv;
|
||||
}
|
||||
|
||||
/* Text rects */
|
||||
GC_Run *raw_run = box->glyph_run;
|
||||
if (AnyBit(box->desc.flags, UI_BoxFlag_DrawText) && raw_run->loaded)
|
||||
GC_Run raw_run = box->glyph_run;
|
||||
if (AnyBit(box->desc.flags, UI_BoxFlag_DrawText) && raw_run.ready)
|
||||
{
|
||||
f32 max_baseline = box->p1.x - box->p0.x;
|
||||
b32 should_truncate = raw_run->count > 0 && (raw_run->rects[raw_run->count - 1].pos + raw_run->rects[raw_run->count - 1].advance) > max_baseline;
|
||||
f32 max_baseline = DimsFromRng2(box->rect).x;
|
||||
b32 should_truncate = raw_run.baseline_length > max_baseline && !AnyBit(box->desc.flags, UI_BoxFlag_NoTextTruncation);
|
||||
|
||||
/* Truncate run */
|
||||
GC_RunRect *truncated_rects = raw_run->rects;
|
||||
u32 truncated_rects_count = raw_run->count;
|
||||
if (should_truncate && !AnyBit(box->desc.flags, UI_BoxFlag_NoTextTruncation))
|
||||
u64 final_rects_count = 0;
|
||||
GC_RunRect *final_rects = 0;
|
||||
if (should_truncate)
|
||||
{
|
||||
/* Get elipses run */
|
||||
GC_Run *elipses_run = GC_RunFromString(scratch.arena, box->desc.font, Lit("..."));
|
||||
if (elipses_run->count > 0)
|
||||
GC_Run elipses_run = GC_RunFromString(scratch.arena, Lit("..."), box->desc.font, box->desc.font_size);
|
||||
f32 elipses_start_pos = max_baseline - elipses_run.baseline_length;
|
||||
|
||||
/* Append non-overflowed rects */
|
||||
final_rects = PushStructsNoZero(scratch.arena, GC_RunRect, raw_run.rects_count);
|
||||
for (u64 rect_idx = 0; rect_idx < raw_run.rects_count; ++rect_idx)
|
||||
{
|
||||
max_baseline -= elipses_run->rects[elipses_run->count - 1].pos + elipses_run->rects[elipses_run->count - 1].advance;
|
||||
GC_RunRect rr = raw_run.rects[rect_idx];
|
||||
if ((rr.baseline_pos + rr.advance) <= elipses_start_pos)
|
||||
{
|
||||
final_rects[final_rects_count] = rr;
|
||||
final_rects_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Subtract glyphs */
|
||||
while (truncated_rects_count > 0)
|
||||
/* Append elipses */
|
||||
for (u64 rect_idx = 0; rect_idx < elipses_run.rects_count; ++rect_idx)
|
||||
{
|
||||
GC_RunRect rr = raw_run->rects[truncated_rects_count - 1];
|
||||
if (rr.pos + rr.advance <= max_baseline)
|
||||
GC_RunRect rr = elipses_run.rects[rect_idx];
|
||||
rr.baseline_pos += elipses_start_pos;
|
||||
rr.bounds = AddRng2Vec2(rr.bounds, VEC2(elipses_start_pos, 0));
|
||||
if ((rr.baseline_pos + rr.advance) <= max_baseline)
|
||||
{
|
||||
break;
|
||||
}
|
||||
--truncated_rects_count;
|
||||
}
|
||||
|
||||
/* Merge trunc rects */
|
||||
/* FIXME: Verify this stil works as expected */
|
||||
{
|
||||
truncated_rects_count += elipses_run->count;
|
||||
truncated_rects = PushStructsNoZero(scratch.arena, GC_RunRect, truncated_rects_count + elipses_run->count);
|
||||
CopyStructs(truncated_rects, raw_run->rects, raw_run->count);
|
||||
f32 elipses_offset = truncated_rects_count > 0 ? (truncated_rects[truncated_rects_count - 1].pos + truncated_rects[truncated_rects_count - 1].advance) : 0;
|
||||
for (u32 i = 0; i < elipses_run->count; ++i)
|
||||
{
|
||||
GC_RunRect *rr = &truncated_rects[i + truncated_rects_count];
|
||||
*rr = elipses_run->rects[i];
|
||||
rr->pos += elipses_offset;
|
||||
final_rects[final_rects_count] = rr;
|
||||
final_rects_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
final_rects = raw_run.rects;
|
||||
final_rects_count = raw_run.rects_count;
|
||||
}
|
||||
|
||||
UI_AxisAlignment x_alignment = box->desc.child_alignment[Axis_X];
|
||||
UI_AxisAlignment y_alignment = box->desc.child_alignment[Axis_Y];
|
||||
@ -1306,68 +1297,64 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
}
|
||||
|
||||
/* Compute baseline */
|
||||
f32 ascent = raw_run->ascent;
|
||||
f32 descent = raw_run->descent;
|
||||
f32 cap = raw_run->cap;
|
||||
f32 baseline_width = truncated_rects_count > 0 ? (truncated_rects[truncated_rects_count - 1].pos + truncated_rects[truncated_rects_count - 1].advance) : 0;
|
||||
f32 baseline_height = ascent + descent;
|
||||
f32 box_width = box->p1.x - box->p0.x;
|
||||
f32 box_height = box->p1.y - box->p0.y;
|
||||
f32 ascent = raw_run.font_ascent;
|
||||
f32 font_descent = raw_run.font_descent;
|
||||
f32 cap = raw_run.font_cap;
|
||||
f32 baseline_width = raw_run.baseline_length;
|
||||
f32 baseline_height = ascent + font_descent;
|
||||
Vec2 box_dims = DimsFromRng2(box->rect);
|
||||
Vec2 baseline = ZI;
|
||||
switch (x_alignment)
|
||||
{
|
||||
case UI_AxisAlignment_Start:
|
||||
{
|
||||
baseline.x = box->p0.x;
|
||||
baseline.x = box->rect.p0.x;
|
||||
} break;
|
||||
case UI_AxisAlignment_End:
|
||||
{
|
||||
baseline.x = box->p1.x;
|
||||
baseline.x = box->rect.p1.x;
|
||||
baseline.x -= baseline_width;
|
||||
} break;
|
||||
case UI_AxisAlignment_Center:
|
||||
{
|
||||
baseline.x = box->p0.x;
|
||||
baseline.x += (box_width - baseline_width) / 2;
|
||||
baseline.x = box->rect.p0.x;
|
||||
baseline.x += (box_dims.x - baseline_width) / 2;
|
||||
} break;
|
||||
}
|
||||
switch (y_alignment)
|
||||
{
|
||||
case UI_AxisAlignment_Start:
|
||||
{
|
||||
baseline.y = box->p0.y;
|
||||
baseline.y = box->rect.p0.y;
|
||||
baseline.y += ascent;
|
||||
} break;
|
||||
case UI_AxisAlignment_End:
|
||||
{
|
||||
baseline.y = box->p1.y;
|
||||
baseline.y -= descent;
|
||||
baseline.y = box->rect.p1.y;
|
||||
baseline.y -= font_descent;
|
||||
} break;
|
||||
case UI_AxisAlignment_Center:
|
||||
{
|
||||
baseline.y = box->p0.y;
|
||||
baseline.y += box_height / 2;
|
||||
baseline.y = box->rect.p0.y;
|
||||
baseline.y += box_dims.y / 2;
|
||||
baseline.y += cap / 2;
|
||||
} break;
|
||||
}
|
||||
baseline = CeilVec2(baseline);
|
||||
|
||||
/* Push text rects */
|
||||
for (u64 i = 0; i < truncated_rects_count; ++i)
|
||||
for (u64 rect_idx = 0; rect_idx < final_rects_count; ++rect_idx)
|
||||
{
|
||||
GC_RunRect rr = truncated_rects[i];
|
||||
Vec2 glyph_size = rr.size;
|
||||
if (glyph_size.x != 0 || glyph_size.y != 0)
|
||||
GC_RunRect rr = final_rects[rect_idx];
|
||||
Vec2 glyph_dims = DimsFromRng2(rr.bounds);
|
||||
if (glyph_dims.x != 0 || glyph_dims.y != 0)
|
||||
{
|
||||
UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect);
|
||||
rect->p0 = AddVec2(baseline, VEC2(rr.pos, 0));
|
||||
rect->p0 = AddVec2(rect->p0, rr.offset);
|
||||
rect->p1 = AddVec2(rect->p0, glyph_size);
|
||||
rect->bounds = AddRng2Vec2(rr.bounds, baseline);
|
||||
rect->debug_lin = LinearFromSrgb(box->desc.debug_color);
|
||||
rect->tint_lin = LinearFromSrgb(box->desc.tint);
|
||||
rect->tex = rr.tex;
|
||||
rect->tex_uv0 = rr.uv.p0;
|
||||
rect->tex_uv1 = rr.uv.p1;
|
||||
rect->tex_slice_uv = rr.tex_uv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,11 +110,10 @@ Enum(UI_BoxFlag)
|
||||
X(FontSize, u32) \
|
||||
X(Text, String) \
|
||||
X(BackgroundTexture, G_Texture2DRef) \
|
||||
X(BackgroundTextureUv0, Vec2) \
|
||||
X(BackgroundTextureUv1, Vec2) \
|
||||
/* --------------------------------------- */ \
|
||||
/* ----------- Virtual styles ----------- */ \
|
||||
/* --------------------------------------- */ \
|
||||
X(BackgroundTextureSliceUv, Rng2) \
|
||||
/* -------------------------------------------- */ \
|
||||
/* -------------- Virtual styles -------------- */ \
|
||||
/* -------------------------------------------- */ \
|
||||
X(BeginVirtualStyles_, i8) \
|
||||
X(ChildAlignment, UI_Alignment) \
|
||||
X(AxisSize, UI_Size) \
|
||||
@ -187,8 +186,7 @@ Struct(UI_Report)
|
||||
Vec2 last_m1_offset;
|
||||
|
||||
/* Where was this box last rendered in screen coordinates */
|
||||
Vec2 screen_p0;
|
||||
Vec2 screen_p1;
|
||||
Rng2 screen_rect;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -233,8 +231,7 @@ Struct(UI_Cmd)
|
||||
{
|
||||
UI_Key key;
|
||||
G_Texture2DRef tex;
|
||||
Vec2 uv0;
|
||||
Vec2 uv1;
|
||||
Rng2 slice_uv;
|
||||
} set_raw_texture;
|
||||
};
|
||||
};
|
||||
@ -269,22 +266,20 @@ Struct(UI_Box)
|
||||
//- Cmd data
|
||||
UI_BoxDesc desc;
|
||||
G_Texture2DRef raw_texture;
|
||||
Vec2 raw_texture_uv0;
|
||||
Vec2 raw_texture_uv1;
|
||||
Rng2 raw_texture_slice_uv;
|
||||
|
||||
//- Pre-layout data
|
||||
u64 pre_index;
|
||||
u64 post_index;
|
||||
|
||||
//- Layout data
|
||||
GC_Run *glyph_run;
|
||||
GC_Run glyph_run;
|
||||
f32 layout_cursor;
|
||||
f32 solved_dims[Axis_CountXY];
|
||||
f32 final_children_size_accum[Axis_CountXY];
|
||||
|
||||
//- Layout results
|
||||
Vec2 p0;
|
||||
Vec2 p1;
|
||||
Rng2 rect;
|
||||
f32 rounding_tl;
|
||||
f32 rounding_tr;
|
||||
f32 rounding_br;
|
||||
@ -443,7 +438,7 @@ UI_Style UI_PopStyle(UI_StyleDesc desc);
|
||||
UI_Key UI_BuildBoxEx(UI_Key key);
|
||||
#define UI_BuildBox() UI_BuildBoxEx(UI_TransKey())
|
||||
|
||||
void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Vec2 uv0, Vec2 uv1);
|
||||
void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Rng2 uv);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Report
|
||||
|
||||
@ -20,16 +20,16 @@ Struct(UI_DParams)
|
||||
|
||||
Struct(UI_DRect)
|
||||
{
|
||||
Vec2 p0;
|
||||
Vec2 p1;
|
||||
Rng2 bounds;
|
||||
|
||||
G_Texture2DRef tex;
|
||||
Rng2 tex_slice_uv;
|
||||
|
||||
Vec4 tint_lin;
|
||||
Vec4 background_lin;
|
||||
Vec4 border_lin;
|
||||
Vec4 debug_lin;
|
||||
f32 border;
|
||||
Vec2 tex_uv0;
|
||||
Vec2 tex_uv1;
|
||||
G_Texture2DRef tex;
|
||||
|
||||
f32 tl_rounding;
|
||||
f32 tr_rounding;
|
||||
|
||||
@ -11,8 +11,8 @@ VertexShader(UI_DRectVS, UI_DRectPSInput)
|
||||
UI_DRect rect = rects[SV_InstanceID];
|
||||
|
||||
Vec2 rect_uv = RectUvFromVertexId(SV_VertexID);
|
||||
Vec2 tex_uv = lerp(rect.tex_uv0, rect.tex_uv1, rect_uv);
|
||||
Vec2 target_pos = lerp(rect.p0, rect.p1, rect_uv);
|
||||
Vec2 tex_uv = lerp(rect.tex_slice_uv.p0, rect.tex_slice_uv.p1, rect_uv);
|
||||
Vec2 target_pos = lerp(rect.bounds.p0, rect.bounds.p1, rect_uv);
|
||||
|
||||
UI_DRectPSInput result;
|
||||
result.sv_position = Vec4(NdcFromPos(target_pos, Vec2(params.target_size).xy), 0, 1);
|
||||
@ -39,8 +39,8 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
|
||||
|
||||
Vec2 p = input.sv_position.xy;
|
||||
Vec2 rect_uv = input.rect_uv;
|
||||
Vec2 p0 = rect.p0;
|
||||
Vec2 p1 = rect.p1;
|
||||
Vec2 p0 = rect.bounds.p0;
|
||||
Vec2 p1 = rect.bounds.p1;
|
||||
|
||||
/* Compute rect sdf (negative means pixel is inside of rect) */
|
||||
f32 rect_dist = min(min(p.x - p0.x, p1.x - p.x), min(p.y - p0.y, p1.y - p.y));
|
||||
@ -147,6 +147,6 @@ PixelShader(UI_BlitPS, UI_BlitPSOutput, UI_BlitPSInput input)
|
||||
Vec4 result = tex.Sample(sampler, uv);
|
||||
|
||||
UI_BlitPSOutput output;
|
||||
output.SV_Target0 = result;
|
||||
output.sv_target0 = result;
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ Struct(UI_BlitPSInput)
|
||||
|
||||
Struct(UI_BlitPSOutput)
|
||||
{
|
||||
Semantic(Vec4, SV_Target0);
|
||||
Semantic(Vec4, sv_target0);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Loading…
Reference in New Issue
Block a user