Parameters relevant to the LOS calculation are now passed as an object los_param that takes care of coordinate translation, bounds checking, opacity of cells and what is written to the output array.
A check for in_bounds was changed to map_bounds for simlicity; this should not have any effect.
Special casing for arena was removed from losight; instead calc_show_los now calls the new losight_permissive.
2EBEWIV4YHXXAFR4GG2GMZJ2K77NK762HNQ77CZLHI3LDVGX7RJAC
ACZYEIX7WMPIIODKCATBCUE626AJ4ZGGBOMVC6BGXM27EQU2RECAC
PEZFWKRHDHV4UJTPK5XJZ3CGTZ3LPTDYSPTYBENLQ7VRSP7YFSIQC
ZNMT5CZHP2FC4HTLNA7KYEDGFBXSCUE5QHJOALVPE6RDPHSEDXRQC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
W52PCSHX72WAMWKG6L4BPUBVMO6E72KYYBNKAA7554KNOTY6V7WQC
MQ62OAMLGJVRW2QIL4PAZRAU6PC52ZVGY2FCOBIY6IWGQIHMU5CAC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
/*
* File: losparam.h
* Summary: Parameters for the LOS algorithm
*/
#ifndef LOSPARAM_H
#define LOSPARAM_H
enum opacity_type
{
OPC_CLEAR,
OPC_HALF, // for opaque clouds; two or more block
OPC_OPAQUE,
NUM_OPACITIES
};
// Subclasses of this are passed to losight() to modify the
// LOS calculation. Implementations will have to translate between
// relative coordinates (-8,-8)..(8,8) and real coordinates,
// specify how opaque the cells are and determine what values
// are written to the visible cells.
struct los_param
{
virtual ~los_param() {}
// Whether the translated coordinate lies in the map (including boundary)
virtual bool map_bounds(const coord_def& p) const = 0;
// appearance(p) will be copied to show(p) for visible p.
virtual unsigned appearance(const coord_def& p) const = 0;
virtual opacity_type opacity(const coord_def& p) const = 0;
};
// Provides translation to given center and bounds checking.
struct los_param_trans : los_param
{
coord_def center;
los_param_trans(const coord_def& c);
coord_def trans(const coord_def& p) const;
bool map_bounds(const coord_def& p) const;
};
// A complete base implementation that does standard visibility
// based on env.grid.
struct los_param_base : los_param_trans
{
los_param_base(const coord_def& c);
dungeon_feature_type feature(const coord_def& p) const;
unsigned appearance(const coord_def& p) const;
unsigned short cloud_idx(const coord_def& p) const;
opacity_type opacity(const coord_def& p) const;
};
// Provides a compatible set of parameters for use with the
// legacy losight() function.
struct los_param_compat : los_param_base
{
feature_grid grid;
bool solid_blocks;
bool ignore_clouds;
los_param_compat(const feature_grid& gr, const coord_def& c,
bool sb, bool ic);
dungeon_feature_type feature(const coord_def& p) const;
unsigned appearance(const coord_def& p) const;
opacity_type opacity(const coord_def& p) const;
};
#endif
/*
* File: losparam.h
* Summary: Parameters for the LOS algorithm
*/
#include "AppHdr.h"
REVISION("$Rev$");
#include "losparam.h"
#include "cloud.h"
#include "externs.h"
#include "stuff.h"
#include "terrain.h"
los_param_trans::los_param_trans(const coord_def& c)
: center(c)
{
}
coord_def los_param_trans::trans(const coord_def& p) const
{
return p + center;
}
bool los_param_trans::map_bounds(const coord_def& p) const
{
return ::map_bounds(trans(p));
}
los_param_base::los_param_base(const coord_def& c)
: los_param_trans(c)
{
}
dungeon_feature_type los_param_base::feature(const coord_def& p) const
{
return env.grid(trans(p));
}
unsigned los_param_base::appearance(const coord_def& p) const
{
return grid_appearance(trans(p));
}
unsigned short los_param_base::cloud_idx(const coord_def& p) const
{
return env.cgrid(trans(p));
}
opacity_type los_param_base::opacity(const coord_def& p) const
{
dungeon_feature_type f = feature(p);
if (grid_is_opaque(f))
return OPC_OPAQUE;
else if (is_opaque_cloud(cloud_idx(p)))
return OPC_HALF;
else
return OPC_CLEAR;
}
los_param_compat::los_param_compat(const feature_grid& gr, const coord_def& c,
bool sb, bool ic)
: los_param_base(c), grid(gr), solid_blocks(sb), ignore_clouds(ic)
{
}
dungeon_feature_type los_param_compat::feature(const coord_def& p) const
{
return grid(trans(p));
}
unsigned los_param_compat::appearance(const coord_def& p) const
{
return grid_appearance(grid, trans(p));
}
opacity_type los_param_compat::opacity(const coord_def& p) const
{
dungeon_feature_type f = feature(p);
if (grid_is_opaque(f) || solid_blocks && grid_is_solid(f))
return OPC_OPAQUE;
else if (!ignore_clouds && is_opaque_cloud(cloud_idx(p)))
return OPC_HALF;
else
return OPC_CLEAR;
}
raycast();
const int x_p = center.x;
const int y_p = center.y;
// go quadrant by quadrant
const int quadrant_x[4] = { 1, -1, -1, 1 };
const int quadrant_y[4] = { 1, 1, -1, -1 };
// clear out sh
sh.init(0);
if (crawl_state.arena || crawl_state.arena_suspended)
{
for (int y = -ENV_SHOW_OFFSET; y <= ENV_SHOW_OFFSET; ++y)
for (int x = -ENV_SHOW_OFFSET; x <= ENV_SHOW_OFFSET; ++x)
{
const coord_def pos = center + coord_def(x, y);
if (map_bounds(pos))
sh[x + sh_xo][y + sh_yo] = gr(pos);
}
return;
}
for (int quadrant = 0; quadrant < 4; ++quadrant)
{
const int xmult = quadrant_x[quadrant];
const int ymult = quadrant_y[quadrant];
// clear out the dead rays array
memset( (void*)dead_rays, 0, sizeof(unsigned long) * num_words);
memset( (void*)smoke_rays, 0, sizeof(unsigned long) * num_words);
const int realx = x_p + xdiff * xmult;
const int realy = y_p + ydiff * ymult;
if (!map_bounds(realx, realy))
continue;
coord_def real(realx, realy);
dungeon_feature_type dfeat = grid_appearance(gr, real);
// if this cell is opaque...
// ... or something you can see but not walk through ...
if (grid_is_opaque(dfeat)
|| clear_walls_block && dfeat < DNGN_MINMOVE)
case OPC_OPAQUE:
// then block the appropriate rays
for (unsigned int i = 0; i < num_words; ++i)
dead_rays[i] |= inptr[i];
break;
case OPC_HALF:
// block rays which have already seen a cloud
for (unsigned int i = 0; i < num_words; ++i)
else if (!ignore_clouds
&& is_opaque_cloud(env.cgrid[realx][realy]))
{
// block rays which have already seen a cloud
for (unsigned int i = 0; i < num_words; ++i)
{
dead_rays[i] |= (smoke_rays[i] & inptr[i]);
smoke_rays[i] |= inptr[i];
}
}
break;
default:
break;
// ray calculation done, now work out which cells in this
// quadrant are visible
unsigned int rayidx = 0;
for (unsigned int wordloc = 0; wordloc < num_words; ++wordloc)
// ray calculation done, now work out which cells in this
// quadrant are visible
unsigned int rayidx = 0;
for (unsigned int wordloc = 0; wordloc < num_words; ++wordloc)
{
const unsigned long curword = dead_rays[wordloc];
// Note: the last word may be incomplete
for (unsigned int bitloc = 0; bitloc < LONGSIZE; ++bitloc)
// make the cells seen by this ray at this point visible
if ( ((curword >> bitloc) & 1UL) == 0 )
// this ray is alive!
const coord_def p = coord_def(sx * compressed_ray_x[rayidx],
sy * compressed_ray_y[rayidx]);
// update shadow map
if (dat.map_bounds(p) && p.abs() <= _los_radius_squared)
// this ray is alive!
const int realx = xmult * compressed_ray_x[rayidx];
const int realy = ymult * compressed_ray_y[rayidx];
// update shadow map
if (x_p + realx >= 0 && x_p + realx < GXM
&& y_p + realy >= 0 && y_p + realy < GYM
&& realx * realx + realy * realy <= _los_radius_squared)
{
sh[sh_xo+realx][sh_yo+realy] = gr[x_p+realx][y_p+realy];
}
sh(p+sh_o) = dat.appearance(p);
*dead_rays = NULL;
*smoke_rays = NULL;
*los_blockrays = NULL;
// ensure precomputations are done
raycast();
const int quadrant_x[4] = { 1, -1, -1, 1 };
const int quadrant_y[4] = { 1, 1, -1, -1 };
for (int q = 0; q < 4; ++q)
{
_losight_quadrant(sh, dat, quadrant_x[q], quadrant_y[q]);
}
// center is always visible
const coord_def o = coord_def(0,0);
sh(o+sh_o) = dat.appearance(o);
}
void losight(env_show_grid &sh, feature_grid &gr,
const coord_def& center, bool clear_walls_block,
bool ignore_clouds)
{
losight(sh, los_param_compat(gr, center, clear_walls_block, ignore_clouds));
}
void losight_permissive(env_show_grid &sh, const coord_def& center)
{
for (int x = -ENV_SHOW_OFFSET; x <= ENV_SHOW_OFFSET; ++x)
for (int y = -ENV_SHOW_OFFSET; y <= ENV_SHOW_OFFSET; ++y)
{
const coord_def pos = center + coord_def(x, y);
if (map_bounds(pos))
sh[x + sh_xo][y + sh_yo] = env.grid(pos);
}