Global lighting
Lighting module is one of the most convoluted parts of rot.js
: it is a mix of various concepts introduced in simpler components. ROT.Lighting
is used to compute how multiple light sources mix and reflect in a cellular map (using a highly simplified radiosity-like algorithm).
To compute a lighting, you need the following:
- a
ROT.FOV
instance, which is used to compute the areas lit by light sources;
- a
lightingCallback
which notifies you about the resulting light for a given coordinates;
- a set of lights, defined by their position (x, y) and color.
If you decide to use a two-pass lighting (more light, more realistic light spread, more computation time), you also need:
- a
reflectivityCallback
which is used to return how much individual map cells reflect incoming light. Please note that wall cells should not reflect any light for the purpose of lighting computation.
Finally, the ROT.Lighting
function accepts an optional configuration object as its second argument. This object may contain:
range
– maximum range for the most powerful light source
passes
– number of computation passes (1: no reflectivity used, 2: reflectivity used)
emissionThreshold
– minimal amount of light at a cell to be re-emited (only for passes>1)
ROT.RNG.setSeed(12345);
ROT.DEFAULT_WIDTH = 60;
ROT.DEFAULT_HEIGHT = 40;
var mapData = {};
var lightData = {};
/* build a map */
var map = new ROT.Map.Cellular().randomize(0.5);
var createCallback = function(x, y, value) {
mapData[x+","+y] = value;
}
for (var i=0; i<4; i++) {
map.create(createCallback);
}
/* prepare a FOV algorithm */
var lightPasses = function(x, y) {
return (mapData[x+","+y] == 1);
}
var fov = new ROT.FOV.PreciseShadowcasting(lightPasses, {topology:4});
/* prepare a lighting algorithm */
var reflectivity = function(x, y) {
return (mapData[x+","+y] == 1 ? 0.3 : 0);
}
var lighting = new ROT.Lighting(reflectivity, {range:12, passes:2});
lighting.setFOV(fov);
lighting.setLight(12, 12, [240, 240, 30]);
lighting.setLight(20, 20, [240, 60, 60]);
lighting.setLight(45, 25, [200, 200, 200]);
var lightingCallback = function(x, y, color) {
lightData[x+","+y] = color;
}
lighting.compute(lightingCallback);
/* draw the resulting mix of mapData and lightData */
var display = new ROT.Display({fontSize:8});
SHOW(display.getContainer());
/* all cells are lit by ambient light; some are also lit by light sources */
var ambientLight = [100, 100, 100];
for (var id in mapData) {
var parts = id.split(",");
var x = parseInt(parts[0]);
var y = parseInt(parts[1]);
var baseColor = (mapData[id] ? [100, 100, 100] : [50, 50, 50]);
var light = ambientLight;
if (id in lightData) { /* add light from our computation */
light = ROT.Color.add(light, lightData[id]);
}
var finalColor = ROT.Color.multiply(baseColor, light);
display.draw(x, y, null, null, ROT.Color.toRGB(finalColor));
}