From 690c47819c8bd46fdd4d5a0937c2bcc44dda55d5 Mon Sep 17 00:00:00 2001 From: Martin Read Date: Mon, 23 Sep 2013 20:38:26 +0100 Subject: [PATCH] Add explanatory comments to fov.c and fix handling of centre-of-radiance. --- fov.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 7 deletions(-) diff --git a/fov.c b/fov.c index 8a5b672..dc10191 100644 --- a/fov.c +++ b/fov.c @@ -34,29 +34,47 @@ #include #include +/*! \brief Transverse-step delta-y for each octant + */ int trn_dy[8] = { 0, -1, 1, 0, 0, 1, -1, 0 }; +/*! \brief Transverse-step delta-x for each octant + */ int trn_dx[8] = { 1, 0, 0, 1, -1, 0, 0, -1 }; +/*! \brief Radial-step delta-y for each octant + */ int rdl_dy[8] = { -1, 0, 0, 1, 1, 0, 0, -1 }; +/*! \brief Radial-step delta-x for each octant + */ int rdl_dx[8] = { 0, 1, 1, 0, 0, -1, -1, 0 }; static void compute_row(Radiance *rad, int octant, int radius, double inmost_slope, double outmost_slope); +/*! \brief Default blocking function + * + * This function returns true if the specified coordinates are out of bounds + * or the terrain at the specified position is opaque. + */ static bool dflt_blk(int y, int x) { return ((y <= 0) || (x <= 0) || (y >= DUN_HEIGHT - 1) || (x >= DUN_WIDTH - 1) || (terrain_is_opaque(terrain[y][x]))); } +/*! \brief Function for marking affected cells as explored + * + * This function marks the specified tile as explored, triggers a symbol + * update, and returns true. + */ static bool mark_explored(int y, int x, void *pvt) { mapflags[y][x] |= MAPFLAG_EXPLORED; @@ -64,41 +82,52 @@ static bool mark_explored(int y, int x, void *pvt) return true; } -/*! \fn - * \brief Return the inner (cardinal-wards) blocking limit of an octant-relative coordinate +/*! \brief Return the inner (cardinal-wards) blocking limit of an octant-relative coordinate */ static inline double inner_slope(int rdl, int trn) { return trn ? ((trn - 0.5) / ((double) rdl)) : 0.0; } +/*! \brief Return the innermost (cardinal-wards) visible slope of an octant-relative coordinate + */ static inline double inner_visible_slope(int rdl, int trn) { return trn ? ((trn - 0.5) / (rdl + 0.5)) : 0.0; } -/*! \fn - * \brief Return the outer (diagonal-wards) blocking limit of an octant-relative coordinate + +/*! \brief Return the outer (diagonal-wards) blocking limit of an octant-relative coordinate */ + static inline double outer_slope(int rdl, int trn) { return (rdl == trn) ? 1.0 : ((trn + 0.5) / (double) rdl); } +/*! \brief Return the outermost (diagonal-wards) visible slope of an octant-relative coordinate + */ + static inline double outer_visible_slope(int rdl, int trn) { return (rdl == trn) ? 1.0 : ((trn + 0.5) / (rdl - 0.5)); } +/*! \brief Reset the affected flags of a Radiance object + */ void clear_radiance(Radiance *rad) { memset(&(rad->affected), '\0', sizeof rad->affected); } +/*! \brief Start computing one octant of a Radiance + */ static inline void compute_octant(Radiance *rad, int octant) { compute_row(rad, octant, 1, 0.0, 1.0); } +/*! \brief Compute one (partial) row of a Radiance and recurse. + */ static void compute_row(Radiance *rad, int octant, int radius, double inmost_slope, double outmost_slope) { int trn; @@ -108,24 +137,44 @@ static void compute_row(Radiance *rad, int octant, int radius, double inmost_slo int outer_idx; int inner_idx; double isl; - double ivs; - double ovs; + + /* + * We should never get the slopes mismatched like this, but if we do, + * return immediately. + */ if (inmost_slope >= outmost_slope) { return; } + /* + * The inner_idx and outer_idx values are used to control which tiles of + * the current row we actually examine. + */ inner_idx = 0.5 + (inmost_slope * radius); outer_idx = 0.5 + (outmost_slope * radius); + /* + * dx and dy - the position of the "cursor" relative to the centre of + * the potentially affected area - are calculated using the rdl_* and trn_* + * arrays. + */ dx = radius * rdl_dx[octant] + outer_idx * trn_dx[octant]; dy = radius * rdl_dy[octant] + outer_idx * trn_dy[octant]; + /* + * Iterate over the range of transverse deflections from outer_idx to + * inner_idx. + */ for (trn = outer_idx; trn >= inner_idx; --trn) { + /* Get the inner "grazing" slope of the diamond inside the tile. */ isl = inner_slope(radius, trn); + /* Mark the tile being examined as affected. */ rad->affected[MAX_FOV_RADIUS + dy][MAX_FOV_RADIUS + dx] = true; if (block_flag) { + /* If the previous tile was opaque... */ if (rad->opaque_fun(dy + rad->centre_y, dx + rad->centre_x)) { + /* ... then if this one is too, update the slope */ if (outmost_slope > isl) { outmost_slope = isl; @@ -133,29 +182,50 @@ static void compute_row(Radiance *rad, int octant, int radius, double inmost_slo } else { + /* ... and if not, clear the blocking flag. */ block_flag = false; } } else { + /* Otherwise... */ if (rad->opaque_fun(dy + rad->centre_y, dx + rad->centre_x)) { + /* ... if the current tile is opaque, set the blocking flag. */ block_flag = true; + /* + * and if we're not examining the first tile of this strip, + * and we're not examining the last row of the octant, + * recursively examine the diagonalwards portion of the + * next row. + */ if ((trn < outer_idx) && (radius < rad->radius)) { compute_row(rad, octant, radius + 1, outer_slope(radius, trn), outmost_slope); } + /* + * Update the outermost slope to reflect what is occluded by + * this cell. + */ if (outmost_slope > isl) { outmost_slope = isl; } } } + /* + * Advance whichever of dx or dy is the transverse coordinate for this + * octant. + */ dx -= trn_dx[octant]; dy -= trn_dy[octant]; } if ((radius < rad->radius) && !block_flag) { + /* + * If we haven't reached the last row, and the last tile we examined + * in this row wasn't opaque, recursively compute the next row. + */ compute_row(rad, octant, radius + 1, inmost_slope, outmost_slope); } } @@ -163,17 +233,19 @@ static void compute_row(Radiance *rad, int octant, int radius, double inmost_slo void compute_radiance(Radiance *rad) { int oct; + /* Compute the eight octants in order. */ for (oct = 0; oct < 8; ++oct) { compute_octant(rad, oct); } + /* Mark the centre as (un)affected according to the Radiance's setup. */ if (rad->exclude_centre) { rad->affected[MAX_FOV_RADIUS][MAX_FOV_RADIUS] = false; } else { - rad->affected[MAX_FOV_RADIUS][MAX_FOV_RADIUS] = false; + rad->affected[MAX_FOV_RADIUS][MAX_FOV_RADIUS] = true; } } @@ -183,6 +255,7 @@ void resolve_radiance(Radiance *rad) int x; int i; int j; + switch (rad->order) { case Reo_ascending: @@ -219,5 +292,6 @@ void compute_fov(void) compute_radiance(&player_fov); resolve_radiance(&player_fov); } + /* fov.c */ // vim:cindent -- 2.11.0