From b0a5f59fe3bea9aab8f52016a90b6cbbcaea4571 Mon Sep 17 00:00:00 2001 From: quou Date: Sun, 4 Aug 2024 15:34:05 +1000 Subject: WIP lightmap baking --- 3de.c | 1 + config.h | 4 +- editor.c | 3 ++ map.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- map.h | 28 ++++++++++ render.c | 35 +++++++++++-- 6 files changed, 239 insertions(+), 6 deletions(-) diff --git a/3de.c b/3de.c index 1c10e03..dc46522 100644 --- a/3de.c +++ b/3de.c @@ -80,6 +80,7 @@ void init_map(Map* m) { for (i = 0; i < 0x100; i++) { t[i] = map_data[i]; } + bake_map(m); } void draw_map(Renderer* r, const Player* p, const Map* m) { diff --git a/config.h b/config.h index 87a4824..8a95ce8 100644 --- a/config.h +++ b/config.h @@ -5,7 +5,8 @@ #define app_memory_size (1024 * 1024 * 32) #define asset_preload_memory_size (1024 * 1024 * 8) #define gui_memory_size (1024 * 8) -#define map_memory_size (1024 * 8) +/* 8 megs for the map is not good. todo compress */ +#define map_memory_size (1024 * 1024 * 8) #define max_vp_w 2000 #define max_vp_h 2000 @@ -15,5 +16,6 @@ #define max_map_w 32 #define max_map_h 32 +#define map_light_tile_size 16 #endif diff --git a/editor.c b/editor.c index 645f7f7..86f7527 100644 --- a/editor.c +++ b/editor.c @@ -66,6 +66,9 @@ void edit_map(Editor* e, GUI* g, Map* m) { mcs[1] = m->h * tile_display_size; gui_btn(g, gui_cut_left(&t, gui_text_width("Load", 4) + 4), "Save"); gui_btn(g, gui_cut_left(&t, gui_text_width("Save", 4) + 4), "Load"); + if (gui_btn(g, gui_cut_left(&t, gui_text_width("Bake Lights", 11) + 4), "Bake Lights")) { + bake_map(m); + } g->uptr = m; gui_scrollable(g, b, mcs, &map_ss, draw_map_scrollable); } diff --git a/map.c b/map.c index 5dbe236..d1dcbb8 100644 --- a/map.c +++ b/map.c @@ -1,7 +1,12 @@ #include "map.h" +#include "maths.h" +#include int map_size(int w, int h) { - return sizeof(Map) + w * h * sizeof(Map_Tile); + return + sizeof(Map) + + w * h * sizeof(Map_Tile) + + w * h * sizeof(Map_Light_Tile); } Map_Tile* map_tiles(Map* m) { @@ -11,3 +16,170 @@ Map_Tile* map_tiles(Map* m) { const Map_Tile* map_tilesc(const Map* m) { return (Map_Tile*)&m[1]; } + +Map_Light_Tile* map_light_tiles(Map* m) { + return (Map_Light_Tile*)&map_tiles(m)[m->w * m->h]; +} + +const Map_Light_Tile* map_light_tilesc(const Map* m) { + return (Map_Light_Tile*)&map_tilesc(m)[m->w * m->h]; +} + +typedef struct { + Line a, b; +} Ray; + +void init_ray(Ray* r, const int* f, const int* t) { + int fa[2], ta[2]; + int fb[2], tb[2]; + fa[0] = f[0]; + fa[1] = f[1]; + ta[0] = t[0]; + ta[1] = t[1]; + fb[0] = f[0]; + fb[1] = f[2]; + tb[0] = t[0]; + tb[1] = t[2]; + init_line(&r->a, fa, ta); + init_line(&r->b, fb, tb); +} + +void step_ray(Ray* r) { + step_line(&r->a); + while (r->a.x != r->b.x) + step_line(&r->b); +} + +void get_ray(const Ray* r, int* d) { + d[0] = r->a.x; + d[1] = r->a.y; + d[2] = r->b.y; +} + +int trace_ray( + Map* m, + const int* f, + const int* t +) { + Ray r; + int pos[3], w[3]; + init_ray(&r, f, t); + while (1) { + int mp[2], coord; + get_ray(&r, pos); + mp[0] = pos[0] >> fbits; + mp[1] = pos[1] >> fbits; + if (mp[0] < 0) goto end; + if (mp[1] < 0) goto end; + if (mp[0] >= m->w) goto end; + if (mp[1] >= m->h) goto end; + if (pos[2] < 0) { /* hit the floor */ + goto end; + } + if (pos[2] >= f1) { /* hit the ceiling */ + goto end; + } + coord = mp[0] + mp[1] * m->w; + if (map_tilesc(m)[coord]) { + goto end; + } + step_ray(&r); + } +end: + return vec_dist(w, pos, t, 3) < 100; +} + +void init_tile(Map* m, int tx, int ty, Map_Light_Tile* t) { + int i, x, y; + Map_Fragment full = { + { 0xff, 0xff, 0xff, 0xff }, + { 0xff, 0xff, 0xff, 0xff }, { + { 0xff, 0xff, 0xff, 0xff }, + { 0xff, 0xff, 0xff, 0xff }, + { 0xff, 0xff, 0xff, 0xff }, + { 0xff, 0xff, 0xff, 0xff }, + }}; + (void)m; + (void)tx; + (void)ty; + for (i = y = 0; y < map_light_tile_size; y++) { + for (x = 0; x < map_light_tile_size; x++, i++) { + t->fragments[i] = full; + } + } +} + +void bake_tile( + Map* m, + int tx, + int ty, + Map_Light_Tile* t, + const Map_Light* light +) { + int i, x, y, fr[3], w[3]; + Map_Tile wall = map_tilesc(m)[tx + ty * m->w]; + tx <<= fbits; + ty <<= fbits; + fr[0] = light->x; + fr[1] = light->y; + fr[2] = f1/2; + for (i = y = 0; y < map_light_tile_size; y++) { + for (x = 0; x < map_light_tile_size; x++, i++) { + int to[3]; + int atten; + Colour c; + to[0] = tx + x * 32; + to[1] = ty + y * 32; + to[2] = f1; + atten = vec_dist(w, fr, to, 3); + atten /= 5; + atten = mini( + (f1 << fbits) / maxi(1, (atten * atten) >> fbits), + f1 + ) - 1; + c = col_scl( + light->c, + (unsigned char)(atten / 2) + ); + if (trace_ray(m, fr, to)) + t->fragments[i].u = c; + to[2] = 0; + if (trace_ray(m, fr, to)) + t->fragments[i].d = c; + } + } +} + +void bake_light(Map* m, const Map_Light* light) { + int x, y, i; + Map_Light_Tile* lt = map_light_tiles(m); + for (i = y = 0; y < m->h; y++) { + for (x = 0; x < m->w; x++, i++) { + bake_tile(m, x, y, <[i], light); + } + } +} + +void bake_map(Map* m) { + Map_Light l = { f1 * 3, f1 * 3, f1, { 0xff, 0xff, 0xff, 0xff } }; + bake_light(m, &l); +} + +const Map_Fragment* sample_map_light( + const Map* m, + int tx, + int ty, + int u, + int v +) { + int coord; + const Map_Light_Tile* t = + &map_light_tilesc(m)[tx + ty * m->w]; + int x = (u * map_light_tile_size) >> fbits; + int y = (v * map_light_tile_size) >> fbits; + x &= map_light_tile_size - 1; + y &= map_light_tile_size - 1; + coord = x + y * map_light_tile_size; + return &t->fragments[coord]; +} + diff --git a/map.h b/map.h index 9e2a413..566b367 100644 --- a/map.h +++ b/map.h @@ -1,14 +1,42 @@ #ifndef map_h #define map_h +#include "config.h" +#include "render.h" + typedef struct Map { int w, h; } Map; +typedef struct { + Colour u, d; + Colour side[4]; /* left, right, north, south */ +} Map_Fragment; + +typedef struct { + int x, y; + int brightness; + Colour c; +} Map_Light; + +typedef struct { + Map_Fragment fragments[map_light_tile_size * map_light_tile_size]; +} Map_Light_Tile; + typedef unsigned Map_Tile; int map_size(int w, int h); Map_Tile* map_tiles(Map* m); const Map_Tile* map_tilesc(const Map* m); +Map_Light_Tile* map_light_tiles(Map* m); +const Map_Light_Tile* map_light_tilesc(const Map* m); +void bake_map(Map* m); +const Map_Fragment* sample_map_light( + const Map* m, + int tx, + int ty, + int u, + int v +); #endif diff --git a/render.c b/render.c index 3e5758b..f50dd04 100644 --- a/render.c +++ b/render.c @@ -785,12 +785,29 @@ void ren_map( int t = ((2 * x) << (fbits * 2)) / w - f1; int coordc = x + y * r->vp[0]; int coordf = x + ((hhi - y) + hhi) * r->vp[0]; - int ifloor[2]; + int ifloor[2], mc[2]; + const Map_Fragment* light; + Colour c; t = (t + f1) / 2; ifloor[0] = floor[0] + ((t * (floor[2] - floor[0])) >> fbits); ifloor[1] = floor[1] + ((t * (floor[3] - floor[1])) >> fbits); - r->t[coordc] = sample_tex(ceiling, ifloor[0], ifloor[1]); - r->t[coordf] = sample_tex(floort, ifloor[0], ifloor[1]); + mc[0] = ifloor[0] >> fbits; + mc[1] = ifloor[1] >> fbits; + if (mc[0] < 0) continue; + if (mc[1] < 0) continue; + if (mc[0] >= map->w) continue; + if (mc[1] >= map->h) continue; + light = sample_map_light( + map, + mc[0], + mc[1], + ifloor[0], + ifloor[1] + ); + c = sample_tex(ceiling, ifloor[0], ifloor[1]); + r->t[coordc] = col_mul(c, light->u); + c = sample_tex(floort, ifloor[0], ifloor[1]); + r->t[coordf] = col_mul(c, light->d); } } for (x = r->clip[0]; x < r->clip[2]; x++) { @@ -819,17 +836,19 @@ void ren_map( dside[1] = (((mp[1] << fbits) + f1 - pos[1]) * delta[1]) >> fbits; } while (1) { - int dist, u; + int dist, u, side; if (dside[0] < dside[1]) { dside[0] += delta[0]; mp[0] += step[0]; dist = dside[0] - delta[0]; u = pos[1] + ((dist * d[1]) >> fbits); + side = d[0] < 0; } else { dside[1] += delta[1]; mp[1] += step[1]; dist = dside[1] - delta[1]; u = pos[0] + ((dist * d[0]) >> fbits); + side = 2 + (d[1] < 0); } if (mp[0] < 0) break; if (mp[1] < 0) break; @@ -845,6 +864,14 @@ void ren_map( int coord = x + y * r->vp[0]; int v = ((y - sy) << fbits) / (ey - sy); Colour c = sample_tex(texture, u, v); + const Map_Fragment* light = sample_map_light( + map, + mp[0], + mp[1], + u, + v + ); + c = col_mul(c, light->side[side]); r->d[coord] = dist; r->t[coord] = c; } -- cgit v1.2.3-54-g00ecf