diff options
Diffstat (limited to 'src/fov.c')
| -rw-r--r-- | src/fov.c | 95 |
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; +} |
