From b292920b36adfbf79c56c2d4862017e006b99b52 Mon Sep 17 00:00:00 2001 From: Lukas Krickl Date: Sat, 7 Mar 2026 09:02:32 +0100 Subject: [PATCH] rendering: wip viewport culling for map rendering. - Added camera zoom rendering for tiles. --- src/r_assets.c | 36 ++++++++++++++++-------------------- src/r_render.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- src/r_render.h | 12 +++++++++++- src/t_camera.c | 2 ++ src/t_map.c | 12 +++--------- src/u_debug_font.h | 8 ++++---- 6 files changed, 81 insertions(+), 35 deletions(-) diff --git a/src/r_assets.c b/src/r_assets.c index 6c2f6aa..0943a47 100644 --- a/src/r_assets.c +++ b/src/r_assets.c @@ -52,29 +52,22 @@ void r_draw_solid_isometric_tile(i32 x, i32 y, r_color color) { u32 j = 0; r_color final_color; u32 hover_color_shift = 0; - struct u_vec2 t = u_tile_to_screen(x, y); - struct u_vec2 tt = u_tile_to_screen(x+1, y+1); - struct u_vec2 tl = u_tile_to_screen(x+2, y); - struct u_vec2 tb = u_tile_to_screen(x+2, y-2); + struct t_camera *c = &t_main_camera; + i32 zoom_factor = t_camera_zoom_factor(c); + u32 tile_w = t_camera_zoom(c, R_TILE_W); + u32 tile_h = t_camera_zoom(c, R_TILE_H); + i32 zfx, zfy; + + struct u_vec2 t = t_camera_zoom_vec2(c, u_tile_to_screen(x, y)); /* get mouse cursor and move by camera */ struct u_vec2 cursor_pos = u_world_to_camera(&t_main_camera, i_cursor_pos()); if (u_point_in_rect(cursor_pos.x, cursor_pos.y, t.x, t.y, - R_TILE_W, R_TILE_H)) { + tile_w, tile_h)) { hover_color_shift = 1; } - - /* do not draw if tile is not visible at all - * also include a few points outside the camera to avoid tiles - * popping in - */ - if (!t_camera_is_visible_screen(&t_main_camera, t.x, t.y) - && !t_camera_is_visible_screen(&t_main_camera, tt.x, tt.y) - && !t_camera_is_visible_screen(&t_main_camera, tb.x, tb.y) - && !t_camera_is_visible_screen(&t_main_camera, tl.x, tl.y)) { - return; - } + t = u_screen_to_camera(&t_main_camera, t); /* converted origin point in isometric space */ @@ -82,9 +75,13 @@ void r_draw_solid_isometric_tile(i32 x, i32 y, r_color color) { /* draw a tile texture from origin */ for (i = 0; i < R_TILE_W; i++) { for (j = 0; j < R_TILE_H; j++) { - final_color = r_asset_fallback_tile[i + j * R_TILE_W] & color; - final_color <<= hover_color_shift; - r_draw_pixel(&r_framebuffer, t.x + i, t.y + j, final_color); + for (zfx = 0; zfx < zoom_factor; zfx++) { + for (zfy = 0; zfy < zoom_factor; zfy++) { + final_color = r_asset_fallback_tile[i + j * R_TILE_W] & color; + final_color <<= hover_color_shift; + r_draw_pixel(&r_framebuffer, t.x + zfx + i * zoom_factor, t.y + zfy + j * zoom_factor, final_color); + } + } } } @@ -95,7 +92,6 @@ void r_draw_solid_isometric_tile(i32 x, i32 y, r_color color) { } void r_draw_tile(struct t_tile *t, i32 x, i32 y) { - switch (t->type) { case T_TILE_TYPE_NONE: break; diff --git a/src/r_render.c b/src/r_render.c index fcacfe8..bbf5e87 100644 --- a/src/r_render.c +++ b/src/r_render.c @@ -6,6 +6,7 @@ #include "u_debug.h" struct r_framebuffer r_framebuffer; +struct r_render_state r_render_state; void r_draw_pixel(struct r_framebuffer *fb, i32 x, i32 y, r_color color) { r_target_color *pixel = LRTS_NULL; @@ -29,7 +30,7 @@ void r_draw_pixel(struct r_framebuffer *fb, i32 x, i32 y, r_color color) { void r_render_debug(void) { struct lrts_state *state = lrts_state(); - u_debug_draw_text(0, 0, "FPS: %02d, Tick: %d", state->fps, state->tick_count); + u_debug_draw_text(0, 0, "FPS: %02d, Tick: %d, Frame: %d", state->fps, state->tick_count, state->frame_count); } void r_render_frame(void) { @@ -52,3 +53,46 @@ void r_render_frame(void) { state->frame_count++; state->fps = u_cap_fps(); } + +void r_render_update_visible_tiles(void) { + i32 x, y; + struct u_vec2 t, tt, tl, tb; + struct t_camera *c = &t_main_camera; + + r_render_state.start_tile.x = t_map.width; + r_render_state.start_tile.y = t_map.height; + + for (x = 0; x < t_map.width; x++) { + for (y = 0; y < t_map.height; y++) { + t = t_camera_zoom_vec2(c, u_tile_to_screen(x, y)); + tt = t_camera_zoom_vec2(c, u_tile_to_screen(x+1, y+1)); + tl = t_camera_zoom_vec2(c, u_tile_to_screen(x+2, y)); + tb = t_camera_zoom_vec2(c, u_tile_to_screen(x+2, y-2)); + + /* do not draw if tile is not visible at all + * also include a few points outside the camera to avoid tiles + * popping in + */ + if (t_camera_is_visible_screen(&t_main_camera, t.x, t.y) + || t_camera_is_visible_screen(&t_main_camera, tt.x, tt.y) + || t_camera_is_visible_screen(&t_main_camera, tb.x, tb.y) + || t_camera_is_visible_screen(&t_main_camera, tl.x, tl.y)) { + + if (r_render_state.end_tile.x < x) { + r_render_state.end_tile.x = x; + } + if (r_render_state.end_tile.y < y) { + r_render_state.end_tile.y = y; + } + + if (r_render_state.start_tile.x > x) { + r_render_state.start_tile.x = x; + } + + if (r_render_state.start_tile.y > y) { + r_render_state.start_tile.y = y; + } + } + } + } +} diff --git a/src/r_render.h b/src/r_render.h index c36390a..28fc9b0 100644 --- a/src/r_render.h +++ b/src/r_render.h @@ -13,15 +13,25 @@ struct r_framebuffer { r_target_color *pixels; }; +struct r_render_state { + struct u_vec2 start_tile; + struct u_vec2 end_tile; +}; + /* The global frame buffer. * This needs to be initialized by the * rendering platform */ extern struct r_framebuffer r_framebuffer; +extern struct r_render_state r_render_state; + /* draws a singel pixel directly to a frame buffer */ void r_draw_pixel(struct r_framebuffer *fb, i32 x, i32 y, r_color color); -void r_render_frame(); +void r_render_frame(void); + +/* updats visible tiles based on the current camera position */ +void r_render_update_visible_tiles(void); #endif diff --git a/src/t_camera.c b/src/t_camera.c index 94dac55..57f5fd5 100644 --- a/src/t_camera.c +++ b/src/t_camera.c @@ -11,6 +11,7 @@ struct t_camera t_camera_init(i32 viewport_x, i32 viewport_y) { c.viewport_y = viewport_y; c.zoom = 1; + r_render_update_visible_tiles(); return c; } @@ -21,6 +22,7 @@ void t_camera_scroll(struct t_camera *c, i32 by_x, i32 by_y) { /* TODO: calculate min/max viewport based on map in a better way */ c->x += by_x; c->y += by_y; + r_render_update_visible_tiles(); } lrts_bool t_camera_is_visible_screen(struct t_camera *c, i32 x, i32 y) { diff --git a/src/t_map.c b/src/t_map.c index 55608a1..018ac29 100644 --- a/src/t_map.c +++ b/src/t_map.c @@ -17,20 +17,14 @@ struct t_map t_map_init(void) { m.tiles[j * m.width + i].type = T_TILE_TYPE_GRASS; } } - + r_render_update_visible_tiles(); return m; } void t_map_draw(struct t_map *m) { i32 i, j; - struct u_vec2 start; - struct u_vec2 end; - - start.x = 0; - start.y = 0; - - end.x = t_map.width; - end.y = t_map.height; + struct u_vec2 start = r_render_state.start_tile; + struct u_vec2 end = r_render_state.end_tile; for (i = start.x; i < end.x; i++) { for (j = start.y; j < end.y; j++) { diff --git a/src/u_debug_font.h b/src/u_debug_font.h index 4fd8fb7..04d8e08 100644 --- a/src/u_debug_font.h +++ b/src/u_debug_font.h @@ -25,13 +25,13 @@ const u8 u_debug_font[] = { /* char 0x2a */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* char 0x2b */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x00, /* char 0x2c */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 0x20, 0x00, /* char 0x2d */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, /* char 0x2e */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, /* char 0x2f */ 0x00, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, /* char 0x30 */ -- 2.30.2