diff --git a/lightings.txt b/lightings.txt new file mode 100644 index 00000000..f8ec1899 --- /dev/null +++ b/lightings.txt @@ -0,0 +1,30 @@ +lightings: + # Default lighting - no effects, shadows, day/night + - class: org.dynmap.hdmap.DefaultHDLighting + name: default + # Shadows enabled day mode + - class: org.dynmap.hdmap.ShadowHDLighting + name: shadows + shadowstrength: 1.0 + # Night view (default moonight level is 4) + - class: org.dynmap.hdmap.ShadowHDLighting + name: night + shadowstrength: 1.0 + ambientlight: 4 + # A 'bright' night view (easier to see unlit landscape dimly) + - class: org.dynmap.hdmap.ShadowHDLighting + name: brightnight + shadowstrength: 1.0 + ambientlight: 8 + # Night and day view + - class: org.dynmap.hdmap.ShadowHDLighting + name: nightandday + shadowstrength: 1.0 + ambientlight: 4 + night-and-day: true + # 'Bright' Night and day view + - class: org.dynmap.hdmap.ShadowHDLighting + name: brightnightandday + shadowstrength: 1.0 + ambientlight: 8 + night-and-day: true diff --git a/shaders.txt b/shaders.txt index 3e75bb75..1d3148df 100644 --- a/shaders.txt +++ b/shaders.txt @@ -1,18 +1,36 @@ shaders: - - class: org.dynmap.hdmap.DefaultHDShader - name: classic - colorscheme: default + - class: org.dynmap.hdmap.DefaultHDShader + name: default + colorscheme: default - - class: org.dynmap.hdmap.DefaultHDShader - name: night - colorscheme: default - ambientlight: 4 - shadowstrength: 1.0 + - class: org.dynmap.hdmap.DefaultHDShader + name: ovocean + colorscheme: ovocean - - class: org.dynmap.hdmap.DefaultHDShader - name: daynight - colorscheme: default - ambientlight: 4 - shadowstrength: 1.0 - night-and-day: true - \ No newline at end of file + - class: org.dynmap.hdmap.DefaultHDShader + name: flames + colorscheme: flames + + - class: org.dynmap.hdmap.DefaultHDShader + name: sk89q + colorscheme: sk89q + + - class: org.dynmap.hdmap.DefaultHDShader + name: biome + biomecolored: biome + + - class: org.dynmap.hdmap.DefaultHDShader + name: temperature + biomecolored: temperature + + - class: org.dynmap.hdmap.DefaultHDShader + name: rainfall + biomecolored: rainfall + + - class: org.dynmap.hdmap.DefaultHDShader + name: no_transparency + colorscheme: default + transparency: false + + + \ No newline at end of file diff --git a/src/main/assembly/package.xml b/src/main/assembly/package.xml index 91a9506a..7e457682 100644 --- a/src/main/assembly/package.xml +++ b/src/main/assembly/package.xml @@ -29,7 +29,8 @@ configuration.txt shaders.txt - perspectives.txt + perspectives.txt + lightings.txt diff --git a/src/main/java/org/dynmap/DynmapPlugin.java b/src/main/java/org/dynmap/DynmapPlugin.java index 0bf23209..59a5df2a 100644 --- a/src/main/java/org/dynmap/DynmapPlugin.java +++ b/src/main/java/org/dynmap/DynmapPlugin.java @@ -48,6 +48,7 @@ public class DynmapPlugin extends JavaPlugin { public ConfigurationNode configuration; public ConfigurationNode shaderconfig; public ConfigurationNode perspectiveconfig; + public ConfigurationNode lightingsconfig; public HashSet enabledTriggers = new HashSet(); public PermissionProvider permissions; public ComponentManager componentManager = new ComponentManager(); @@ -86,6 +87,9 @@ public class DynmapPlugin extends JavaPlugin { org.bukkit.util.config.Configuration bukkitPerspectiveConfig = new org.bukkit.util.config.Configuration(new File(this.getDataFolder(), "perspectives.txt")); bukkitPerspectiveConfig.load(); perspectiveconfig = new ConfigurationNode(bukkitPerspectiveConfig); + org.bukkit.util.config.Configuration bukkitLightingsConfig = new org.bukkit.util.config.Configuration(new File(this.getDataFolder(), "lightings.txt")); + bukkitLightingsConfig.load(); + lightingsconfig = new ConfigurationNode(bukkitLightingsConfig); Log.verbose = configuration.getBoolean("verbose", true); @@ -99,7 +103,7 @@ public class DynmapPlugin extends JavaPlugin { playerList = new PlayerList(getServer(), getFile("hiddenplayers.txt"), configuration); playerList.load(); - mapManager = new MapManager(this, configuration, shaderconfig, perspectiveconfig); + mapManager = new MapManager(this, configuration, shaderconfig, perspectiveconfig, lightingsconfig); mapManager.startRendering(); loadWebserver(); diff --git a/src/main/java/org/dynmap/MapManager.java b/src/main/java/org/dynmap/MapManager.java index d4fb68a1..42a0c4fe 100644 --- a/src/main/java/org/dynmap/MapManager.java +++ b/src/main/java/org/dynmap/MapManager.java @@ -319,13 +319,15 @@ public class MapManager { } } - public MapManager(DynmapPlugin plugin, ConfigurationNode configuration, ConfigurationNode shadercfg, ConfigurationNode perspectivecfg) { + public MapManager(DynmapPlugin plugin, ConfigurationNode configuration, ConfigurationNode shadercfg, ConfigurationNode perspectivecfg, + ConfigurationNode lightingscfg) { plug_in = plugin; mapman = this; /* Initialize HD map manager */ hdmapman = new HDMapManager(); hdmapman.loadHDShaders(shadercfg); hdmapman.loadHDPerspectives(perspectivecfg); + hdmapman.loadHDLightings(lightingscfg); this.tileQueue = new AsynchronousQueue(new Handler() { @Override diff --git a/src/main/java/org/dynmap/hdmap/DefaultHDLighting.java b/src/main/java/org/dynmap/hdmap/DefaultHDLighting.java new file mode 100644 index 00000000..92b2fb8b --- /dev/null +++ b/src/main/java/org/dynmap/hdmap/DefaultHDLighting.java @@ -0,0 +1,54 @@ +package org.dynmap.hdmap; + +import java.util.HashSet; + +import org.dynmap.Color; +import org.dynmap.ColorScheme; +import org.dynmap.ConfigurationNode; +import org.dynmap.hdmap.DefaultHDShader.BiomeColorOption; +import org.json.simple.JSONObject; +import static org.dynmap.JSONUtils.s; + +public class DefaultHDLighting implements HDLighting { + private String name; + + public DefaultHDLighting(ConfigurationNode configuration) { + name = (String) configuration.get("name"); + } + + /* Get lighting name */ + public String getName() { return name; } + + /* 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) { + for(Color oc: outcolor) + oc.setColor(incolor); + } + + /* Test if Biome Data is needed for this renderer */ + public boolean isBiomeDataNeeded() { return false; } + + /* Test if raw biome temperature/rainfall data is needed */ + public boolean isRawBiomeDataNeeded() { return false; } + + /* Test if highest block Y data is needed */ + public boolean isHightestBlockYDataNeeded() { return false; } + + /* Tet if block type data needed */ + public boolean isBlockTypeDataNeeded() { return false; } + + /* Test if night/day is enabled for this renderer */ + public boolean isNightAndDayEnabled() { return false; } + + /* Test if sky light level needed */ + public boolean isSkyLightLevelNeeded() { return false; } + + /* Test if emitted light level needed */ + public boolean isEmittedLightLevelNeeded() { return false; } + + /* Add shader's contributions to JSON for map object */ + public void addClientConfiguration(JSONObject mapObject) { + s(mapObject, "lighting", name); + s(mapObject, "nightandday", isNightAndDayEnabled()); + } +} diff --git a/src/main/java/org/dynmap/hdmap/DefaultHDShader.java b/src/main/java/org/dynmap/hdmap/DefaultHDShader.java index ca4a5067..b2461da0 100644 --- a/src/main/java/org/dynmap/hdmap/DefaultHDShader.java +++ b/src/main/java/org/dynmap/hdmap/DefaultHDShader.java @@ -1,7 +1,6 @@ package org.dynmap.hdmap; import static org.dynmap.JSONUtils.s; -import java.util.HashSet; import org.bukkit.block.Biome; import org.dynmap.Color; import org.dynmap.ColorScheme; @@ -14,12 +13,6 @@ public class DefaultHDShader implements HDShader { private String name; protected ColorScheme colorScheme; - protected HashSet highlightBlocks = new HashSet(); - protected Color highlightColor = new Color(255, 0, 0); - - protected int shadowscale[]; /* index=skylight level, value = 256 * scaling value */ - protected int lightscale[]; /* scale skylight level (light = lightscale[skylight] */ - protected boolean night_and_day; /* If true, render both day (prefix+'-day') and night (prefix) tiles */ protected boolean transparency; /* Is transparency support active? */ public enum BiomeColorOption { NONE, BIOME, TEMPERATURE, RAINFALL @@ -28,30 +21,7 @@ public class DefaultHDShader implements HDShader { public DefaultHDShader(ConfigurationNode configuration) { name = (String) configuration.get("name"); - double shadowweight = configuration.getDouble("shadowstrength", 0.0); - if(shadowweight > 0.0) { - shadowscale = new int[16]; - shadowscale[15] = 256; - /* Normal brightness weight in MC is a 20% relative dropoff per step */ - for(int i = 14; i >= 0; i--) { - double v = shadowscale[i+1] * (1.0 - (0.2 * shadowweight)); - shadowscale[i] = (int)v; - if(shadowscale[i] > 256) shadowscale[i] = 256; - if(shadowscale[i] < 0) shadowscale[i] = 0; - } - } - int v = configuration.getInteger("ambientlight", -1); - if(v >= 0) { - lightscale = new int[16]; - for(int i = 0; i < 16; i++) { - if(i < (15-v)) - lightscale[i] = 0; - else - lightscale[i] = i - (15-v); - } - } colorScheme = ColorScheme.getScheme(configuration.getString("colorscheme", "default")); - night_and_day = configuration.getBoolean("night-and-day", false); transparency = configuration.getBoolean("transparency", true); /* Default on */ String biomeopt = configuration.getString("biomecolored", "none"); if(biomeopt.equals("biome")) { @@ -68,30 +38,60 @@ public class DefaultHDShader implements HDShader { } } - public boolean isBiomeDataNeeded() { return biomecolored == BiomeColorOption.BIOME; } - public boolean isRawBiomeDataNeeded() { return (biomecolored == BiomeColorOption.RAINFALL) || (biomecolored == BiomeColorOption.TEMPERATURE); }; - public boolean isNightAndDayEnabled() { return night_and_day; } - public boolean isSkyLightLevelNeeded() { return (lightscale != null); } - public boolean isEmittedLightLevelNeeded() { return (shadowscale != null); } - public boolean isHightestBlockYDataNeeded() { return false; } - public boolean isBlockTypeDataNeeded() { return true; } - - public String getName() { return name; } + @Override + public boolean isBiomeDataNeeded() { + return biomecolored == BiomeColorOption.BIOME; + } - private class OurRendererState implements HDShaderState { - private Color color = new Color(); - private Color daycolor; + @Override + public boolean isRawBiomeDataNeeded() { + return (biomecolored == BiomeColorOption.RAINFALL) || (biomecolored == BiomeColorOption.TEMPERATURE); + } + + @Override + public boolean isHightestBlockYDataNeeded() { + return false; + } + + @Override + public boolean isBlockTypeDataNeeded() { + return true; + } + + @Override + public boolean isSkyLightLevelNeeded() { + return false; + } + + @Override + public boolean isEmittedLightLevelNeeded() { + return false; + } + + @Override + public String getName() { + return name; + } + + private class OurShaderState implements HDShaderState { + private Color color[]; protected MapIterator mapiter; protected HDMap map; - private Color tmpcolor = new Color(); - private Color tmpdaycolor = new Color(); + private Color tmpcolor[]; private int pixelodd; + private HDLighting lighting; - private OurRendererState(MapIterator mapiter, HDMap map) { + private OurShaderState(MapIterator mapiter, HDMap map) { this.mapiter = mapiter; this.map = map; - if(night_and_day) { - daycolor = new Color(); + this.lighting = map.getLighting(); + if(lighting.isNightAndDayEnabled()) { + color = new Color[] { new Color(), new Color() }; + tmpcolor = new Color[] { new Color(), new Color() }; + } + else { + color = new Color[] { new Color() }; + tmpcolor = new Color[] { new Color() }; } } /** @@ -107,13 +107,18 @@ public class DefaultHDShader implements HDShader { public HDMap getMap() { return map; } + /** + * Get our lighting + */ + public HDLighting getLighting() { + return lighting; + } /** * Reset renderer state for new ray */ public void reset(HDPerspectiveState ps) { - color.setTransparent(); - if(daycolor != null) - daycolor.setTransparent(); + for(Color c: color) + c.setTransparent(); pixelodd = (ps.getPixelX() & 0x3) + (ps.getPixelY()<<1); } @@ -129,6 +134,7 @@ public class DefaultHDShader implements HDShader { * @return true if ray is done, false if ray needs to continue */ public boolean processBlock(HDPerspectiveState ps) { + int i; int blocktype = ps.getBlockTypeID(); if(blocktype == 0) return false; @@ -140,75 +146,44 @@ public class DefaultHDShader implements HDShader { switch(ps.getLastBlockStep()) { case X_PLUS: case X_MINUS: - seq = 1; + seq = 0; break; case Z_PLUS: case Z_MINUS: - seq = 3; + seq = 2; break; default: if(((pixelodd + mapiter.getY()) & 0x03) == 0) - seq = 2; + seq = 3; else - seq = 0; + seq = 1; break; } Color c = colors[seq]; if (c.getAlpha() > 0) { /* Handle light level, if needed */ - int lightlevel = 15, lightlevel_day = 15; - if(shadowscale != null) { - lightlevel = lightlevel_day = ps.getSkyLightLevel(); - if(lightscale != null) - lightlevel = lightscale[lightlevel]; - if((lightlevel < 15) || (lightlevel_day < 15)) { - int emitted = ps.getEmittedLightLevel(); - lightlevel = Math.max(emitted, lightlevel); - lightlevel_day = Math.max(emitted, lightlevel_day); - } - } - /* Figure out our color, with lighting if needed */ - tmpcolor.setColor(c); - if(lightlevel < 15) { - shadowColor(tmpcolor, lightlevel); - } - if(daycolor != null) { - if(lightlevel_day == lightlevel) { - tmpdaycolor.setColor(tmpcolor); - } - else { - tmpdaycolor.setColor(c); - if(lightlevel_day < 15) { - shadowColor(tmpdaycolor, lightlevel_day); - } - } - } + lighting.applyLighting(ps, this, c, tmpcolor); /* Blend color with accumulated color (weighted by alpha) */ if(!transparency) { /* No transparency support */ - color.setARGB(tmpcolor.getARGB() | 0xFF000000); - if(daycolor != null) - daycolor.setARGB(tmpdaycolor.getARGB() | 0xFF000000); + for(i = 0; i < color.length; i++) + color[i].setARGB(tmpcolor[i].getARGB() | 0xFF000000); return true; /* We're done */ } /* If no previous color contribution, use new color */ - else if(color.isTransparent()) { - color.setColor(tmpcolor); - if(daycolor != null) - daycolor.setColor(tmpdaycolor); - return (color.getAlpha() == 255); + else if(color[0].isTransparent()) { + for(i = 0; i < color.length; i++) + color[i].setColor(tmpcolor[i]); + return (color[0].getAlpha() == 255); } /* Else, blend and generate new alpha */ else { - int alpha = color.getAlpha(); - int alpha2 = tmpcolor.getAlpha() * (255-alpha) / 255; + int alpha = color[0].getAlpha(); + int alpha2 = tmpcolor[0].getAlpha() * (255-alpha) / 255; int talpha = alpha + alpha2; - color.setRGBA((tmpcolor.getRed()*alpha2 + color.getRed()*alpha) / talpha, - (tmpcolor.getGreen()*alpha2 + color.getGreen()*alpha) / talpha, - (tmpcolor.getBlue()*alpha2 + color.getBlue()*alpha) / talpha, talpha); - if(daycolor != null) - daycolor.setRGBA((tmpdaycolor.getRed()*alpha2 + daycolor.getRed()*alpha) / talpha, - (tmpdaycolor.getGreen()*alpha2 + daycolor.getGreen()*alpha) / talpha, - (tmpdaycolor.getBlue()*alpha2 + daycolor.getBlue()*alpha) / talpha, talpha); + for(i = 0; i < color.length; i++) + color[i].setRGBA((tmpcolor[i].getRed()*alpha2 + color[i].getRed()*alpha) / talpha, + (tmpcolor[i].getGreen()*alpha2 + color[i].getGreen()*alpha) / talpha, + (tmpcolor[i].getBlue()*alpha2 + color[i].getBlue()*alpha) / talpha, talpha); return (talpha >= 254); /* If only one short, no meaningful contribution left */ } } @@ -226,27 +201,17 @@ public class DefaultHDShader implements HDShader { * @param index - index of color to request (renderer specific - 0=default, 1=day for night/day renderer */ public void getRayColor(Color c, int index) { - if(index == 0) - c.setColor(color); - else if((index == 1) && (daycolor != null)) - c.setColor(daycolor); + c.setColor(color[index]); } /** * Clean up state object - called after last ray completed */ public void cleanup() { } - - private final void shadowColor(Color c, int lightlevel) { - int scale = shadowscale[lightlevel]; - if(scale < 256) - c.setRGBA((c.getRed() * scale) >> 8, (c.getGreen() * scale) >> 8, - (c.getBlue() * scale) >> 8, c.getAlpha()); - } } - private class OurBiomeRendererState extends OurRendererState { - private OurBiomeRendererState(MapIterator mapiter, HDMap map) { + private class OurBiomeShaderState extends OurShaderState { + private OurBiomeShaderState(MapIterator mapiter, HDMap map) { super(mapiter, map); } protected Color[] getBlockColors(int blocktype, int blockdata) { @@ -257,8 +222,8 @@ public class DefaultHDShader implements HDShader { } } - private class OurBiomeRainfallRendererState extends OurRendererState { - private OurBiomeRainfallRendererState(MapIterator mapiter, HDMap map) { + private class OurBiomeRainfallShaderState extends OurShaderState { + private OurBiomeRainfallShaderState(MapIterator mapiter, HDMap map) { super(mapiter, map); } protected Color[] getBlockColors(int blocktype, int blockdata) { @@ -266,8 +231,8 @@ public class DefaultHDShader implements HDShader { } } - private class OurBiomeTempRendererState extends OurRendererState { - private OurBiomeTempRendererState(MapIterator mapiter, HDMap map) { + private class OurBiomeTempShaderState extends OurShaderState { + private OurBiomeTempShaderState(MapIterator mapiter, HDMap map) { super(mapiter, map); } protected Color[] getBlockColors(int blocktype, int blockdata) { @@ -284,13 +249,13 @@ public class DefaultHDShader implements HDShader { public HDShaderState getStateInstance(HDMap map, MapChunkCache cache, MapIterator mapiter) { switch(biomecolored) { case NONE: - return new OurRendererState(mapiter, map); + return new OurShaderState(mapiter, map); case BIOME: - return new OurBiomeRendererState(mapiter, map); + return new OurBiomeShaderState(mapiter, map); case RAINFALL: - return new OurBiomeRainfallRendererState(mapiter, map); + return new OurBiomeRainfallShaderState(mapiter, map); case TEMPERATURE: - return new OurBiomeTempRendererState(mapiter, map); + return new OurBiomeTempShaderState(mapiter, map); } return null; } @@ -298,6 +263,5 @@ public class DefaultHDShader implements HDShader { /* Add shader's contributions to JSON for map object */ public void addClientConfiguration(JSONObject mapObject) { s(mapObject, "shader", name); - s(mapObject, "nightandday", night_and_day); } } diff --git a/src/main/java/org/dynmap/hdmap/HDLighting.java b/src/main/java/org/dynmap/hdmap/HDLighting.java new file mode 100644 index 00000000..11e572d8 --- /dev/null +++ b/src/main/java/org/dynmap/hdmap/HDLighting.java @@ -0,0 +1,29 @@ +package org.dynmap.hdmap; + +import org.dynmap.Color; +import org.dynmap.utils.MapChunkCache; +import org.dynmap.utils.MapIterator; +import org.json.simple.JSONObject; + +public interface HDLighting { + /* Get lighting name */ + String getName(); + /* Apply lighting to given pixel colors (1 outcolor if normal, 2 if night/day) */ + void applyLighting(HDPerspectiveState ps, HDShaderState ss, Color incolor, Color[] outcolor); + /* Test if Biome Data is needed for this renderer */ + boolean isBiomeDataNeeded(); + /* Test if raw biome temperature/rainfall data is needed */ + boolean isRawBiomeDataNeeded(); + /* Test if highest block Y data is needed */ + boolean isHightestBlockYDataNeeded(); + /* Tet if block type data needed */ + boolean isBlockTypeDataNeeded(); + /* Test if night/day is enabled for this renderer */ + boolean isNightAndDayEnabled(); + /* Test if sky light level needed */ + boolean isSkyLightLevelNeeded(); + /* Test if emitted light level needed */ + boolean isEmittedLightLevelNeeded(); + /* Add shader's contributions to JSON for map object */ + void addClientConfiguration(JSONObject mapObject); +} diff --git a/src/main/java/org/dynmap/hdmap/HDMap.java b/src/main/java/org/dynmap/hdmap/HDMap.java index 1113b448..0b8ff3d4 100644 --- a/src/main/java/org/dynmap/hdmap/HDMap.java +++ b/src/main/java/org/dynmap/hdmap/HDMap.java @@ -21,6 +21,7 @@ public class HDMap extends MapType { private String prefix; private HDPerspective perspective; private HDShader shader; + private HDLighting lighting; private ConfigurationNode configuration; public HDMap(ConfigurationNode configuration) { @@ -43,12 +44,20 @@ public class HDMap extends MapType { name = null; return; } + String lightingid = configuration.getString("lighting", "default"); + lighting = MapManager.mapman.hdmapman.lightings.get(lightingid); + if(lighting == null) { + Log.severe("HDMap '"+name+"' loading invalid lighting '" + lighting + "' - map disabled"); + name = null; + return; + } prefix = configuration.getString("prefix", name); this.configuration = configuration; } public HDShader getShader() { return shader; } public HDPerspective getPerspective() { return perspective; } + public HDLighting getLighting() { return lighting; } @Override public MapTile[] getTiles(Location loc) { @@ -77,7 +86,7 @@ public class HDMap extends MapType { public List baseZoomFilePrefixes() { ArrayList s = new ArrayList(); s.add(prefix); - if(shader.isNightAndDayEnabled()) + if(lighting.isNightAndDayEnabled()) s.add(prefix + "_day"); return s; } @@ -117,6 +126,7 @@ public class HDMap extends MapType { perspective.addClientConfiguration(o); shader.addClientConfiguration(o); + lighting.addClientConfiguration(o); a(worldObject, "maps", o); diff --git a/src/main/java/org/dynmap/hdmap/HDMapManager.java b/src/main/java/org/dynmap/hdmap/HDMapManager.java index 9ae2c875..590d76f3 100644 --- a/src/main/java/org/dynmap/hdmap/HDMapManager.java +++ b/src/main/java/org/dynmap/hdmap/HDMapManager.java @@ -20,16 +20,20 @@ import org.dynmap.utils.MapIterator; public class HDMapManager { public HashMap shaders = new HashMap(); public HashMap perspectives = new HashMap(); + public HashMap lightings = new HashMap(); public HashSet maps = new HashSet(); public HashMap> maps_by_world_perspective = new HashMap>(); public void loadHDShaders(ConfigurationNode shadercfg) { Log.verboseinfo("Loading shaders..."); for(HDShader shader : shadercfg.createInstances("shaders", new Class[0], new Object[0])) { + if(shader.getName() == null) continue; if(shaders.containsKey(shader.getName())) { Log.severe("Duplicate shader name '" + shader.getName() + "' - shader ignored"); } - shaders.put(shader.getName(), shader); + else { + shaders.put(shader.getName(), shader); + } } Log.info("Loaded " + shaders.size() + " shaders."); } @@ -37,14 +41,31 @@ public class HDMapManager { public void loadHDPerspectives(ConfigurationNode perspectivecfg) { Log.verboseinfo("Loading perspectives..."); for(HDPerspective perspective : perspectivecfg.createInstances("perspectives", new Class[0], new Object[0])) { + if(perspective.getName() == null) continue; if(perspectives.containsKey(perspective.getName())) { Log.severe("Duplicate perspective name '" + perspective.getName() + "' - perspective ignored"); } - perspectives.put(perspective.getName(), perspective); + else { + perspectives.put(perspective.getName(), perspective); + } } Log.info("Loaded " + perspectives.size() + " perspectives."); } + public void loadHDLightings(ConfigurationNode lightingcfg) { + Log.verboseinfo("Loading lightings..."); + for(HDLighting lighting : lightingcfg.createInstances("lightings", new Class[0], new Object[0])) { + if(lighting.getName() == null) continue; + if(lightings.containsKey(lighting.getName())) { + Log.severe("Duplicate lighting name '" + lighting.getName() + "' - lighting ignored"); + } + else { + lightings.put(lighting.getName(), lighting); + } + } + Log.info("Loaded " + lightings.size() + " lightings."); + } + /** * Initialize shader states for all shaders for given tile */ @@ -102,10 +123,11 @@ public class HDMapManager { HDMap hdmap = (HDMap)map; if(hdmap.getPerspective() == t.perspective) { HDShader sh = hdmap.getShader(); - flags[BIOMEDATAFLAG] |= sh.isBiomeDataNeeded(); - flags[HIGHESTZFLAG] |= sh.isHightestBlockYDataNeeded(); - flags[RAWBIOMEFLAG] |= sh.isRawBiomeDataNeeded(); - flags[BLOCKTYPEFLAG] |= sh.isBlockTypeDataNeeded(); + HDLighting lt = hdmap.getLighting(); + flags[BIOMEDATAFLAG] |= sh.isBiomeDataNeeded() | lt.isBiomeDataNeeded(); + flags[HIGHESTZFLAG] |= sh.isHightestBlockYDataNeeded() | lt.isHightestBlockYDataNeeded(); + flags[RAWBIOMEFLAG] |= sh.isRawBiomeDataNeeded() | lt.isRawBiomeDataNeeded(); + flags[BLOCKTYPEFLAG] |= sh.isBlockTypeDataNeeded() | lt.isBlockTypeDataNeeded(); } } } diff --git a/src/main/java/org/dynmap/hdmap/HDShader.java b/src/main/java/org/dynmap/hdmap/HDShader.java index be16442f..08ac8e0d 100644 --- a/src/main/java/org/dynmap/hdmap/HDShader.java +++ b/src/main/java/org/dynmap/hdmap/HDShader.java @@ -8,7 +8,7 @@ import org.dynmap.utils.MapIterator; import org.json.simple.JSONObject; public interface HDShader { - /* Get renderer name */ + /* Get shader name */ String getName(); /** * Get renderer state object for use rendering a tile @@ -26,8 +26,6 @@ public interface HDShader { boolean isHightestBlockYDataNeeded(); /* Tet if block type data needed */ boolean isBlockTypeDataNeeded(); - /* Test if night/day is enabled for this renderer */ - boolean isNightAndDayEnabled(); /* Test if sky light level needed */ boolean isSkyLightLevelNeeded(); /* Test if emitted light level needed */ diff --git a/src/main/java/org/dynmap/hdmap/HDShaderState.java b/src/main/java/org/dynmap/hdmap/HDShaderState.java index 6a2e7fba..151aeea4 100644 --- a/src/main/java/org/dynmap/hdmap/HDShaderState.java +++ b/src/main/java/org/dynmap/hdmap/HDShaderState.java @@ -12,6 +12,10 @@ public interface HDShaderState { * Get our shader */ HDShader getShader(); + /** + * Get our lighting + */ + HDLighting getLighting(); /** * Get our map */ diff --git a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java index 75a207a3..d4d96c1f 100644 --- a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java +++ b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java @@ -363,13 +363,14 @@ public class IsoHDPerspective implements HDPerspective { for(int i = 0; i < numshaders; i++) { HDShader shader = shaderstate[i].getShader(); - if(shader.isEmittedLightLevelNeeded()) + HDLighting lighting = shaderstate[i].getLighting(); + if(shader.isEmittedLightLevelNeeded() || lighting.isEmittedLightLevelNeeded()) need_emittedlightlevel = true; - if(shader.isSkyLightLevelNeeded()) + if(shader.isSkyLightLevelNeeded() || lighting.isSkyLightLevelNeeded()) need_skylightlevel = true; im[i] = KzedMap.allocateBufferedImage(tileWidth, tileHeight); argb_buf[i] = im[i].argb_buf; - if(shader.isNightAndDayEnabled()) { + if(lighting.isNightAndDayEnabled()) { dayim[i] = KzedMap.allocateBufferedImage(tileWidth, tileHeight); day_argb_buf[i] = dayim[i].argb_buf; } diff --git a/src/main/java/org/dynmap/hdmap/ShadowHDLighting.java b/src/main/java/org/dynmap/hdmap/ShadowHDLighting.java new file mode 100644 index 00000000..3f740280 --- /dev/null +++ b/src/main/java/org/dynmap/hdmap/ShadowHDLighting.java @@ -0,0 +1,99 @@ +package org.dynmap.hdmap; + +import static org.dynmap.JSONUtils.s; + +import org.dynmap.Color; +import org.dynmap.ConfigurationNode; +import org.dynmap.Log; +import org.json.simple.JSONObject; + +public class ShadowHDLighting extends DefaultHDLighting { + + protected int shadowscale[]; /* index=skylight level, value = 256 * scaling value */ + protected int lightscale[]; /* scale skylight level (light = lightscale[skylight] */ + protected boolean night_and_day; /* If true, render both day (prefix+'-day') and night (prefix) tiles */ + + public ShadowHDLighting(ConfigurationNode configuration) { + super(configuration); + double shadowweight = configuration.getDouble("shadowstrength", 0.0); + if(shadowweight > 0.0) { + shadowscale = new int[16]; + shadowscale[15] = 256; + /* Normal brightness weight in MC is a 20% relative dropoff per step */ + for(int i = 14; i >= 0; i--) { + double v = shadowscale[i+1] * (1.0 - (0.2 * shadowweight)); + shadowscale[i] = (int)v; + if(shadowscale[i] > 256) shadowscale[i] = 256; + if(shadowscale[i] < 0) shadowscale[i] = 0; + } + } + int v = configuration.getInteger("ambientlight", -1); + if((v >= 0) && (v < 15)) { + lightscale = new int[16]; + for(int i = 0; i < 16; i++) { + if(i < (15-v)) + lightscale[i] = 0; + else + lightscale[i] = i - (15-v); + } + } + night_and_day = configuration.getBoolean("night-and-day", false); + if(night_and_day) { + if(lightscale == null) { + Log.severe("night-and-day in lighting '" + getName() + "' requires ambientlight<15"); + night_and_day = false; + } + } + } + + /* 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 lightlevel = 15, lightlevel_day = 15; + /* If processing for shadows, use sky light level as base lighting */ + if(shadowscale != null) { + lightlevel = lightlevel_day = ps.getSkyLightLevel(); + } + /* If ambient light, adjust base lighting for it */ + if(lightscale != null) + lightlevel = lightscale[lightlevel]; + /* If we're below max, see if emitted light helps */ + if((lightlevel < 15) || (lightlevel_day < 15)) { + int emitted = ps.getEmittedLightLevel(); + 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); + } + 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); + } + } + } + } + + private final void shadowColor(Color c, int lightlevel) { + 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 (shadowscale != null); } + + /* Test if emitted light level needed */ + public boolean isEmittedLightLevelNeeded() { return (shadowscale != null) || (lightscale != null); } + +}