diff --git a/assets/white square.png b/assets/white square.png index 9054853..d58e9f7 100644 Binary files a/assets/white square.png and b/assets/white square.png differ diff --git a/main.c b/main.c index 3d0fdb4..fbf28a8 100644 --- a/main.c +++ b/main.c @@ -190,6 +190,7 @@ typedef HMM_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} HMM_Vec2 screen_size() { return HMM_V2((float)sapp_width(), (float)sapp_height()); @@ -210,6 +211,20 @@ HMM_Vec2 cam_offset() { return HMM_AddV2(cam.pos, HMM_MulV2F(screen_size(), 0.5f)); } +// in pixels +HMM_Vec2 img_size(sg_image img) { + sg_image_info info = sg_query_image_info(img); + return HMM_V2((float)info.width, (float)info.height); +} + +// full region in pixels +AABB full_region(sg_image img) { + return (AABB) { + .upper_left = HMM_V2(0.0f, 0.0f), + .lower_right = img_size(img), + }; +} + // screen coords are in pixels counting from bottom left as (0,0), Y+ is up HMM_Vec2 world_to_screen(HMM_Vec2 world) { HMM_Vec2 to_return = world; @@ -285,7 +300,15 @@ bool overlapping(AABB a, AABB b) { // points must be of length 4, and be in the order: upper left, upper right, lower right, lower left // the points are in pixels in screen space. The image region is in pixel space of the image -void draw_quad_all_parameters(HMM_Vec2 *points, sg_image image, AABB image_region, Color tint) { +void draw_quad(bool world_space, HMM_Vec2 *points_in, sg_image image, AABB image_region, Color tint) { + HMM_Vec2 points[4] = {0}; + memcpy(points, points_in, sizeof(points)); + + if(world_space) { + for(int i = 0; i < 4; i++) { + points[i] = world_to_screen(points[i]); + } + } AABB cam_aabb = { .upper_left = HMM_V2(0.0, screen_size().Y), .lower_right = HMM_V2(screen_size().X, 0.0) }; AABB points_bounding_box = { .upper_left = HMM_V2(INFINITY, -INFINITY), .lower_right = HMM_V2(-INFINITY, INFINITY) }; @@ -340,27 +363,70 @@ void draw_quad_all_parameters(HMM_Vec2 *points, sg_image image, AABB image_regio sg_draw(0, 6, 1); } -void draw_quad_world_all(HMM_Vec2 *points, sg_image image, AABB image_region, Color tint) { - HMM_Vec2 into_screen[4] = {0}; - memcpy(into_screen, points, sizeof(into_screen)); - for(int i = 0; i < 4; i++) { - into_screen[i] = world_to_screen(into_screen[i]); - } - draw_quad_all_parameters(into_screen, image, image_region, tint); -} -// in pixels -HMM_Vec2 img_size(sg_image img) { - sg_image_info info = sg_query_image_info(img); - return HMM_V2((float)info.width, (float)info.height); +void colorbox(bool world_space, HMM_Vec2 upper_left, HMM_Vec2 lower_right, Color color) { + HMM_Vec2 size = HMM_SubV2(lower_right, upper_left); + size.Y *= -1.0; + assert(size.Y >= 0.0); + HMM_Vec2 points[4] = { + HMM_AddV2(upper_left, HMM_V2(0.0f, 0.0f)), + HMM_AddV2(upper_left, HMM_V2(size.X, 0.0f)), + HMM_AddV2(upper_left, HMM_V2(size.X, -size.Y)), + HMM_AddV2(upper_left, HMM_V2(0.0f, -size.Y)), + }; + draw_quad(world_space, points, image_white_square, full_region(image_white_square), color); } -// full region in pixels -AABB full_region(sg_image img) { - return (AABB) { - .upper_left = HMM_V2(0.0f, 0.0f), - .lower_right = img_size(img), - }; +// 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, size_t length, HMM_Vec2 pos, Color color) { + size_t text_len = strlen(text); + AABB bounds = {0}; + float y = 0.0; + float x = 0.0; + for(int i = 0; i < text_len; i++) { + stbtt_aligned_quad q; + float old_y = y; + stbtt_GetBakedQuad(cdata, 512, 512, text[i]-32, &x, &y, &q, 1); + float difference = y - old_y; + y = old_y + difference; + + HMM_Vec2 size = HMM_V2(q.x1 - q.x0, q.y1 - q.y0); + if(size.Y > 0.0 && size.X > 0.0) { // spaces (and maybe other characters) produce quads of size 0 + HMM_Vec2 points[4] = { + HMM_AddV2(HMM_V2(q.x0, -q.y0), HMM_V2(0.0f, 0.0f)), + HMM_AddV2(HMM_V2(q.x0, -q.y0), HMM_V2(size.X, 0.0f)), + HMM_AddV2(HMM_V2(q.x0, -q.y0), HMM_V2(size.X, -size.Y)), + HMM_AddV2(HMM_V2(q.x0, -q.y0), HMM_V2(0.0f, -size.Y)), + }; + + AABB font_atlas_region = (AABB) { + .upper_left = HMM_V2(q.s0, q.t0), + .lower_right = HMM_V2(q.s1, q.t1), + }; + font_atlas_region.upper_left.X *= img_size(image_font).X; + 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.lower_right.Y *= img_size(image_font).Y; + + for(int i = 0; i < 4; i++) { + bounds.upper_left.X = min(bounds.upper_left.X, points[i].X); + bounds.upper_left.Y = max(bounds.upper_left.Y, points[i].Y); + bounds.lower_right.X = max(bounds.lower_right.X, points[i].X); + bounds.lower_right.Y = min(bounds.lower_right.Y, points[i].Y); + } + + for(int i = 0; i < 4; i++) { + points[i] = HMM_AddV2(points[i], pos); + } + + if(!dry_run) { + draw_quad(world_space, points, image_font, font_atlas_region, color); + } + } + } + + return bounds; } double time = 0.0; @@ -376,6 +442,7 @@ void frame(void) { double dt_double = 0.0; { dt_double = stm_sec(stm_diff(stm_now(), last_frame_time)); + dt_double = min(dt_double, 5.0 / 60.0); // clamp dt at maximum 5 frames, avoid super huge dt time += dt_double; last_frame_time = stm_now(); } @@ -413,7 +480,7 @@ void frame(void) { } } if(info == NULL) info = &mystery_tile; - draw_quad_world_all(points, *info->img, info->regions[0], WHITE); + draw_quad(true, points, *info->img, info->regions[0], WHITE); } } } @@ -423,40 +490,29 @@ void frame(void) { { HMM_Vec2 points[4] = {0}; quad_points_centered_size(points, HMM_V2(0.0, 0.0), HMM_V2(250.0, 250.0)); - draw_quad_world_all(points, image_font,full_region(image_font), BLACK); + draw_quad(true, points, image_font,full_region(image_font), BLACK); } + +#ifdef DEVTOOLS + // statistics + { + // background panel + colorbox(false, HMM_V2(0.0, 0.0), HMM_V2(200.0, -200.0), (Color){1.0, 1.0, 1.0, 0.5}); + char frametime[128] = {0}; + snprintf(frametime, 128, "Frametime: %.1f ms", dt*1000.0); + draw_text(false, false, frametime, strlen(frametime), HMM_V2(0.0, 0.0), BLACK); + } +#endif + const char *text = "great idea"; + // measure text + { + AABB bounds = draw_text(true, true, text, strlen(text), HMM_V2(0.0, 0.0), BLACK); + colorbox(true, bounds.upper_left, bounds.lower_right, (Color){1.0,0.0,0.0,0.5}); + } // draw text - const char *text = "Hello, can anybody hear me?"; { - float x = 0.0; - float y = 0.0; - for(int i = 0; i < strlen(text); i++) { - stbtt_aligned_quad q; - float old_y = y; - stbtt_GetBakedQuad(cdata, 512, 512, text[i]-32, &x, &y, &q, 1); - float difference = y - old_y; - y = old_y + difference; - - HMM_Vec2 size = HMM_V2(q.x1 - q.x0, q.y1 - q.y0); - HMM_Vec2 points[4] = { - HMM_AddV2(HMM_V2(q.x0, -q.y0), HMM_V2(0.0f, 0.0f)), - HMM_AddV2(HMM_V2(q.x0, -q.y0), HMM_V2(size.X, 0.0f)), - HMM_AddV2(HMM_V2(q.x0, -q.y0), HMM_V2(size.X, -size.Y)), - HMM_AddV2(HMM_V2(q.x0, -q.y0), HMM_V2(0.0f, -size.Y)), - }; - - AABB region = (AABB){ - .upper_left = HMM_V2(q.s0, q.t0), - .lower_right = HMM_V2(q.s1, q.t1), - }; - region.upper_left.X *= img_size(image_font).X; - region.lower_right.X *= img_size(image_font).X; - region.upper_left.Y *= img_size(image_font).Y; - region.lower_right.Y *= img_size(image_font).Y; - - draw_quad_world_all(points, image_font, region, BLACK); - } + draw_text(true, false, text, strlen(text), HMM_V2(0.0, 0.0), BLACK); } // merchant @@ -471,7 +527,7 @@ void frame(void) { region.upper_left = HMM_V2( (float)((index % ((int)img_size(image_merchant).X/cell_size)) * cell_size), 0.0); region.lower_right = HMM_V2(region.upper_left.X + (float)cell_size, (float)cell_size); - draw_quad_world_all(points, image_merchant, region, WHITE); + draw_quad(true, points, image_merchant, region, WHITE); sg_end_pass(); sg_commit();