From 48c0eb8461c87aad4ce69c28f442fe5779f5479b Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Wed, 22 Feb 2023 19:14:19 -0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=98=AD=20wrapped=20text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build_desktop_debug.bat | 3 +- main.c | 113 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 107 insertions(+), 9 deletions(-) diff --git a/build_desktop_debug.bat b/build_desktop_debug.bat index 0f35ac4..9c7546a 100644 --- a/build_desktop_debug.bat +++ b/build_desktop_debug.bat @@ -3,7 +3,8 @@ @REM https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170 call run_codegen.bat || goto :error -cl /DDEVTOOLS /Igen /Ithirdparty /W3 /Zi /WX main.c || goto :error +@REM cl /DDEVTOOLS /Igen /Ithirdparty /W3 /Zi /WX main.c || goto :error +cl /Igen /Ithirdparty /W3 /Zi /WX main.c || goto :error goto :EOF :error diff --git a/main.c b/main.c index 08acc50..d42a9c3 100644 --- a/main.c +++ b/main.c @@ -92,6 +92,13 @@ typedef enum EntityKind ENTITY_BULLET, } EntityKind; +#define MAX_SENTENCE_LENGTH 400 +typedef struct { char text[MAX_SENTENCE_LENGTH]; } Sentence; + +typedef struct Dialog +{ + Sentence sentences[8]; +} Dialog; typedef struct Entity { @@ -544,6 +551,7 @@ typedef Vec4 Color; #define WHITE (Color){1.0f, 1.0f, 1.0f, 1.0f} #define BLACK (Color){0.0f, 0.0f, 0.0f, 1.0f} #define RED (Color){1.0f, 0.0f, 0.0f, 1.0f} +#define GREEN (Color){0.0f, 1.0f, 0.0f, 1.0f} Vec2 screen_size() @@ -833,11 +841,10 @@ Vec2 tile_id_to_coord(sg_image tileset_image, Vec2 tile_size, uint16_t tile_id) } // returns bounds. To measure text you can set dry run to true and get the bounds -AABB draw_text(bool world_space, bool dry_run, const char *text, Vec2 pos, Color color) +AABB draw_text(bool world_space, bool dry_run, const char *text, Vec2 pos, Color color, float scale) { size_t text_len = strlen(text); - AABB bounds = - {0}; + AABB bounds = {0}; float y = 0.0; float x = 0.0; for(int i = 0; i < text_len; i++) @@ -869,6 +876,11 @@ AABB draw_text(bool world_space, bool dry_run, const char *text, Vec2 pos, Color }, }; + for(int i = 0; i < 4; i++) + { + to_draw.points[i] = MulV2F(to_draw.points[i], scale); + } + AABB font_atlas_region = (AABB) { .upper_left = V2(q.s0, q.t0), @@ -1040,7 +1052,8 @@ Vec2 move_and_slide(Entity *from, Vec2 position, Vec2 movement_this_frame) { AABB to_depenetrate_from = to_check[i]; dbgrect(to_depenetrate_from); - while(overlapping(to_depenetrate_from, at_new)) + int iters_tried_to_push_apart = 0; + while(overlapping(to_depenetrate_from, at_new) && iters_tried_to_push_apart < 500) { //dbgsquare(to_depenetrate_from.upper_left); //dbgsquare(to_depenetrate_from.lower_right); @@ -1069,12 +1082,56 @@ Vec2 move_and_slide(Entity *from, Vec2 position, Vec2 movement_this_frame) Vec2 move = MulV2F(move_dir, move_dist); at_new.upper_left = AddV2(at_new.upper_left,move); at_new.lower_right = AddV2(at_new.lower_right,move); + iters_tried_to_push_apart++; } } return aabb_center(at_new); } +// returns next vertical cursor position +float draw_wrapped_text(Vec2 at_point, float max_width, char *text, float text_scale, Color color) +{ + char *sentence_to_draw = text; + size_t sentence_len = strlen(sentence_to_draw); + + Vec2 cursor = at_point; + while(sentence_len > 0) + { + char line_to_draw[MAX_SENTENCE_LENGTH] = {0}; + size_t chars_from_sentence = 0; + AABB line_bounds = {0}; + while(chars_from_sentence <= sentence_len) + { + memset(line_to_draw, 0, MAX_SENTENCE_LENGTH); + memcpy(line_to_draw, sentence_to_draw, chars_from_sentence); + + line_bounds = draw_text(true, true, line_to_draw, cursor, color, text_scale); + if(line_bounds.lower_right.X > at_point.X + max_width) + { + // too big + assert(chars_from_sentence > 0); + chars_from_sentence -= 1; + break; + } + + chars_from_sentence += 1; + } + if(chars_from_sentence > sentence_len) chars_from_sentence--; + memset(line_to_draw, 0, MAX_SENTENCE_LENGTH); + memcpy(line_to_draw, sentence_to_draw, chars_from_sentence); + float line_height = line_bounds.upper_left.Y - line_bounds.lower_right.Y; + AABB drawn_bounds = draw_text(true, false, line_to_draw, AddV2(cursor, V2(0.0f, -line_height)), color, text_scale); + dbgrect(drawn_bounds); + + sentence_len -= chars_from_sentence; + sentence_to_draw += chars_from_sentence; + cursor = V2(drawn_bounds.upper_left.X, drawn_bounds.lower_right.Y); + } + + return cursor.Y; +} + double time = 0.0; double last_frame_processing_time = 0.0; uint64_t last_frame_time; @@ -1166,7 +1223,7 @@ void frame(void) Vec2 points[4] ={0}; AABB q = tile_aabb(hovering); dbgrect(q); - draw_text(false, false, tprint("%d", get_tile(&level_level0, hovering).kind), world_to_screen(tilecoord_to_world(hovering)), BLACK); + draw_text(false, false, tprint("%d", get_tile(&level_level0, hovering).kind), world_to_screen(tilecoord_to_world(hovering)), BLACK, 1.0f); } // debug draw font image @@ -1180,12 +1237,12 @@ void frame(void) int num_entities = 0; ENTITIES_ITER(entities) num_entities++; char *stats = tprint("Frametime: %.1f ms\nProcessing: %.1f ms\nEntities: %d\n", dt*1000.0, last_frame_processing_time*1000.0, num_entities); - AABB bounds = draw_text(false, true, stats, pos, BLACK); + AABB bounds = draw_text(false, true, stats, pos, BLACK, 1.0f); pos.Y -= bounds.upper_left.Y - screen_size().Y; - bounds = draw_text(false, true, stats, pos, BLACK); + bounds = draw_text(false, true, stats, pos, BLACK, 1.0f); // background panel colorquad(false, quad_aabb(bounds), (Color){1.0, 1.0, 1.0, 0.3f}); - draw_text(false, false, stats, pos, BLACK); + draw_text(false, false, stats, pos, BLACK, 1.0f); } #endif // devtools @@ -1371,6 +1428,46 @@ void frame(void) } } + // do dialog + AABB dialog_rect = centered_aabb(player->pos, V2(TILE_SIZE*2.0f, TILE_SIZE*2.0f)); + dbgrect(dialog_rect); + Overlapping possible_dialogs = get_overlapping(cur_level, dialog_rect); + Entity *closest_talkto = NULL; + float closest_talkto_dist = INFINITY; + for(int i = 0; i < possible_dialogs.num_results; i++) + { + Overlap *it = &possible_dialogs.results[i]; + if(!it->is_tile && it->e->kind == ENTITY_OLD_MAN && !it->e->aggressive) + { + float dist = LenV2(SubV2(it->e->pos, player->pos)); + if(dist < closest_talkto_dist) + { + closest_talkto_dist = dist; + closest_talkto = it->e; + } + } + } + if(closest_talkto != NULL) + { + Dialog dialog = { + .sentences[0].text = "I'm an old man. fjdslfdasljfla dsfjdsalkf adskjfdlskfkladsjfkljdskljsadlkfjdsaklfjldsajf", + .sentences[1].text = "I'm the player. I have lots of things to say. Bla bla bla. All I do is say things. How cringe and terrible", + }; + float panel_width = 250.0f; + float panel_height = 100.0f; + float panel_vert_offset = 30.0f; + AABB dialog_panel = (AABB){ + .upper_left = AddV2(closest_talkto->pos, V2(-panel_width/2.0f, panel_vert_offset+panel_height)), + .lower_right = AddV2(closest_talkto->pos, V2(panel_width/2.0f, panel_vert_offset)), + }; + colorquad(true, quad_aabb(dialog_panel), (Color){1.0f, 1.0f, 1.0f, 0.2f}); + + float new_line_height = draw_wrapped_text(dialog_panel.upper_left, dialog_panel.lower_right.X - dialog_panel.upper_left.X, dialog.sentences[0].text, 0.5f, WHITE); + new_line_height = draw_wrapped_text(V2(dialog_panel.upper_left.X, new_line_height), dialog_panel.lower_right.X - dialog_panel.upper_left.X, dialog.sentences[1].text, 0.5f, GREEN); + + dbgrect(dialog_panel); + } + sg_end_pass(); sg_commit();