mirror of https://github.com/webbukkit/dynmap.git
294 lines
10 KiB
Java
294 lines
10 KiB
Java
package org.dynmap.hdmap;
|
|
|
|
import org.dynmap.Color;
|
|
import org.dynmap.ConfigurationNode;
|
|
import org.dynmap.DynmapCore;
|
|
import org.dynmap.DynmapWorld;
|
|
import org.dynmap.MapManager;
|
|
import org.dynmap.utils.LightLevels;
|
|
import org.dynmap.utils.BlockStep;
|
|
|
|
public class ShadowHDLighting extends DefaultHDLighting {
|
|
|
|
protected final int defLightingTable[]; /* index=skylight level, value = 256 * scaling value */
|
|
protected final int lightscale[]; /* scale skylight level (light = lightscale[skylight] */
|
|
protected final boolean night_and_day; /* If true, render both day (prefix+'-day') and night (prefix) tiles */
|
|
protected final boolean smooth;
|
|
protected final boolean useWorldBrightnessTable;
|
|
|
|
public ShadowHDLighting(DynmapCore core, ConfigurationNode configuration) {
|
|
super(core, configuration);
|
|
double shadowweight = configuration.getDouble("shadowstrength", 0.0);
|
|
// See if we're using world's lighting table, or our own
|
|
useWorldBrightnessTable = configuration.getBoolean("use-brightness-table", MapManager.mapman.useBrightnessTable());
|
|
|
|
defLightingTable = new int[16];
|
|
defLightingTable[15] = 256;
|
|
/* Normal brightness weight in MC is a 20% relative dropoff per step */
|
|
for(int i = 14; i >= 0; i--) {
|
|
double v = defLightingTable[i+1] * (1.0 - (0.2 * shadowweight));
|
|
defLightingTable[i] = (int)v;
|
|
if(defLightingTable[i] > 256) defLightingTable[i] = 256;
|
|
if(defLightingTable[i] < 0) defLightingTable[i] = 0;
|
|
}
|
|
int v = configuration.getInteger("ambientlight", -1);
|
|
if(v < 0) v = 15;
|
|
if(v > 15) v = 15;
|
|
night_and_day = configuration.getBoolean("night-and-day", false);
|
|
lightscale = new int[16];
|
|
for(int i = 0; i < 16; i++) {
|
|
if(i < (15-v))
|
|
lightscale[i] = 0;
|
|
else
|
|
lightscale[i] = i - (15-v);
|
|
}
|
|
smooth = configuration.getBoolean("smooth-lighting", MapManager.mapman.getSmoothLighting());
|
|
}
|
|
|
|
private void applySmoothLighting(HDPerspectiveState ps, HDShaderState ss, Color incolor, Color[] outcolor, int[] shadowscale) {
|
|
int[] xyz = ps.getSubblockCoord();
|
|
int scale = (int)ps.getScale();
|
|
int mid = scale/2;
|
|
BlockStep s1, s2;
|
|
int w1, w2;
|
|
/* Figure out which directions to look */
|
|
switch(ps.getLastBlockStep()) {
|
|
case X_MINUS:
|
|
case X_PLUS:
|
|
if(xyz[1] < mid) {
|
|
s1 = BlockStep.Y_MINUS;
|
|
w1 = mid - xyz[1];
|
|
}
|
|
else {
|
|
s1 = BlockStep.Y_PLUS;
|
|
w1 = xyz[1] - mid;
|
|
}
|
|
if(xyz[2] < mid) {
|
|
s2 = BlockStep.Z_MINUS;
|
|
w2 = mid - xyz[2];
|
|
}
|
|
else {
|
|
s2 = BlockStep.Z_PLUS;
|
|
w2 = xyz[2] - mid;
|
|
}
|
|
break;
|
|
case Z_MINUS:
|
|
case Z_PLUS:
|
|
if(xyz[0] < mid) {
|
|
s1 = BlockStep.X_MINUS;
|
|
w1 = mid - xyz[0];
|
|
}
|
|
else {
|
|
s1 = BlockStep.X_PLUS;
|
|
w1 = xyz[0] - mid;
|
|
}
|
|
if(xyz[1] < mid) {
|
|
s2 = BlockStep.Y_MINUS;
|
|
w2 = mid - xyz[1];
|
|
}
|
|
else {
|
|
s2 = BlockStep.Y_PLUS;
|
|
w2 = xyz[1] - mid;
|
|
}
|
|
break;
|
|
default:
|
|
if(xyz[0] < mid) {
|
|
s1 = BlockStep.X_MINUS;
|
|
w1 = mid - xyz[0];
|
|
}
|
|
else {
|
|
s1 = BlockStep.X_PLUS;
|
|
w1 = xyz[0] - mid;
|
|
}
|
|
if(xyz[2] < mid) {
|
|
s2 = BlockStep.Z_MINUS;
|
|
w2 = mid - xyz[2];
|
|
}
|
|
else {
|
|
s2 = BlockStep.Z_PLUS;
|
|
w2 = xyz[2] - mid;
|
|
}
|
|
break;
|
|
}
|
|
/* Now get the 3 needed light levels */
|
|
LightLevels skyemit0 = ps.getCachedLightLevels(0);
|
|
ps.getLightLevels(skyemit0);
|
|
LightLevels skyemit1 = ps.getCachedLightLevels(1);
|
|
ps.getLightLevelsAtStep(s1, skyemit1);
|
|
LightLevels skyemit2 = ps.getCachedLightLevels(2);
|
|
ps.getLightLevelsAtStep(s2, skyemit2);
|
|
|
|
/* Get light levels */
|
|
int ll0 = getLightLevel(skyemit0, true);
|
|
int ll1 = getLightLevel(skyemit1, true);
|
|
int weight = 0;
|
|
if(ll1 < ll0)
|
|
weight -= w1;
|
|
else if(ll1 > ll0)
|
|
weight += w1;
|
|
int ll2 = getLightLevel(skyemit2, true);
|
|
if(ll2 < ll0)
|
|
weight -= w2;
|
|
else if(ll2 > ll0)
|
|
weight += w2;
|
|
outcolor[0].setColor(incolor);
|
|
int cscale = 256;
|
|
if(weight == 0) {
|
|
cscale = shadowscale[ll0];
|
|
}
|
|
else if(weight < 0) { /* If negative, interpolate down */
|
|
weight = -weight;
|
|
if(ll0 > 0) {
|
|
cscale = (shadowscale[ll0] * (scale-weight) + shadowscale[ll0-1] * weight)/scale;
|
|
}
|
|
else {
|
|
cscale = shadowscale[ll0];
|
|
}
|
|
}
|
|
else {
|
|
if(ll0 < 15) {
|
|
cscale = (shadowscale[ll0] * (scale-weight) + shadowscale[ll0+1] * weight)/scale;
|
|
}
|
|
else {
|
|
cscale = shadowscale[ll0];
|
|
}
|
|
}
|
|
if(cscale < 256) {
|
|
Color c = outcolor[0];
|
|
c.setRGBA((c.getRed() * cscale) >> 8, (c.getGreen() * cscale) >> 8,
|
|
(c.getBlue() * cscale) >> 8, c.getAlpha());
|
|
}
|
|
if(outcolor.length > 1) {
|
|
ll0 = getLightLevel(skyemit0, false);
|
|
ll1 = getLightLevel(skyemit1, false);
|
|
weight = 0;
|
|
if(ll1 < ll0)
|
|
weight -= w1;
|
|
else if(ll1 > ll0)
|
|
weight += w1;
|
|
ll2 = getLightLevel(skyemit2, false);
|
|
if(ll2 < ll0)
|
|
weight -= w2;
|
|
else if(ll2 > ll0)
|
|
weight += w2;
|
|
outcolor[1].setColor(incolor);
|
|
cscale = 256;
|
|
if(weight == 0) {
|
|
cscale = shadowscale[ll0];
|
|
}
|
|
else if(weight < 0) { /* If negative, interpolate down */
|
|
weight = -weight;
|
|
if(ll0 > 0) {
|
|
cscale = (shadowscale[ll0] * (scale-weight) + shadowscale[ll0-1] * weight)/scale;
|
|
}
|
|
else {
|
|
cscale = shadowscale[ll0];
|
|
}
|
|
}
|
|
else {
|
|
if(ll0 < 15) {
|
|
cscale = (shadowscale[ll0] * (scale-weight) + shadowscale[ll0+1] * weight)/scale;
|
|
}
|
|
else {
|
|
cscale = shadowscale[ll0];
|
|
}
|
|
}
|
|
if(cscale < 256) {
|
|
Color c = outcolor[1];
|
|
c.setRGBA((c.getRed() * cscale) >> 8, (c.getGreen() * cscale) >> 8,
|
|
(c.getBlue() * cscale) >> 8, c.getAlpha());
|
|
}
|
|
}
|
|
}
|
|
|
|
private final int getLightLevel(final LightLevels ll, boolean useambient) {
|
|
int lightlevel;
|
|
/* If ambient light, adjust base lighting for it */
|
|
if(useambient)
|
|
lightlevel = lightscale[ll.sky];
|
|
else
|
|
lightlevel = ll.sky;
|
|
/* If we're below max, see if emitted light helps */
|
|
if(lightlevel < 15) {
|
|
lightlevel = Math.max(ll.emitted, lightlevel);
|
|
}
|
|
return lightlevel;
|
|
}
|
|
|
|
/* Apply lighting to given pixel colors (1 outcolor if normal, 2 if night/day) */
|
|
public void applyLighting(HDPerspectiveState ps, HDShaderState ss, Color incolor, Color[] outcolor) {
|
|
int[] shadowscale = null;
|
|
if(smooth) {
|
|
shadowscale = ss.getLightingTable();
|
|
if (shadowscale == null) {
|
|
shadowscale = defLightingTable;
|
|
}
|
|
applySmoothLighting(ps, ss, incolor, outcolor, shadowscale);
|
|
return;
|
|
}
|
|
LightLevels ll = null;
|
|
int lightlevel = 15, lightlevel_day = 15;
|
|
/* If processing for shadows, use sky light level as base lighting */
|
|
if(defLightingTable != null) {
|
|
shadowscale = ss.getLightingTable();
|
|
if (shadowscale == null) {
|
|
shadowscale = defLightingTable;
|
|
}
|
|
ll = ps.getCachedLightLevels(0);
|
|
ps.getLightLevels(ll);
|
|
lightlevel = lightlevel_day = ll.sky;
|
|
}
|
|
/* If ambient light, adjust base lighting for it */
|
|
lightlevel = lightscale[lightlevel];
|
|
/* If we're below max, see if emitted light helps */
|
|
if((lightlevel < 15) || (lightlevel_day < 15)) {
|
|
int emitted = ll.emitted;
|
|
lightlevel = Math.max(emitted, lightlevel);
|
|
lightlevel_day = Math.max(emitted, lightlevel_day);
|
|
}
|
|
/* Figure out our color, with lighting if needed */
|
|
outcolor[0].setColor(incolor);
|
|
if(lightlevel < 15) {
|
|
shadowColor(outcolor[0], lightlevel, shadowscale);
|
|
}
|
|
if(outcolor.length > 1) {
|
|
if(lightlevel_day == lightlevel) {
|
|
outcolor[1].setColor(outcolor[0]);
|
|
}
|
|
else {
|
|
outcolor[1].setColor(incolor);
|
|
if(lightlevel_day < 15) {
|
|
shadowColor(outcolor[1], lightlevel_day, shadowscale);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private final void shadowColor(Color c, int lightlevel, int[] shadowscale) {
|
|
int scale = shadowscale[lightlevel];
|
|
if(scale < 256)
|
|
c.setRGBA((c.getRed() * scale) >> 8, (c.getGreen() * scale) >> 8,
|
|
(c.getBlue() * scale) >> 8, c.getAlpha());
|
|
}
|
|
|
|
|
|
/* Test if night/day is enabled for this renderer */
|
|
public boolean isNightAndDayEnabled() { return night_and_day; }
|
|
|
|
/* Test if sky light level needed */
|
|
public boolean isSkyLightLevelNeeded() { return true; }
|
|
|
|
/* Test if emitted light level needed */
|
|
public boolean isEmittedLightLevelNeeded() { return true; }
|
|
|
|
@Override
|
|
public int[] getBrightnessTable(DynmapWorld world) {
|
|
if (useWorldBrightnessTable) {
|
|
return world.getBrightnessTable();
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
}
|