Skip to content

Commit 600089d

Browse files
committed
Add Pascal diffusion FOV
Fix minor issues with Triage FOV
1 parent 323f040 commit 600089d

7 files changed

Lines changed: 163 additions & 3 deletions

File tree

buildsys/autotools/sources.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ libtcod_fov_include_HEADERS = \
1010
../../include/libtcod-fov/error.hpp \
1111
../../include/libtcod-fov/fov.h \
1212
../../include/libtcod-fov/fov.hpp \
13+
../../include/libtcod-fov/fov_pascal.h \
1314
../../include/libtcod-fov/fov_triage.h \
1415
../../include/libtcod-fov/fov_types.h \
1516
../../include/libtcod-fov/libtcod_int.h \
@@ -26,6 +27,7 @@ libtcod_fov_la_SOURCES = \
2627
../../src/libtcod-fov/fov_c.c \
2728
../../src/libtcod-fov/fov_circular_raycasting.c \
2829
../../src/libtcod-fov/fov_diamond_raycasting.c \
30+
../../src/libtcod-fov/fov_pascal.c \
2931
../../src/libtcod-fov/fov_permissive2.c \
3032
../../src/libtcod-fov/fov_recursive_shadowcasting.c \
3133
../../src/libtcod-fov/fov_restrictive.c \

include/libtcod-fov/fov_pascal.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
#pragma once
3+
#ifndef TCODFOV_FOV_PASCAL_H_
4+
#define TCODFOV_FOV_PASCAL_H_
5+
6+
#include <stdbool.h>
7+
8+
#include "config.h"
9+
#include "error.h"
10+
#include "map_types.h"
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
16+
TCODFOV_PUBLIC TCODFOV_Error TCODFOV_pascal_diffusion_2d(
17+
const TCODFOV_Map2D* __restrict transparent, TCODFOV_Map2D* __restrict out, int pov_x, int pov_y);
18+
19+
#ifdef __cplusplus
20+
} // extern "C"
21+
#endif
22+
#endif // TCODFOV_FOV_PASCAL_H_

include/libtcod-fov/fov_triage.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@
99
#include "error.h"
1010
#include "map_types.h"
1111

12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
1216
TCODFOV_PUBLIC TCODFOV_Error
1317
TCODFOV_triage_2d(const TCODFOV_Map2D* __restrict transparent, TCODFOV_Map2D* __restrict out, int pov_x, int pov_y);
1418

19+
#ifdef __cplusplus
20+
} // extern "C"
21+
#endif
1522
#endif // TCODFOV_FOV_TRIAGE_H_

include/libtcod-fov/map_inline.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,12 @@ static inline void TCODFOV_map2d_set_bool(TCODFOV_Map2D* __restrict map, int x,
150150
static inline void TCODFOV_map2d_set_int(TCODFOV_Map2D* __restrict map, int x, int y, int value) {
151151
TCODFOV_map2d_set_bool(map, x, y, value != 0); // Fallback until maps can hold integers
152152
}
153+
154+
static inline double TCODFOV_map2d_get_d(const TCODFOV_Map2D* __restrict map, int x, int y) {
155+
return TCODFOV_map2d_get_bool(map, x, y) ? 1.0 : 0.0; // Fallback until maps can hold floats
156+
}
157+
158+
static inline void TCODFOV_map2d_set_d(TCODFOV_Map2D* __restrict map, int x, int y, double value) {
159+
TCODFOV_map2d_set_bool(map, x, y, value >= 0.5); // Fallback until maps can hold floats
160+
}
153161
#endif // TCODFOV_MAP_INLINE_H_

src/libtcod-fov/fov_pascal.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#include "fov_pascal.h"
2+
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
#include <string.h>
6+
7+
#include "map_inline.h"
8+
9+
static void pascal_scan_line(
10+
const TCODFOV_Map2D* __restrict transparent, // Input transparency
11+
TCODFOV_Map2D* __restrict out,
12+
int pov_x, // X position
13+
int scan_y, // Y position
14+
int iteration, // Distance from pov_y, always `abs(scan_y - pov_y)`
15+
const double* __restrict prev_row, // Previous row data
16+
double* __restrict next_row, // Active row to be written
17+
int x_begin,
18+
int x_end,
19+
int_fast8_t x_step // Step direction: -1 or 1
20+
) {
21+
for (int x = x_begin; x != x_end; x += x_step) {
22+
int_fast8_t casts = 0; // Number of tiles cast from
23+
double visiblity = 0.0;
24+
25+
// Cast diagonal
26+
++casts;
27+
visiblity += prev_row[x - x_step];
28+
29+
if (pov_x - iteration <= x && x <= pov_x + iteration) { // Cast from previous row
30+
++casts;
31+
visiblity += prev_row[x];
32+
}
33+
if (x <= pov_x - iteration || pov_x + iteration <= x) { // Cast from adjacent tile
34+
++casts;
35+
visiblity += next_row[x - x_step];
36+
}
37+
visiblity *= (1.0 / (double)casts);
38+
TCODFOV_map2d_set_d(out, x, scan_y, visiblity);
39+
if (visiblity) visiblity *= TCODFOV_map2d_get_d(transparent, x, scan_y);
40+
next_row[x] = visiblity;
41+
}
42+
}
43+
44+
/// @brief Compute the next row of visiblity, continue until out-of-bounds
45+
static void pascal_scan_next_row(
46+
const TCODFOV_Map2D* __restrict transparent, // Input transparency
47+
TCODFOV_Map2D* __restrict out,
48+
int pov_x, // X position
49+
int scan_y, // Y position
50+
int_fast8_t scan_dir, // Y step direction, -1 or 1
51+
int iteration, // Distance from pov_y, always `abs(scan_y - pov_y)`
52+
double* __restrict prev_row, // Previous row light-level
53+
double* __restrict next_row // This row light-level
54+
) {
55+
if (scan_y < 0 || scan_y >= TCODFOV_map2d_get_height(out)) return; // Finished, out-of-bounds
56+
57+
// Compute tile at pov_x, scan_y
58+
TCODFOV_map2d_set_d(out, pov_x, scan_y, prev_row[pov_x]);
59+
next_row[pov_x] = prev_row[pov_x] * TCODFOV_map2d_get_d(transparent, pov_x, scan_y);
60+
61+
// Compute tiles on sides of active row
62+
pascal_scan_line(transparent, out, pov_x, scan_y, iteration, prev_row, next_row, pov_x - 1, -1, -1);
63+
pascal_scan_line(
64+
transparent, out, pov_x, scan_y, iteration, prev_row, next_row, pov_x + 1, TCODFOV_map2d_get_width(out), 1);
65+
66+
// Swap next_row and prev_row and continue
67+
pascal_scan_next_row(transparent, out, pov_x, scan_y + scan_dir, scan_dir, iteration + 1, next_row, prev_row);
68+
}
69+
70+
static void pascal_scan_init(
71+
const TCODFOV_Map2D* __restrict transparent, // Input transparency
72+
TCODFOV_Map2D* __restrict out,
73+
int pov_x,
74+
int pov_y,
75+
double* __restrict row // Holds the light level this tile will cast onto others
76+
) {
77+
// Source always starts at 1.0
78+
TCODFOV_map2d_set_d(out, pov_x, pov_y, 1.0);
79+
// But the data stored in row is multiplied by the maps transparency
80+
row[pov_x] = TCODFOV_map2d_get_d(transparent, pov_x, pov_y);
81+
double visiblity = row[pov_x]; // Visiblity of the active cast
82+
for (int x = pov_x - 1; x >= 0; --x) {
83+
// Output visiblity is the light level cast from the previous tile.
84+
// But the value stored in row is after the transparency is applied.
85+
TCODFOV_map2d_set_d(out, x, pov_y, visiblity);
86+
if (visiblity != 0) visiblity *= TCODFOV_map2d_get_d(transparent, x, pov_y);
87+
row[x] = visiblity;
88+
}
89+
// Repeat for the other direction
90+
visiblity = row[pov_x];
91+
for (int x = pov_x + 1; x < TCODFOV_map2d_get_width(out); ++x) {
92+
TCODFOV_map2d_set_d(out, x, pov_y, visiblity);
93+
if (visiblity != 0) visiblity *= TCODFOV_map2d_get_d(transparent, x, pov_y);
94+
row[x] = visiblity;
95+
}
96+
}
97+
98+
TCODFOV_Error TCODFOV_pascal_diffusion_2d(
99+
const TCODFOV_Map2D* __restrict transparent, TCODFOV_Map2D* __restrict out, int pov_x, int pov_y) {
100+
// Holds the light-level to cast to adjacent rows
101+
double* __restrict row = malloc(TCODFOV_map2d_get_width(out) * 3 * sizeof(*row));
102+
103+
if (!row) {
104+
TCODFOV_set_errorv("Out of memory.");
105+
return TCODFOV_E_OUT_OF_MEMORY;
106+
}
107+
108+
double* __restrict row2 = row + TCODFOV_map2d_get_width(out);
109+
double* __restrict row3 = row + TCODFOV_map2d_get_width(out) * 2;
110+
111+
pascal_scan_init(transparent, out, pov_x, pov_y, row);
112+
113+
memcpy(row2, row, TCODFOV_map2d_get_width(out) * sizeof(*row));
114+
pascal_scan_next_row(transparent, out, pov_x, pov_y - 1, -1, 1, row2, row3);
115+
memcpy(row2, row, TCODFOV_map2d_get_width(out) * sizeof(*row));
116+
pascal_scan_next_row(transparent, out, pov_x, pov_y + 1, 1, 1, row2, row3);
117+
return TCODFOV_E_OK;
118+
}

src/libtcod-fov/fov_triage.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ TCODFOV_Error TCODFOV_triage_2d(
105105
// X = transparent: caches input transparency if applicable
106106
// Y = always visible: all tiles to this tile are always visible
107107
// Z = maybe visible: at least one tile to this tile is maybe visible
108-
int8_t* __restrict row = malloc(TCODFOV_map2d_get_width(out) * 3);
108+
int8_t* __restrict row = malloc(TCODFOV_map2d_get_width(out) * 3 * sizeof(*row));
109109
if (!row) {
110110
TCODFOV_set_errorv("Out of memory.");
111111
return TCODFOV_E_OUT_OF_MEMORY;
@@ -115,8 +115,9 @@ TCODFOV_Error TCODFOV_triage_2d(
115115

116116
triage_scan_init(transparent, out, pov_x, pov_y, row);
117117

118-
memcpy(row2, row, TCODFOV_map2d_get_width(out));
118+
memcpy(row2, row, TCODFOV_map2d_get_width(out) * sizeof(*row));
119119
triage_scan_next_row(transparent, out, pov_x, pov_y - 1, -1, 1, row2, row3);
120-
triage_scan_next_row(transparent, out, pov_x, pov_y + 1, 1, 1, row, row2);
120+
memcpy(row2, row, TCODFOV_map2d_get_width(out) * sizeof(*row));
121+
triage_scan_next_row(transparent, out, pov_x, pov_y + 1, 1, 1, row2, row3);
121122
return TCODFOV_E_OK;
122123
}

src/sources.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ target_sources(${PROJECT_NAME} PRIVATE
66
libtcod-fov/fov_c.c
77
libtcod-fov/fov_circular_raycasting.c
88
libtcod-fov/fov_diamond_raycasting.c
9+
libtcod-fov/fov_pascal.c
910
libtcod-fov/fov_permissive2.c
1011
libtcod-fov/fov_recursive_shadowcasting.c
1112
libtcod-fov/fov_restrictive.c
@@ -28,6 +29,7 @@ install(FILES
2829
../include/libtcod-fov/error.hpp
2930
../include/libtcod-fov/fov.h
3031
../include/libtcod-fov/fov.hpp
32+
../include/libtcod-fov/fov_pascal.h
3133
../include/libtcod-fov/fov_triage.h
3234
../include/libtcod-fov/fov_types.h
3335
../include/libtcod-fov/libtcod_int.h

0 commit comments

Comments
 (0)