summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/los.cc179
-rw-r--r--crawl-ref/source/los.h2
-rw-r--r--crawl-ref/source/losparam.cc88
-rw-r--r--crawl-ref/source/losparam.h76
-rw-r--r--crawl-ref/source/makefile.obj1
-rw-r--r--crawl-ref/source/terrain.cc2
-rw-r--r--crawl-ref/source/terrain.h2
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);