summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--3de.c1
-rw-r--r--config.h4
-rw-r--r--editor.c3
-rw-r--r--map.c174
-rw-r--r--map.h28
-rw-r--r--render.c35
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 <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];
+}
+
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;
}