diff options
Diffstat (limited to 'map.c')
-rw-r--r-- | map.c | 174 |
1 files changed, 173 insertions, 1 deletions
@@ -1,7 +1,12 @@ #include "map.h" +#include "maths.h" +#include <stdlib.h> 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]; +} + |