untrusted-test-only / lib /rotjs-library /src /fov /discrete-shadowcasting.js
lychees's picture
Upload 569 files
87b3b3a
/**
* @class Discrete shadowcasting algorithm
* @augments ROT.FOV
*/
ROT.FOV.DiscreteShadowcasting = function(lightPassesCallback, options) {
ROT.FOV.call(this, lightPassesCallback, options);
}
ROT.FOV.DiscreteShadowcasting.extend(ROT.FOV);
/**
* @see ROT.FOV#compute
*/
ROT.FOV.DiscreteShadowcasting.prototype.compute = function(x, y, R, callback) {
var center = this._coords;
var map = this._map;
/* this place is always visible */
callback(x, y, 0);
/* standing in a dark place. FIXME is this a good idea? */
if (!this._lightPasses(x, y)) { return; }
/* start and end angles */
var DATA = [];
var A, B, cx, cy, blocks;
/* analyze surrounding cells in concentric rings, starting from the center */
for (var r=1; r<=R; r++) {
var neighbors = this._getCircle(x, y, r);
var angle = 360 / neighbors.length;
for (var i=0;i<neighbors.length;i++) {
cx = neighbors[i][0];
cy = neighbors[i][1];
A = angle * (i - 0.5);
B = A + angle;
blocks = !this._lightPasses(cx, cy);
if (this._visibleCoords(Math.floor(A), Math.ceil(B), blocks, DATA)) { callback(cx, cy, r, 1); }
if (DATA.length == 2 && DATA[0] == 0 && DATA[1] == 360) { return; } /* cutoff? */
} /* for all cells in this ring */
} /* for all rings */
}
/**
* @param {int} A start angle
* @param {int} B end angle
* @param {bool} blocks Does current cell block visibility?
* @param {int[][]} DATA shadowed angle pairs
*/
ROT.FOV.DiscreteShadowcasting.prototype._visibleCoords = function(A, B, blocks, DATA) {
if (A < 0) {
var v1 = arguments.callee(0, B, blocks, DATA);
var v2 = arguments.callee(360+A, 360, blocks, DATA);
return v1 || v2;
}
var index = 0;
while (index < DATA.length && DATA[index] < A) { index++; }
if (index == DATA.length) { /* completely new shadow */
if (blocks) { DATA.push(A, B); }
return true;
}
var count = 0;
if (index % 2) { /* this shadow starts in an existing shadow, or within its ending boundary */
while (index < DATA.length && DATA[index] < B) {
index++;
count++;
}
if (count == 0) { return false; }
if (blocks) {
if (count % 2) {
DATA.splice(index-count, count, B);
} else {
DATA.splice(index-count, count);
}
}
return true;
} else { /* this shadow starts outside an existing shadow, or within a starting boundary */
while (index < DATA.length && DATA[index] < B) {
index++;
count++;
}
/* visible when outside an existing shadow, or when overlapping */
if (A == DATA[index-count] && count == 1) { return false; }
if (blocks) {
if (count % 2) {
DATA.splice(index-count, count, A);
} else {
DATA.splice(index-count, count, A, B);
}
}
return true;
}
}