summaryrefslogtreecommitdiff
path: root/src/fov.c
diff options
context:
space:
mode:
authoronelin <oscar@nelin.dk>2025-10-31 23:55:42 +0000
committeronelin <oscar@nelin.dk>2025-11-02 22:07:17 +0000
commitd38deeef3af2316a666f8fc0173940bd769b748e (patch)
tree6e30d4a9eea18daa5705c894f28cd99ff047e8f9 /src/fov.c
parent6c077751982ea2c7bd2d9262b01b9f8602f80dc8 (diff)
Flatten project structure
This will make it easier to break up the code into smaller chunks again later. One would think doing this seems fun to me at this point.
Diffstat (limited to 'src/fov.c')
-rw-r--r--src/fov.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/fov.c b/src/fov.c
new file mode 100644
index 0000000..d7c6746
--- /dev/null
+++ b/src/fov.c
@@ -0,0 +1,95 @@
+#include <daw/utils/fov.h>
+#include <daw/utils.h>
+#include <math.h>
+#include <stdint.h>
+
+void fov_shadowcast_rec(const void* map, const ivec2 mapsize,
+ bool (*visblocking)(const void*), i32* lightmap,
+ const i32 range, ivec2 src, const i32 row, f32 start,
+ const f32 end, const i8 xx, const i8 xy, const i8 yx,
+ const i8 yy) {
+
+ if (start < end) return;
+
+ const i32 range_2 = range * range;
+ f32 new_start = start;
+
+ for (i32 i = row; i <= range; i++) {
+ i32 dx = (-1 * i) - 1;
+ i32 dy = -1 * i;
+
+ bool blocked = false;
+
+ while (dx <= 0) {
+ dx += 1;
+
+ const i32 mapx = src[0] + dx * xx + dy * xy;
+ const i32 mapy = src[1] + dx * yx + dy * yy;
+
+ const f32 slope_l = (((f32)dx) - 0.5f) / (((f32)dy) + 0.5f);
+ const f32 slope_r = (((f32)dx) + 0.5f) / (((f32)dy) - 0.5f);
+
+ if (start < slope_r) continue;
+ if (end > slope_l) break;
+
+ if (dx * dx + dy * dy < range_2) {
+ /* set as visible */
+ if (mapx >= 0 && mapx < (long)mapsize[0] && mapy >= 0 &&
+ mapy < (long)mapsize[1]) {
+ // TODO: Calculate proper dist from source
+ i32 x_2 = (src[0] - mapx) * (src[0] - mapx);
+ i32 y_2 = (src[1] - mapy) * (src[1] - mapy);
+ lightmap[mapy * mapsize[0] + mapx] =
+ MAX(lightmap[mapy * mapsize[0] + mapx],
+ (i32)(range - sqrt((f64)(x_2 + y_2))));
+ }
+ }
+
+ /* sizeof(i32) is the size of enums */
+ /* -- unless the compiler doesn't follow standard behaviour */
+ const bool is_blocked = visblocking(
+ (void*)((u64)map
+ + sizeof(i32) /* ~ enum size */
+ * (usize)(mapsize[0] * mapy + mapx) /* index */
+ ));
+
+ if (blocked) {
+ if (!is_blocked) {
+ new_start = slope_r;
+ } else {
+ blocked = false;
+ start = new_start;
+ }
+ } else if (!is_blocked && i < range) {
+ blocked = true;
+ fov_shadowcast_rec(map, mapsize, visblocking, lightmap, range, src,
+ i + 1, start, slope_l, xx, xy, yx, yy);
+ new_start = slope_r;
+ }
+ }
+
+ if (blocked) break;
+ }
+}
+
+/* http://www.roguebasin.com/index.php?title=FOV_using_recursive_shadowcasting
+ */
+void fov_shadowcast(const void* map, const ivec2 mapsize,
+ bool (*visblocking)(const void*), i32* lightmap,
+ const i32 range, const ivec2 src) {
+
+ const i8 m[4][8] = {
+ {1, 0, 0, -1, -1, 0, 0, 1},
+ {0, 1, -1, 0, 0, -1, 1, 0},
+ {0, 1, 1, 0, 0, -1, -1, 0},
+ {1, 0, 0, 1, -1, 0, 0, -1},
+ };
+
+ for (i32 oct = 0; oct < 8; oct++) {
+ fov_shadowcast_rec(map, mapsize, visblocking, lightmap, range, src, 1, 1.0,
+ 0.0, m[0][oct], m[1][oct], m[2][oct], m[3][oct]);
+ }
+
+ /* The center is the most lit square */
+ lightmap[src[1] * mapsize[0] + src[0]] = range;
+}