summaryrefslogtreecommitdiff
path: root/map.c
diff options
context:
space:
mode:
Diffstat (limited to 'map.c')
-rw-r--r--map.c174
1 files changed, 173 insertions, 1 deletions
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 <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, &lt[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];
+}
+