Merge pull request #263 from kichikuou/lightmap

Dungeons & Dolls: Enable light mapping
This commit is contained in:
Nunuhara Cabbage
2025-08-15 13:49:56 -07:00
committed by GitHub
4 changed files with 326 additions and 14 deletions
+1
View File
@@ -144,6 +144,7 @@ static inline bool dgn_is_in_map(struct dgn *dgn, uint32_t x, uint32_t y, uint32
// Returns a list of cells visible from (x, y, z), sorted by distance from (x, y, z).
struct dgn_cell **dgn_get_visible_cells(struct dgn *dgn, int x, int y, int z, int *nr_cells_out);
void dgn_calc_lightmap(struct dgn *dgn);
struct dgn *dgn_generate_drawdungeon2(int level);
void dgn_paint_step(struct dgn *dgn, int x, int y);
+284
View File
@@ -281,6 +281,289 @@ struct dgn_cell **dgn_get_visible_cells(struct dgn *dgn, int x, int y, int z, in
return dgn_get_visible_cells_nopvs(dgn, x, y, z, nr_cells_out);
}
#define LM_N (1 << 0)
#define LM_S (1 << 1)
#define LM_W (1 << 2)
#define LM_E (1 << 3)
#define LM_NW (1 << 4)
#define LM_NE (1 << 5)
#define LM_SW (1 << 6)
#define LM_SE (1 << 7)
static int lightmap_texture_index(uint8_t flags)
{
if (flags & LM_N || flags & LM_W) flags &= ~LM_NW;
if (flags & LM_N || flags & LM_E) flags &= ~LM_NE;
if (flags & LM_S || flags & LM_W) flags &= ~LM_SW;
if (flags & LM_S || flags & LM_E) flags &= ~LM_SE;
switch (flags) {
case LM_N | LM_W | LM_E: return 0;
case LM_W | LM_E: return 1;
case LM_S | LM_W | LM_E: return 2;
case LM_N | LM_S | LM_W: return 3;
case LM_N | LM_S: return 4;
case LM_N | LM_S | LM_E: return 5;
case LM_N | LM_W: return 6;
case LM_N: return 7;
case LM_N | LM_E: return 8;
case LM_W: return 9;
case LM_E: return 10;
case LM_S | LM_W: return 11;
case LM_S: return 12;
case LM_S | LM_E: return 13;
case LM_N | LM_S | LM_W | LM_E: return 14;
case LM_W | LM_NE | LM_SE: return 15;
case LM_N | LM_SW | LM_SE: return 16;
case LM_E | LM_NW | LM_SW: return 17;
case LM_S | LM_NW | LM_NE: return 18;
case LM_NW | LM_NE | LM_SW | LM_SE: return 19;
case LM_W | LM_NE: return 20;
case LM_N | LM_SE: return 21;
case LM_E | LM_SW: return 22;
case LM_S | LM_NW: return 23;
case LM_NE: return 24;
case LM_W | LM_SE: return 25;
case LM_N | LM_SW: return 26;
case LM_E | LM_NW: return 27;
case LM_S | LM_NE: return 28;
case LM_SE: return 29;
case LM_NE | LM_SE: return 30;
case LM_SW | LM_SE: return 31;
case LM_NW | LM_SW: return 32;
case LM_NW | LM_NE: return 33;
case LM_SW: return 34;
case LM_NW: return 35;
case LM_N | LM_W | LM_SE: return 36;
case LM_N | LM_E | LM_SW: return 37;
case LM_S | LM_E | LM_NW: return 38;
case LM_S | LM_W | LM_NE: return 39;
case LM_NW | LM_NE | LM_SW: return 40;
case LM_NW | LM_NE | LM_SE: return 41;
case LM_NE | LM_SW | LM_SE: return 42;
case LM_NW | LM_SW | LM_SE: return 43;
case LM_NE | LM_SW: return 44;
case LM_NW | LM_SE: return 45;
default: return -1;
};
}
static int calc_floor_lightmap(struct dgn *dgn, struct dgn_cell *cell,
struct dgn_cell *north_cell, struct dgn_cell *south_cell,
struct dgn_cell *west_cell, struct dgn_cell *east_cell)
{
if (cell->floor == -1)
return -1;
uint8_t flags = 0;
if (cell->north_wall != -1 || cell->north_door != -1 ||
(north_cell && north_cell->stairs_texture != -1 && north_cell->stairs_orientation == 0))
flags |= LM_N;
if (cell->south_wall != -1 || cell->south_door != -1 ||
(south_cell && south_cell->stairs_texture != -1 && south_cell->stairs_orientation == 2))
flags |= LM_S;
if (cell->west_wall != -1 || cell->west_door != -1 ||
(west_cell && west_cell->stairs_texture != -1 && west_cell->stairs_orientation == 1))
flags |= LM_W;
if (cell->east_wall != -1 || cell->east_door != -1 ||
(east_cell && east_cell->stairs_texture != -1 && east_cell->stairs_orientation == 3))
flags |= LM_E;
if ((north_cell && (north_cell->west_wall != -1 || north_cell->west_door != -1)) ||
(west_cell && (west_cell->north_wall != -1 || west_cell->north_door != -1)))
flags |= LM_NW;
if ((north_cell && (north_cell->east_wall != -1 || north_cell->east_door != -1)) ||
(east_cell && (east_cell->north_wall != -1 || east_cell->north_door != -1)))
flags |= LM_NE;
if ((south_cell && (south_cell->west_wall != -1 || south_cell->west_door != -1)) ||
(west_cell && (west_cell->south_wall != -1 || west_cell->south_door != -1)))
flags |= LM_SW;
if ((south_cell && (south_cell->east_wall != -1 || south_cell->east_door != -1)) ||
(east_cell && (east_cell->south_wall != -1 || east_cell->south_door != -1)))
flags |= LM_SE;
return lightmap_texture_index(flags);
}
static int calc_ceiling_lightmap(struct dgn *dgn, struct dgn_cell *cell,
struct dgn_cell *north_cell, struct dgn_cell *south_cell,
struct dgn_cell *west_cell, struct dgn_cell *east_cell)
{
if (cell->ceiling == -1)
return -1;
uint8_t flags = 0;
if (cell->north_wall != -1 || cell->north_door != -1)
flags |= LM_N;
if (cell->south_wall != -1 || cell->south_door != -1)
flags |= LM_S;
if (cell->west_wall != -1 || cell->west_door != -1)
flags |= LM_E;
if (cell->east_wall != -1 || cell->east_door != -1)
flags |= LM_W;
if ((north_cell && (north_cell->east_wall != -1 || north_cell->east_door != -1)) ||
(east_cell && (east_cell->north_wall != -1 || east_cell->north_door != -1)))
flags |= LM_NW;
if ((north_cell && (north_cell->west_wall != -1 || north_cell->west_door != -1)) ||
(west_cell && (west_cell->north_wall != -1 || west_cell->north_door != -1)))
flags |= LM_NE;
if ((south_cell && (south_cell->east_wall != -1 || south_cell->east_door != -1)) ||
(east_cell && (east_cell->south_wall != -1 || east_cell->south_door != -1)))
flags |= LM_SW;
if ((south_cell && (south_cell->west_wall != -1 || south_cell->west_door != -1)) ||
(west_cell && (west_cell->south_wall != -1 || west_cell->south_door != -1)))
flags |= LM_SE;
return lightmap_texture_index(flags);
}
static int calc_north_lightmap(struct dgn *dgn, struct dgn_cell *cell,
struct dgn_cell *up_cell, struct dgn_cell *down_cell,
struct dgn_cell *west_cell, struct dgn_cell *east_cell)
{
if (cell->north_wall == -1)
return -1;
uint8_t flags = 0;
if (cell->ceiling != -1)
flags |= LM_N;
if (cell->floor != -1)
flags |= LM_S;
if (cell->west_wall != -1 || cell->west_door != -1)
flags |= LM_W;
if (cell->east_wall != -1 || cell->east_door != -1)
flags |= LM_E;
if ((up_cell && (up_cell->west_wall != -1 || up_cell->west_door != -1)) ||
(west_cell && (west_cell->ceiling != -1)))
flags |= LM_NW;
if ((up_cell && (up_cell->east_wall != -1 || up_cell->east_door != -1)) ||
(east_cell && (east_cell->ceiling != -1)))
flags |= LM_NE;
if ((down_cell && (down_cell->west_wall != -1 || down_cell->west_door != -1)) ||
(west_cell && (west_cell->floor != -1)))
flags |= LM_SW;
if ((down_cell && (down_cell->east_wall != -1 || down_cell->east_door != -1)) ||
(east_cell && (east_cell->floor != -1)))
flags |= LM_SE;
return lightmap_texture_index(flags);
}
static int calc_south_lightmap(struct dgn *dgn, struct dgn_cell *cell,
struct dgn_cell *up_cell, struct dgn_cell *down_cell,
struct dgn_cell *west_cell, struct dgn_cell *east_cell)
{
if (cell->south_wall == -1)
return -1;
uint8_t flags = 0;
if (cell->ceiling != -1)
flags |= LM_N;
if (cell->floor != -1)
flags |= LM_S;
if (cell->east_wall != -1 || cell->east_door != -1)
flags |= LM_W;
if (cell->west_wall != -1 || cell->west_door != -1)
flags |= LM_E;
if ((up_cell && (up_cell->east_wall != -1 || up_cell->east_door != -1)) ||
(east_cell && (east_cell->ceiling != -1)))
flags |= LM_NW;
if ((up_cell && (up_cell->west_wall != -1 || up_cell->west_door != -1)) ||
(west_cell && (west_cell->ceiling != -1)))
flags |= LM_NE;
if ((down_cell && (down_cell->east_wall != -1 || down_cell->east_door != -1)) ||
(east_cell && (east_cell->floor != -1)))
flags |= LM_SW;
if ((down_cell && (down_cell->west_wall != -1 || down_cell->west_door != -1)) ||
(west_cell && (west_cell->floor != -1)))
flags |= LM_SE;
return lightmap_texture_index(flags);
}
static int calc_west_lightmap(struct dgn *dgn, struct dgn_cell *cell,
struct dgn_cell *up_cell, struct dgn_cell *down_cell,
struct dgn_cell *north_cell, struct dgn_cell *south_cell)
{
if (cell->west_wall == -1)
return -1;
uint8_t flags = 0;
if (cell->ceiling != -1)
flags |= LM_N;
if (cell->floor != -1)
flags |= LM_S;
if (cell->south_wall != -1 || cell->south_door != -1)
flags |= LM_W;
if (cell->north_wall != -1 || cell->north_door != -1)
flags |= LM_E;
if ((up_cell && (up_cell->south_wall != -1 || up_cell->south_door != -1)) ||
(south_cell && (south_cell->ceiling != -1)))
flags |= LM_NW;
if ((up_cell && (up_cell->north_wall != -1 || up_cell->north_door != -1)) ||
(north_cell && (north_cell->ceiling != -1)))
flags |= LM_NE;
if ((down_cell && (down_cell->south_wall != -1 || down_cell->south_door != -1)) ||
(south_cell && (south_cell->floor != -1)))
flags |= LM_SW;
if ((down_cell && (down_cell->north_wall != -1 || down_cell->north_door != -1)) ||
(north_cell && (north_cell->floor != -1)))
flags |= LM_SE;
return lightmap_texture_index(flags);
}
static int calc_east_lightmap(struct dgn *dgn, struct dgn_cell *cell,
struct dgn_cell *up_cell, struct dgn_cell *down_cell,
struct dgn_cell *north_cell, struct dgn_cell *south_cell)
{
if (cell->east_wall == -1)
return -1;
uint8_t flags = 0;
if (cell->ceiling != -1)
flags |= LM_N;
if (cell->floor != -1)
flags |= LM_S;
if (cell->north_wall != -1 || cell->north_door != -1)
flags |= LM_W;
if (cell->south_wall != -1 || cell->south_door != -1)
flags |= LM_E;
if ((up_cell && (up_cell->north_wall != -1 || up_cell->north_door != -1)) ||
(north_cell && (north_cell->ceiling != -1)))
flags |= LM_NW;
if ((up_cell && (up_cell->south_wall != -1 || up_cell->south_door != -1)) ||
(south_cell && (south_cell->ceiling != -1)))
flags |= LM_NE;
if ((down_cell && (down_cell->north_wall != -1 || down_cell->north_door != -1)) ||
(north_cell && (north_cell->floor != -1)))
flags |= LM_SW;
if ((down_cell && (down_cell->south_wall != -1 || down_cell->south_door != -1)) ||
(south_cell && (south_cell->floor != -1)))
flags |= LM_SE;
return lightmap_texture_index(flags);
}
void dgn_calc_lightmap(struct dgn *dgn)
{
int nr_cells = dgn_nr_cells(dgn);
for (int i = 0; i < nr_cells; i++) {
struct dgn_cell *cell = &dgn->cells[i];
struct dgn_cell *north = cell->z + 1 < dgn->size_z
? dgn_cell_at(dgn, cell->x, cell->y, cell->z + 1) : NULL;
struct dgn_cell *south = cell->z > 0
? dgn_cell_at(dgn, cell->x, cell->y, cell->z - 1) : NULL;
struct dgn_cell *west = cell->x > 0
? dgn_cell_at(dgn, cell->x - 1, cell->y, cell->z) : NULL;
struct dgn_cell *east = cell->x + 1 < dgn->size_x
? dgn_cell_at(dgn, cell->x + 1, cell->y, cell->z) : NULL;
struct dgn_cell *up = cell->y + 1 < dgn->size_y
? dgn_cell_at(dgn, cell->x, cell->y + 1, cell->z) : NULL;
struct dgn_cell *down = cell->y > 0
? dgn_cell_at(dgn, cell->x, cell->y - 1, cell->z) : NULL;
cell->lightmap_floor = calc_floor_lightmap(dgn, cell, north, south, west, east);
cell->lightmap_ceiling = calc_ceiling_lightmap(dgn, cell, north, south, west, east);
cell->lightmap_north = calc_north_lightmap(dgn, cell, up, down, west, east);
cell->lightmap_south = calc_south_lightmap(dgn, cell, up, down, west, east);
cell->lightmap_west = calc_west_lightmap(dgn, cell, up, down, north, south);
cell->lightmap_east = calc_east_lightmap(dgn, cell, up, down, north, south);
}
}
#define DD2_MAP_WIDTH 18
#define DD2_MAP_HEIGHT 18
typedef char dd2_map[DD2_MAP_WIDTH+1][DD2_MAP_HEIGHT+1]; // +1 to prevent OOB access
@@ -604,6 +887,7 @@ struct dgn *dgn_generate_drawdungeon2(int level)
cell->north_wall = wall_texture(map[x - 1][z + 1], map[x + 1][z + 1], x, z, 1);
}
}
dgn_calc_lightmap(dgn);
return dgn;
}
+40 -13
View File
@@ -27,6 +27,8 @@
#include "dungeon/dtx.h"
#include "dungeon/mtrand43.h"
#define DTX_VERSION_DTL 0xffffffff
struct dtx *dtx_parse(uint8_t *data, size_t size)
{
struct buffer r;
@@ -76,18 +78,42 @@ void dtx_free(struct dtx *dtx)
struct cg *dtx_create_cg(struct dtx *dtx, enum dtx_texture_type type, int index)
{
int row;
switch (type) {
case DTX_WALL: row = 0; break;
case DTX_FLOOR: row = 1; break;
case DTX_CEILING: row = 2; break;
case DTX_STAIRS: row = 3; break;
case DTX_DOOR: row = 4; break;
case DTX_SKYBOX: row = 5; break;
case DTX_LIGHTMAP: row = dtx->version == 0 ? 6 : 7; break;
default:
return NULL;
switch (dtx->version) {
case 0:
switch (type) {
case DTX_WALL: row = 0; break;
case DTX_FLOOR: row = 1; break;
case DTX_CEILING: row = 2; break;
case DTX_STAIRS: row = 3; break;
case DTX_DOOR: row = 4; break;
case DTX_SKYBOX: row = 5; break;
case DTX_LIGHTMAP: row = 6; break;
default: return NULL;
}
break;
case 1:
switch (type) {
case DTX_WALL: row = 0; break;
case DTX_FLOOR: row = 1; break;
case DTX_CEILING: row = 2; break;
case DTX_STAIRS: row = 3; break;
case DTX_DOOR: row = 4; break;
case DTX_SKYBOX: row = 5; break;
case DTX_LIGHTMAP: row = 7; break;
default: return NULL;
}
break;
case DTX_VERSION_DTL:
switch (type) {
case DTX_WALL: row = 0; break;
case DTX_FLOOR: row = 1; break;
case DTX_CEILING: row = 2; break;
case DTX_LIGHTMAP: row = 3; break;
default: return NULL;
}
break;
}
if (index < 0 || index >= dtx->nr_columns)
if (row >= dtx->nr_rows || index < 0 || index >= dtx->nr_columns)
return NULL;
struct dtx_entry *entry = &dtx->entries[row * dtx->nr_columns + index];
if (!entry->data)
@@ -129,8 +155,9 @@ struct dtx *dtx_load_from_dtl(const char *path, uint32_t seed)
}
dtx = xcalloc(1, sizeof(struct dtx));
dtx->nr_rows = 3;
dtx->nr_columns = 8;
dtx->version = DTX_VERSION_DTL;
dtx->nr_rows = 4;
dtx->nr_columns = 46; // number of lightmap textures
dtx->entries = xcalloc(dtx->nr_rows * dtx->nr_columns, sizeof(struct dtx_entry));
uint8_t buf[4];
for (int row = 0; row < dtx->nr_rows; row++) {