summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/losglobal.cc
diff options
context:
space:
mode:
authorRobert Vollmert <rvollmert@gmx.net>2010-03-22 09:32:10 +0100
committerRobert Vollmert <rvollmert@gmx.net>2010-03-22 18:49:32 +0100
commit0d95dc671575c8b38eb1d18f20fa9537f9c38d5e (patch)
tree3f6088119ab9614f51bdaf68a02152f560f465bf /crawl-ref/source/losglobal.cc
parent8cc49931c17750ea03154485fde5143f1a9ce46f (diff)
downloadcrawl-ref-0d95dc671575c8b38eb1d18f20fa9537f9c38d5e.tar.gz
crawl-ref-0d95dc671575c8b38eb1d18f20fa9537f9c38d5e.zip
losglobal.cc: A start at tracking LOS globally.
Diffstat (limited to 'crawl-ref/source/losglobal.cc')
-rw-r--r--crawl-ref/source/losglobal.cc89
1 files changed, 89 insertions, 0 deletions
diff --git a/crawl-ref/source/losglobal.cc b/crawl-ref/source/losglobal.cc
new file mode 100644
index 0000000000..bd2bb147a4
--- /dev/null
+++ b/crawl-ref/source/losglobal.cc
@@ -0,0 +1,89 @@
+#include "AppHdr.h"
+
+#include "losglobal.h"
+
+#include "coord.h"
+#include "coordit.h"
+#include "fixedarray.h"
+#include "los_def.h"
+
+typedef unsigned char losfield_t;
+typedef FixedArray<losfield_t, LOS_MAX_RANGE+1, 2*LOS_MAX_RANGE+1> halflos_t;
+const coord_def o_half(0, LOS_MAX_RANGE);
+typedef FixedArray<halflos_t, GXM, GYM> globallos_t;
+
+globallos_t globallos;
+
+static losfield_t* _lookup_globallos(const coord_def& p, const coord_def& q)
+{
+ if (!map_bounds(p) || !map_bounds(q))
+ return (NULL);
+ coord_def diff = q - p;
+ if (diff.rdist() > LOS_MAX_RANGE)
+ return (NULL);
+ // p < q iff p.x < q.x || p.x == q.x && p.y < q.y
+ if (diff < coord_def(0, 0))
+ return (&globallos(q)(-diff+o_half));
+ else
+ return (&globallos(p)(diff+o_half));
+}
+
+static void _save_los(los_def* los, los_type l)
+{
+ const coord_def o = los->get_center();
+ for (radius_iterator ri(o, LOS_MAX_RANGE, C_SQUARE); ri; ++ri)
+ {
+ losfield_t* flags = _lookup_globallos(o, *ri);
+ if (!flags)
+ continue;
+ // XXX: we're assuming that if one type of LOS is updated,
+ // all will be.
+ *flags &= ~LOS_FLAG_INVALID;
+ if (los->see_cell(*ri))
+ *flags |= l;
+ else
+ *flags &= ~l;
+ }
+}
+
+// Opacity at p has changed.
+void invalidate_los_around(const coord_def& p)
+{
+ const coord_def tl = p - coord_def(LOS_MAX_RANGE, LOS_MAX_RANGE);
+ const coord_def br = p + coord_def(0, LOS_MAX_RANGE);
+ // We're wiping out a little more than required here.
+ for (rectangle_iterator ri(tl, br); ri; ++ri)
+ if (map_bounds(*ri))
+ globallos(*ri).init(LOS_FLAG_INVALID);
+}
+
+void invalidate_los()
+{
+ for (rectangle_iterator ri(0); ri; ++ri)
+ globallos(*ri).init(LOS_FLAG_INVALID);
+}
+
+static void _update_globallos_at(const coord_def& p)
+{
+ los_def los(p, opc_default);
+ los.update();
+ _save_los(&los, LOS_DEFAULT);
+ los.set_opacity(opc_no_trans);
+ los.update();
+ _save_los(&los, LOS_NO_TRANS);
+}
+
+bool cell_see_cell(const coord_def& p, const coord_def& q, los_type l)
+{
+ losfield_t* flags = _lookup_globallos(p, q);
+
+ if (!flags)
+ return (false); // outside range
+
+ if (*flags & LOS_FLAG_INVALID)
+ _update_globallos_at(p);
+
+ ASSERT(!(*flags & LOS_FLAG_INVALID));
+
+ return (*flags & l);
+}