Optimize wrapped text function by not remeasuring previous text

main
Cameron Murphy Reikes 2 years ago
parent 389d17e897
commit 5baaa77d5f

@ -1082,9 +1082,14 @@ void end_text_input(char *what_player_said_cstr)
sg_image image_font = { 0 }; sg_image image_font = { 0 };
Vec2 image_font_size = { 0 }; // this image's size is queried a lot, and img_size seems to be slow when profiled
float font_line_advance = 0.0f; float font_line_advance = 0.0f;
const float font_size = 32.0; const float font_size = 32.0;
float font_scale;
unsigned char *fontBuffer = 0; // font file data. Can't be freed until program quits, because used to get character width
stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs
stbtt_fontinfo font;
static struct static struct
@ -1155,6 +1160,13 @@ Color blendalpha(Color c, float alpha)
return to_return; return to_return;
} }
// in pixels
Vec2 img_size(sg_image img)
{
sg_image_info info = sg_query_image_info(img);
return V2((float)info.width, (float)info.height);
}
void init(void) void init(void)
{ {
#ifdef WEB #ifdef WEB
@ -1200,7 +1212,7 @@ void init(void)
size_t size = ftell(fontFile); /* how long is the file ? */ size_t size = ftell(fontFile); /* how long is the file ? */
fseek(fontFile, 0, SEEK_SET); /* reset */ fseek(fontFile, 0, SEEK_SET); /* reset */
unsigned char *fontBuffer = malloc(size); fontBuffer = calloc(size, 1);
fread(fontBuffer, size, 1, fontFile); fread(fontBuffer, size, 1, fontFile);
fclose(fontFile); fclose(fontFile);
@ -1230,17 +1242,17 @@ void init(void)
} }
}); });
stbtt_fontinfo font; image_font_size = img_size(image_font);
stbtt_InitFont(&font, fontBuffer, 0); stbtt_InitFont(&font, fontBuffer, 0);
int ascent = 0; int ascent = 0;
int descent = 0; int descent = 0;
int lineGap = 0; int lineGap = 0;
float scale = stbtt_ScaleForPixelHeight(&font, font_size); font_scale = stbtt_ScaleForPixelHeight(&font, font_size);
stbtt_GetFontVMetrics(&font, &ascent, &descent, &lineGap); stbtt_GetFontVMetrics(&font, &ascent, &descent, &lineGap);
font_line_advance = (float)(ascent - descent + lineGap) * scale * 0.75f; font_line_advance = (float)(ascent - descent + lineGap) * font_scale * 0.75f;
free(font_bitmap_rgba); free(font_bitmap_rgba);
free(fontBuffer);
} }
state.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc) state.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc)
@ -1397,12 +1409,6 @@ Vec2 cam_offset()
return to_return; return to_return;
} }
// in pixels
Vec2 img_size(sg_image img)
{
sg_image_info info = sg_query_image_info(img);
return V2((float)info.width, (float)info.height);
}
#define IMG(img) img, full_region(img) #define IMG(img) img, full_region(img)
@ -1907,14 +1913,17 @@ typedef struct TextParams
// returns bounds. To measure text you can set dry run to true and get the bounds // returns bounds. To measure text you can set dry run to true and get the bounds
AABB draw_text(TextParams t) AABB draw_text(TextParams t)
{ {
size_t text_len = t.text.size;
AABB bounds = { 0 }; AABB bounds = { 0 };
PROFILE_SCOPE("draw text")
{
size_t text_len = t.text.size;
float y = 0.0; float y = 0.0;
float x = 0.0; float x = 0.0;
for (int i = 0; i < text_len; i++) for (int i = 0; i < text_len; i++)
{ {
stbtt_aligned_quad q; stbtt_aligned_quad q;
float old_y = y; float old_y = y;
PROFILE_SCOPE("get baked quad")
stbtt_GetBakedQuad(cdata, 512, 512, t.text.str[i]-32, &x, &y, &q, 1); stbtt_GetBakedQuad(cdata, 512, 512, t.text.str[i]-32, &x, &y, &q, 1);
float difference = y - old_y; float difference = y - old_y;
y = old_y + difference; y = old_y + difference;
@ -1931,7 +1940,10 @@ AABB draw_text(TextParams t)
} }
if (size.Y > 0.0 && size.X > 0.0) if (size.Y > 0.0 && size.X > 0.0)
{ // spaces (and maybe other characters) produce quads of size 0 { // spaces (and maybe other characters) produce quads of size 0
Quad to_draw = { Quad to_draw;
PROFILE_SCOPE("Calculate to draw quad")
{
to_draw = (Quad){
.points = { .points = {
AddV2(V2(q.x0, -q.y0), V2(0.0f, 0.0f)), AddV2(V2(q.x0, -q.y0), V2(0.0f, 0.0f)),
AddV2(V2(q.x0, -q.y0), V2(size.X, 0.0f)), AddV2(V2(q.x0, -q.y0), V2(size.X, 0.0f)),
@ -1939,7 +1951,9 @@ AABB draw_text(TextParams t)
AddV2(V2(q.x0, -q.y0), V2(0.0f, -size.Y)), AddV2(V2(q.x0, -q.y0), V2(0.0f, -size.Y)),
}, },
}; };
}
PROFILE_SCOPE("Scale points")
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
to_draw.points[i] = MulV2F(to_draw.points[i], t.scale); to_draw.points[i] = MulV2F(to_draw.points[i], t.scale);
@ -1950,11 +1964,15 @@ AABB draw_text(TextParams t)
.upper_left = V2(q.s0, q.t0), .upper_left = V2(q.s0, q.t0),
.lower_right = V2(q.s1, q.t1), .lower_right = V2(q.s1, q.t1),
}; };
font_atlas_region.upper_left.X *= img_size(image_font).X; PROFILE_SCOPE("Scaling font atlas region to img font size")
font_atlas_region.lower_right.X *= img_size(image_font).X; {
font_atlas_region.upper_left.Y *= img_size(image_font).Y; font_atlas_region.upper_left.X *= image_font_size.X;
font_atlas_region.lower_right.Y *= img_size(image_font).Y; font_atlas_region.lower_right.X *= image_font_size.X;
font_atlas_region.upper_left.Y *= image_font_size.Y;
font_atlas_region.lower_right.Y *= image_font_size.Y;
}
PROFILE_SCOPE("bounds computation")
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
bounds.upper_left.X = fminf(bounds.upper_left.X, to_draw.points[i].X); bounds.upper_left.X = fminf(bounds.upper_left.X, to_draw.points[i].X);
@ -1963,12 +1981,15 @@ AABB draw_text(TextParams t)
bounds.lower_right.Y = fminf(bounds.lower_right.Y, to_draw.points[i].Y); bounds.lower_right.Y = fminf(bounds.lower_right.Y, to_draw.points[i].Y);
} }
PROFILE_SCOPE("shifting points")
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
to_draw.points[i] = AddV2(to_draw.points[i], t.pos); to_draw.points[i] = AddV2(to_draw.points[i], t.pos);
} }
if (!t.dry_run) if (!t.dry_run)
{
PROFILE_SCOPE("Actually drawing")
{ {
Color col = t.color; Color col = t.color;
if (t.colors) if (t.colors)
@ -1991,9 +2012,12 @@ AABB draw_text(TextParams t)
} }
} }
} }
}
bounds.upper_left = AddV2(bounds.upper_left, t.pos); bounds.upper_left = AddV2(bounds.upper_left, t.pos);
bounds.lower_right = AddV2(bounds.lower_right, t.pos); bounds.lower_right = AddV2(bounds.lower_right, t.pos);
}
return bounds; return bounds;
} }
@ -2281,6 +2305,13 @@ Vec2 move_and_slide(MoveSlideParams p)
return result_pos; return result_pos;
} }
float character_width(int ascii_letter, float text_scale)
{
int advanceWidth;
stbtt_GetCodepointHMetrics(&font, ascii_letter, &advanceWidth, 0);
return (float)advanceWidth * font_scale * text_scale;
}
typedef struct typedef struct
{ {
bool dry_run; bool dry_run;
@ -2308,13 +2339,11 @@ float draw_wrapped_text(WrappedTextParams p)
Color colors_to_draw[MAX_SENTENCE_LENGTH] = { 0 }; Color colors_to_draw[MAX_SENTENCE_LENGTH] = { 0 };
size_t chars_from_sentence = 0; size_t chars_from_sentence = 0;
AABB line_bounds = { 0 }; AABB line_bounds = { 0 };
float current_line_width = 0.0f;
while (chars_from_sentence <= sentence_len) while (chars_from_sentence <= sentence_len)
{ {
memset(line_to_draw, 0, MAX_SENTENCE_LENGTH); //line_bounds = draw_text((TextParams) { !p.screen_space, true, MD_S8CString(line_to_draw), cursor, BLACK, p.text_scale, p.clip_to, .do_clipping = p.do_clipping});
memcpy(line_to_draw, sentence_to_draw, chars_from_sentence); if (current_line_width >= p.max_width)
line_bounds = draw_text((TextParams) { !p.screen_space, true, MD_S8CString(line_to_draw), cursor, BLACK, p.text_scale, p.clip_to, .do_clipping = p.do_clipping});
if (line_bounds.lower_right.X > p.at_point.X + p.max_width)
{ {
// too big // too big
if (chars_from_sentence <= 0) chars_from_sentence = 1; // @CREDIT(warehouse56) always draw at least one character, if there's not enough room if (chars_from_sentence <= 0) chars_from_sentence = 1; // @CREDIT(warehouse56) always draw at least one character, if there's not enough room
@ -2322,6 +2351,11 @@ float draw_wrapped_text(WrappedTextParams p)
break; break;
} }
chars_from_sentence += 1; chars_from_sentence += 1;
memset(line_to_draw, 0, MAX_SENTENCE_LENGTH);
memcpy(line_to_draw, sentence_to_draw, chars_from_sentence);
//AABB next_character_bounds = draw_text((TextParams) { !p.screen_space, true, MD_S8((MD_u8*)line_to_draw + chars_from_sentence - 1, 1), cursor, BLACK, p.text_scale, p.clip_to, .do_clipping = p.do_clipping});
//current_line_width += aabb_size(next_character_bounds).x;
current_line_width += character_width( *(line_to_draw + chars_from_sentence - 1), p.text_scale);
} }
if (chars_from_sentence > sentence_len) chars_from_sentence--; if (chars_from_sentence > sentence_len) chars_from_sentence--;
memset(line_to_draw, 0, MAX_SENTENCE_LENGTH); memset(line_to_draw, 0, MAX_SENTENCE_LENGTH);
@ -3455,6 +3489,9 @@ void frame(void)
#ifdef DESKTOP #ifdef DESKTOP
MD_ArenaTemp scratch = MD_GetScratch(0, 0); MD_ArenaTemp scratch = MD_GetScratch(0, 0);
MD_String8 mocked_ai_response = {0};
if(false)
{
const char *argument = 0; const char *argument = 0;
MD_String8List dialog_elems = {0}; MD_String8List dialog_elems = {0};
ActionKind act = ACT_none; ActionKind act = ACT_none;
@ -3475,10 +3512,7 @@ void frame(void)
MD_S8ListPushFmt(scratch.arena, &dialog_elems, "%d times talked", it->times_talked_to); MD_S8ListPushFmt(scratch.arena, &dialog_elems, "%d times talked", it->times_talked_to);
} }
MD_String8 mocked_ai_response = {0};
if(false)
{
MD_StringJoin join = {0}; MD_StringJoin join = {0};
MD_String8 dialog = MD_S8ListJoin(scratch.arena, dialog_elems, &join); MD_String8 dialog = MD_S8ListJoin(scratch.arena, dialog_elems, &join);
if (argument) if (argument)
@ -4360,6 +4394,7 @@ void frame(void)
void cleanup(void) void cleanup(void)
{ {
free(fontBuffer);
sg_shutdown(); sg_shutdown();
hmfree(imui_state); hmfree(imui_state);
Log("Cleaning up\n"); Log("Cleaning up\n");

Loading…
Cancel
Save