rendering: wip viewport culling for map rendering.
authorLukas Krickl <lukas@krickl.dev>
Sat, 7 Mar 2026 08:02:32 +0000 (09:02 +0100)
committerLukas Krickl <lukas@krickl.dev>
Sat, 7 Mar 2026 08:02:32 +0000 (09:02 +0100)
- Added camera zoom rendering for tiles.

src/r_assets.c
src/r_render.c
src/r_render.h
src/t_camera.c
src/t_map.c
src/u_debug_font.h

index 6c2f6aa24629dc8ab54fe72ef655402fa13ddf2f..0943a476662ad7525440d38299ec42ee3fac0ab7 100644 (file)
@@ -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;
index fcacfe8ec0d13a5e3f58bb98ccafa2d780fb80c0..bbf5e8797fa1129f0362fcbd7ae7963dfd3ba248 100644 (file)
@@ -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;
+                                       }
+                       }
+               }
+       }
+}
index c36390aa863932ef2944dd42a2d074787ed0bec4..28fc9b08adffdbe1fc31ee2f6fa8753bbd87c403 100644 (file)
@@ -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
index 94dac55f62bdb1a39bac7f3ba6bf7397d2f3d417..57f5fd5313d81db18f0cc5de8673816ebf49976c 100644 (file)
@@ -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) {
index 55608a1eb0d6da0a8d13814d29bb9c85b76b5ab6..018ac291d1ea82761388d9b757139015d65029cd 100644 (file)
@@ -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++) {
index 4fd8fb75a43c6622ccd5ebf14b8cfbe77c122026..04d8e08fa58c62065b623a2944e8111c6851b88b 100644 (file)
@@ -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 */