diff options
Diffstat (limited to 'crawl-ref')
-rw-r--r-- | crawl-ref/source/los.cc | 179 | ||||
-rw-r--r-- | crawl-ref/source/los.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/losparam.cc | 88 | ||||
-rw-r--r-- | crawl-ref/source/losparam.h | 76 | ||||
-rw-r--r-- | crawl-ref/source/makefile.obj | 1 | ||||
-rw-r--r-- | crawl-ref/source/terrain.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/terrain.h | 2 |
7 files changed, 256 insertions, 94 deletions
diff --git a/crawl-ref/source/los.cc b/crawl-ref/source/los.cc index 4a63c04b25..400ea200a2 100644 --- a/crawl-ref/source/los.cc +++ b/crawl-ref/source/los.cc @@ -15,6 +15,7 @@ REVISION("$Rev$"); #include "debug.h" #include "directn.h" #include "externs.h" +#include "losparam.h" #include "ray.h" #include "state.h" #include "stuff.h" @@ -35,6 +36,7 @@ REVISION("$Rev$"); const int sh_xo = 9; // X and Y origins for the sh array const int sh_yo = 9; +const coord_def sh_o = coord_def(sh_xo, sh_yo); unsigned long* los_blockrays = NULL; unsigned long* dead_rays = NULL; @@ -738,118 +740,111 @@ bool grid_see_grid(const coord_def& p1, const coord_def& p2, // IMPROVEMENTS: // Smoke will now only block LOS after two cells of smoke. This is // done by updating with a second array. -void losight(env_show_grid &sh, - feature_grid &gr, const coord_def& center, - bool clear_walls_block, bool ignore_clouds) -{ - 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; - } +void _losight_quadrant(env_show_grid& sh, const los_param& dat, int sx, int sy) +{ const unsigned int num_cellrays = compressed_ray_x.size(); const unsigned int num_words = (num_cellrays + LONGSIZE - 1) / LONGSIZE; - 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); - // 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); + // kill all blocked rays + const unsigned long* inptr = los_blockrays; - // kill all blocked rays - const unsigned long* inptr = los_blockrays; + for (int x = 0; x <= LOS_MAX_RANGE_X; ++x) + for (int y = 0; y <= LOS_MAX_RANGE_Y; ++y, inptr += num_words) + { + coord_def p = coord_def(sx*x, sy*y); + if (!dat.map_bounds(p)) + continue; - for (int xdiff = 0; xdiff <= LOS_MAX_RANGE_X; ++xdiff) - for (int ydiff = 0; ydiff <= LOS_MAX_RANGE_Y; - ++ydiff, inptr += num_words) + // if this cell is opaque... + switch (dat.opacity(p)) { - - 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) - { - // then block the appropriate rays - for (unsigned int i = 0; i < num_words; ++i) - dead_rays[i] |= inptr[i]; - } - else if (!ignore_clouds - && is_opaque_cloud(env.cgrid[realx][realy])) + 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) { - // 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]; - } + 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) { - 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 ) { - // 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); } - ++rayidx; - if (rayidx == num_cellrays) - break; } + ++rayidx; + if (rayidx == num_cellrays) + break; } } +} + +void losight(env_show_grid& sh, const los_param& dat) +{ + sh.init(0); + + // 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]); + } - // [dshaligram] The player's current position is always visible. - sh[sh_xo][sh_yo] = gr[x_p][y_p]; + // center is always visible + const coord_def o = coord_def(0,0); + sh(o+sh_o) = dat.appearance(o); +} - *dead_rays = NULL; - *smoke_rays = NULL; - *los_blockrays = NULL; +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); + } } void calc_show_los() @@ -865,7 +860,7 @@ void calc_show_los() } else { - losight(env.show, grd, crawl_view.glosc()); + losight_permissive(env.show, crawl_view.glosc()); } } diff --git a/crawl-ref/source/los.h b/crawl-ref/source/los.h index 301806b8c6..0eca7e4fc4 100644 --- a/crawl-ref/source/los.h +++ b/crawl-ref/source/los.h @@ -7,6 +7,7 @@ #define LOS_H #include "externs.h" +#include "losparam.h" #define EPSILON_VALUE 0.00001 @@ -33,6 +34,7 @@ void clear_rays_on_exit(); void losight(env_show_grid &sh, feature_grid &gr, const coord_def& center, bool clear_walls_block = false, bool ignore_clouds = false); +void losight(env_show_grid& sh, const los_param& dat); void calc_show_los(); bool see_grid( const env_show_grid &show, diff --git a/crawl-ref/source/losparam.cc b/crawl-ref/source/losparam.cc new file mode 100644 index 0000000000..dc22990ee0 --- /dev/null +++ b/crawl-ref/source/losparam.cc @@ -0,0 +1,88 @@ +/* + * 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; +} + diff --git a/crawl-ref/source/losparam.h b/crawl-ref/source/losparam.h new file mode 100644 index 0000000000..a31fbb46f5 --- /dev/null +++ b/crawl-ref/source/losparam.h @@ -0,0 +1,76 @@ +/* + * 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 diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj index 0cd08afa04..aaa4f4d168 100644 --- a/crawl-ref/source/makefile.obj +++ b/crawl-ref/source/makefile.obj @@ -37,6 +37,7 @@ items.o \ lev-pand.o \ libutil.o \ los.o \ +losparam.o \ luadgn.o \ macro.o \ makeitem.o \ diff --git a/crawl-ref/source/terrain.cc b/crawl-ref/source/terrain.cc index 5d831713bb..ee0efbde29 100644 --- a/crawl-ref/source/terrain.cc +++ b/crawl-ref/source/terrain.cc @@ -368,7 +368,7 @@ dungeon_feature_type grid_appearance(const coord_def &gc) return grid_appearance(grd, gc); } -dungeon_feature_type grid_appearance(feature_grid &gr, const coord_def &gc) +dungeon_feature_type grid_appearance(const feature_grid &gr, const coord_def &gc) { dungeon_feature_type grid = gr(gc); if (grid == DNGN_SECRET_DOOR) diff --git a/crawl-ref/source/terrain.h b/crawl-ref/source/terrain.h index 702237013d..1c0adc0b1d 100644 --- a/crawl-ref/source/terrain.h +++ b/crawl-ref/source/terrain.h @@ -53,7 +53,7 @@ void find_connected_range(coord_def d, dungeon_feature_type ft_min, void get_door_description(int door_size, const char** adjective, const char** noun); dungeon_feature_type grid_secret_door_appearance(const coord_def &where); dungeon_feature_type grid_appearance(const coord_def &gc); -dungeon_feature_type grid_appearance(feature_grid &gr, const coord_def &gc); +dungeon_feature_type grid_appearance(const feature_grid &gr, const coord_def &gc); unsigned int show_appearance(const coord_def &ep); bool grid_destroys_items(dungeon_feature_type grid); |