Get full existing shader function working on HDMap

This commit is contained in:
Mike Primm 2011-07-05 22:17:22 -05:00
parent f3f871df3c
commit 1f2722b249
7 changed files with 527 additions and 156 deletions

View File

@ -0,0 +1,297 @@
package org.dynmap.hdmap;
import static org.dynmap.JSONUtils.a;
import static org.dynmap.JSONUtils.s;
import java.io.File;
import java.util.HashSet;
import org.bukkit.block.Biome;
import org.dynmap.Color;
import org.dynmap.ColorScheme;
import org.dynmap.ConfigurationNode;
import org.dynmap.Log;
import org.dynmap.hdmap.HDMap.BlockStep;
import org.dynmap.kzedmap.KzedMapTile;
import org.dynmap.kzedmap.DefaultTileRenderer.BiomeColorOption;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator;
import org.json.simple.JSONObject;
public class DefaultHDShader implements HDShader {
private ConfigurationNode configuration;
private String name;
protected ColorScheme colorScheme;
protected HashSet<Integer> highlightBlocks = new HashSet<Integer>();
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
}
protected BiomeColorOption biomecolored = BiomeColorOption.NONE; /* Use biome for coloring */
public DefaultHDShader(ConfigurationNode configuration) {
this.configuration = configuration;
name = (String) configuration.get("prefix");
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((String)configuration.get("colorscheme"));
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")) {
biomecolored = BiomeColorOption.BIOME;
}
else if(biomeopt.equals("temperature")) {
biomecolored = BiomeColorOption.TEMPERATURE;
}
else if(biomeopt.equals("rainfall")) {
biomecolored = BiomeColorOption.RAINFALL;
}
else {
biomecolored = BiomeColorOption.NONE;
}
}
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 String getName() { return name; }
private class OurRendererState implements HDShaderState {
private Color color = new Color();
private Color daycolor;
protected MapIterator mapiter;
private int seqy; /* For dither */
private Color tmpcolor = new Color();
private Color tmpdaycolor = new Color();
private OurRendererState(MapIterator mapiter) {
this.mapiter = mapiter;
if(night_and_day) {
daycolor = new Color();
}
}
/**
* Reset renderer state for new ray
*/
public void reset(int x, int y) {
color.setTransparent();
if(daycolor != null)
daycolor.setTransparent();
if(((x+y) & 0x01) == 0x01)
seqy = 0;
else
seqy = 2;
}
protected Color[] getBlockColors(int blocktype, int blockdata) {
if((blockdata != 0) && (colorScheme.datacolors[blocktype] != null))
return colorScheme.datacolors[blocktype][blockdata];
else
return colorScheme.colors[blocktype];
}
/**
* Process next ray step - called for each block on route
* @param blocktype - block type of current block
* @param blockdata - data nibble of current block
* @param skylightlevel - sky light level of previous block (surface on current block)
* @param emittedlightlevel - emitted light level of previous block (surface on current block)
* @param laststep - direction of last step
* @return true if ray is done, false if ray needs to continue
*/
public boolean processBlock(int blocktype, int blockdata, int skylightlevel, int emittedlightlevel, HDMap.BlockStep laststep) {
if(blocktype == 0)
return false;
Color[] colors = getBlockColors(blocktype, blockdata);
if (colors != null) {
int seq;
/* Figure out which color to use */
if((laststep == BlockStep.X_PLUS) || (laststep == BlockStep.X_MINUS))
seq = 1;
else if((laststep == BlockStep.Z_PLUS) || (laststep == BlockStep.Z_MINUS))
seq = 3;
else
seq = seqy;
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 = skylightlevel;
if(lightscale != null)
lightlevel = lightscale[lightlevel];
if((lightlevel < 15) || (lightlevel_day < 15)) {
int emitted = emittedlightlevel;
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);
}
}
}
/* 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);
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, blend and generate new alpha */
else {
int alpha = color.getAlpha();
int alpha2 = tmpcolor.getAlpha() * (255-alpha) / 255;
color.setRGBA((tmpcolor.getRed()*alpha2 + color.getRed()*alpha) / 255,
(tmpcolor.getGreen()*alpha2 + color.getGreen()*alpha) / 255,
(tmpcolor.getBlue()*alpha2 + color.getBlue()*alpha) / 255, alpha+alpha2);
if(daycolor != null)
daycolor.setRGBA((tmpdaycolor.getRed()*alpha2 + daycolor.getRed()*alpha) / 255,
(tmpdaycolor.getGreen()*alpha2 + daycolor.getGreen()*alpha) / 255,
(tmpdaycolor.getBlue()*alpha2 + daycolor.getBlue()*alpha) / 255, alpha+alpha2);
return (alpha+alpha2) >= 254; /* If only one short, no meaningful contribution left */
}
}
}
return false;
}
/**
* Ray ended - used to report that ray has exited map (called if renderer has not reported complete)
*/
public void rayFinished() {
}
/**
* Get result color - get resulting color for ray
* @param c - object to store color value in
* @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);
}
/**
* 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) {
super(mapiter);
}
protected Color[] getBlockColors(int blocktype, int blockdata) {
Biome bio = mapiter.getBiome();
if(bio != null)
return colorScheme.biomecolors[bio.ordinal()];
return null;
}
}
private class OurBiomeRainfallRendererState extends OurRendererState {
private OurBiomeRainfallRendererState(MapIterator mapiter) {
super(mapiter);
}
protected Color[] getBlockColors(int blocktype, int blockdata) {
return colorScheme.getRainColor(mapiter.getRawBiomeRainfall());
}
}
private class OurBiomeTempRendererState extends OurRendererState {
private OurBiomeTempRendererState(MapIterator mapiter) {
super(mapiter);
}
protected Color[] getBlockColors(int blocktype, int blockdata) {
return colorScheme.getTempColor(mapiter.getRawBiomeTemperature());
}
}
/**
* Get renderer state object for use rendering a tile
* @param map - map being rendered
* @param cache - chunk cache containing data for tile to be rendered
* @param mapiter - iterator used when traversing rays in tile
* @return state object to use for all rays in tile
*/
public HDShaderState getStateInstance(HDMap map, MapChunkCache cache, MapIterator mapiter) {
switch(biomecolored) {
case NONE:
return new OurRendererState(mapiter);
case BIOME:
return new OurBiomeRendererState(mapiter);
case RAINFALL:
return new OurBiomeRainfallRendererState(mapiter);
case TEMPERATURE:
return new OurBiomeTempRendererState(mapiter);
}
return null;
}
@Override
public void buildClientConfiguration(JSONObject worldObject) {
ConfigurationNode c = configuration;
JSONObject o = new JSONObject();
s(o, "type", "HDMapType");
s(o, "name", c.getString("name"));
s(o, "title", c.getString("title"));
s(o, "icon", c.getString("icon"));
s(o, "prefix", c.getString("prefix"));
a(worldObject, "maps", o);
}
}

View File

@ -1,45 +0,0 @@
package org.dynmap.hdmap;
import static org.dynmap.JSONUtils.a;
import static org.dynmap.JSONUtils.s;
import java.io.File;
import org.dynmap.ColorScheme;
import org.dynmap.ConfigurationNode;
import org.dynmap.Log;
import org.dynmap.kzedmap.KzedMapTile;
import org.dynmap.kzedmap.DefaultTileRenderer.BiomeColorOption;
import org.dynmap.utils.MapChunkCache;
import org.json.simple.JSONObject;
public class DummyHDRenderer implements HDMapTileRenderer {
private ConfigurationNode configuration;
private String name;
public DummyHDRenderer(ConfigurationNode configuration) {
this.configuration = configuration;
name = (String) configuration.get("prefix");
}
public boolean isBiomeDataNeeded() { return false; }
public boolean isRawBiomeDataNeeded() { return false; };
public boolean isNightAndDayEnabled() { return false; }
public String getName() { return name; }
public boolean render(MapChunkCache cache, HDMapTile tile, File outputFile) {
Log.info("DummyHDRenderer(" + tile + ", " + outputFile.getPath());
return false;
}
@Override
public void buildClientConfiguration(JSONObject worldObject) {
ConfigurationNode c = configuration;
JSONObject o = new JSONObject();
s(o, "type", "HDMapType");
s(o, "name", c.getString("name"));
s(o, "title", c.getString("title"));
s(o, "icon", c.getString("icon"));
s(o, "prefix", c.getString("prefix"));
a(worldObject, "maps", o);
}
}

View File

@ -49,7 +49,16 @@ public class HDMap extends MapType {
public double azimuth; /* Angle in degrees from looking north (0), east (90), south (180), or west (270) */
public double inclination; /* Angle in degrees from horizontal (0) to vertical (90) */
public double scale; /* Scale - tile pixel widths per block */
public ColorScheme colorScheme;
/* Represents last step of movement of the ray */
public enum BlockStep {
X_PLUS,
Y_PLUS,
Z_PLUS,
X_MINUS,
Y_MINUS,
Z_MINUS
};
/* Coordinate space for tiles consists of a plane (X, Y), corresponding to the projection of each tile on to the
* plane of the bottom of the world (X positive to the right, Y positive to the top), with Z+ corresponding to the
* height above this plane on a vector towards the viewer). Logically, this makes the parallelogram representing the
@ -73,11 +82,13 @@ public class HDMap extends MapType {
public static final double MAX_SCALE = 64;
public static final double MIN_SCALE = 1;
private HDMapTileRenderer renderers[];
private HDShader shaders[];
private boolean need_skylightlevel = false;
private boolean need_emittedlightlevel = false;
private boolean need_biomedata = false;
private boolean need_rawbiomedata = false;
public HDMap(ConfigurationNode configuration) {
colorScheme = ColorScheme.getScheme(configuration.getString("colorscheme", "default"));
azimuth = configuration.getDouble("azimuth", 135.0); /* Get azimuth (default to classic kzed POV */
inclination = configuration.getDouble("inclination", 60.0);
if(inclination > MAX_INCLINATION) inclination = MAX_INCLINATION;
@ -111,11 +122,21 @@ public class HDMap extends MapType {
transform.multiply(coordswap);
map_to_world = transform;
Log.verboseinfo("Loading renderers for map '" + getClass().toString() + "'...");
List<HDMapTileRenderer> renderers = configuration.<HDMapTileRenderer>createInstances("renderers", new Class<?>[0], new Object[0]);
this.renderers = new HDMapTileRenderer[renderers.size()];
renderers.toArray(this.renderers);
Log.verboseinfo("Loaded " + renderers.size() + " renderers for map '" + getClass().toString() + "'.");
Log.verboseinfo("Loading shaders for map '" + getClass().toString() + "'...");
List<HDShader> shaders = configuration.<HDShader>createInstances("shaders", new Class<?>[0], new Object[0]);
this.shaders = new HDShader[shaders.size()];
shaders.toArray(this.shaders);
Log.verboseinfo("Loaded " + shaders.size() + " shaders for map '" + getClass().toString() + "'.");
for(HDShader shader : shaders) {
if(shader.isBiomeDataNeeded())
need_biomedata = true;
if(shader.isEmittedLightLevelNeeded())
need_emittedlightlevel = true;
if(shader.isSkyLightLevelNeeded())
need_skylightlevel = true;
if(shader.isRawBiomeDataNeeded())
need_rawbiomedata = true;
}
}
@Override
@ -156,16 +177,14 @@ public class HDMap extends MapType {
int x = t.tx;
int y = t.ty;
return new MapTile[] {
new HDMapTile(w, this, t.renderer, x, y - 1),
new HDMapTile(w, this, t.renderer, x + 1, y),
new HDMapTile(w, this, t.renderer, x, y + 1),
new HDMapTile(w, this, t.renderer, x - 1, y) };
new HDMapTile(w, this, x, y - 1),
new HDMapTile(w, this, x + 1, y),
new HDMapTile(w, this, x, y + 1),
new HDMapTile(w, this, x - 1, y) };
}
public void addTile(HashSet<MapTile> tiles, DynmapWorld world, int tx, int ty) {
for (int i = 0; i < renderers.length; i++) {
tiles.add(new HDMapTile(world, this, renderers[i], tx, ty));
}
tiles.add(new HDMapTile(world, this, tx, ty));
}
public void invalidateTile(MapTile tile) {
@ -312,82 +331,118 @@ public class HDMap extends MapType {
}
@Override
public boolean render(MapChunkCache cache, MapTile tile, File outputFile) {
public boolean render(MapChunkCache cache, MapTile tile, File bogus) {
HDMapTile t = (HDMapTile) tile;
World w = t.getWorld();
boolean rendered = false;
Color rslt = new Color();
int[] pixel = new int[4];
KzedBufferedImage im = KzedMap.allocateBufferedImage(tileWidth, tileHeight);
int[] argb_buf = im.argb_buf;
MapIterator mapiter = cache.getIterator(0, 0, 0);
/* Build shader state object for each shader */
HDShaderState[] shaderstate = new HDShaderState[shaders.length];
for(int i = 0; i < shaders.length; i++) {
shaderstate[i] = shaders[i].getStateInstance(this, cache, mapiter);
if(shaders[i].isEmittedLightLevelNeeded())
need_emittedlightlevel = true;
if(shaders[i].isSkyLightLevelNeeded())
need_skylightlevel = true;
}
/* Create buffered image for each */
KzedBufferedImage im[] = new KzedBufferedImage[shaders.length];
KzedBufferedImage dayim[] = new KzedBufferedImage[shaders.length];
int[][] argb_buf = new int[shaders.length][];
int[][] day_argb_buf = new int[shaders.length][];
for(int i = 0; i < shaders.length; i++) {
im[i] = KzedMap.allocateBufferedImage(tileWidth, tileHeight);
argb_buf[i] = im[i].argb_buf;
if(shaders[i].isNightAndDayEnabled()) {
dayim[i] = KzedMap.allocateBufferedImage(tileWidth, tileHeight);
day_argb_buf[i] = dayim[i].argb_buf;
}
}
Vector3D top = new Vector3D();
Vector3D bottom = new Vector3D();
double xbase = t.tx * tileWidth;
double ybase = t.ty * tileHeight;
boolean odd = false;
boolean shaderdone[] = new boolean[shaders.length];
boolean rendered[] = new boolean[shaders.length];
for(int x = 0; x < tileWidth; x++) {
for(int y = 0; y < tileHeight; y++) {
top.x = bottom.x = xbase + x + 0.5; /* Start at center of pixel at Y=127.5, bottom at Y=-0.5 */
top.y = bottom.y = ybase + y + 0.5;
top.z = 127.5; bottom.z = -0.5;
map_to_world.transform(top); /* Transform to world coordinates */
map_to_world.transform(bottom);
raytrace(cache, mapiter, top, bottom, rslt, odd);
argb_buf[(tileHeight-y-1)*tileWidth + x] = rslt.getARGB();
rendered = true;
odd = !odd;
map_to_world.transform(bottom);
for(int i = 0; i < shaders.length; i++) {
shaderstate[i].reset(x, y);
}
raytrace(cache, mapiter, top, bottom, shaderstate, shaderdone);
for(int i = 0; i < shaders.length; i++) {
if(shaderdone[i] == false) {
shaderstate[i].rayFinished();
}
else {
shaderdone[i] = false;
rendered[i] = true;
}
shaderstate[i].getRayColor(rslt, 0);
argb_buf[i][(tileHeight-y-1)*tileWidth + x] = rslt.getARGB();
if(day_argb_buf[i] != null) {
shaderstate[i].getRayColor(rslt, 1);
day_argb_buf[i][(tileHeight-y-1)*tileWidth + x] = rslt.getARGB();
}
}
}
odd = !odd;
}
boolean renderedone = false;
/* Test to see if we're unchanged from older tile */
TileHashManager hashman = MapManager.mapman.hashman;
long crc = hashman.calculateTileHash(argb_buf);
boolean tile_update = false;
FileLockManager.getWriteLock(outputFile);
try {
if((!outputFile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), null, t.tx, t.ty))) {
/* Wrap buffer as buffered image */
Debug.debug("saving image " + outputFile.getPath());
if(!outputFile.getParentFile().exists())
outputFile.getParentFile().mkdirs();
for(int i = 0; i < shaders.length; i++) {
long crc = hashman.calculateTileHash(argb_buf[i]);
boolean tile_update = false;
String shadername = shaders[i].getName();
if(rendered[i]) {
File f = new File(t.getDynmapWorld().worldtilepath, t.getFilename(shadername));
FileLockManager.getWriteLock(f);
try {
FileLockManager.imageIOWrite(im.buf_img, "png", outputFile);
} catch (IOException e) {
Debug.error("Failed to save image: " + outputFile.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + outputFile.getPath(), e);
if((!f.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), shadername, t.tx, t.ty))) {
/* Wrap buffer as buffered image */
Debug.debug("saving image " + f.getPath());
if(!f.getParentFile().exists())
f.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(im[i].buf_img, "png", f);
} catch (IOException e) {
Debug.error("Failed to save image: " + f.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + f.getPath(), e);
}
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(f.getPath()));
hashman.updateHashCode(tile.getKey(), shadername, t.tx, t.ty, crc);
tile.getDynmapWorld().enqueueZoomOutUpdate(f);
tile_update = true;
}
else {
Debug.debug("skipping image " + f.getPath() + " - hash match");
}
} finally {
FileLockManager.releaseWriteLock(f);
renderedone = true;
KzedMap.freeBufferedImage(im[i]);
if(dayim[i] != null)
KzedMap.freeBufferedImage(dayim[i]);
}
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getFilename()));
hashman.updateHashCode(tile.getKey(), null, t.tx, t.ty, crc);
tile.getDynmapWorld().enqueueZoomOutUpdate(outputFile);
tile_update = true;
}
else {
Debug.debug("skipping image " + outputFile.getPath() + " - hash match");
}
} finally {
FileLockManager.releaseWriteLock(outputFile);
KzedMap.freeBufferedImage(im);
MapManager.mapman.updateStatistics(tile, shadername, true, tile_update, !rendered[i]);
}
MapManager.mapman.updateStatistics(tile, null, true, tile_update, !rendered);
return rendered;
return renderedone;
}
public enum BlockStep {
X_PLUS,
Y_PLUS,
Z_PLUS,
X_MINUS,
Y_MINUS,
Z_MINUS
};
/**
* Trace ray, based on "Voxel Tranversal along a 3D line"
*/
private void raytrace(MapChunkCache cache, MapIterator mapiter, Vector3D top, Vector3D bottom, Color rslt, boolean odd) {
private void raytrace(MapChunkCache cache, MapIterator mapiter, Vector3D top, Vector3D bottom,
HDShaderState[] shaderstate, boolean[] shaderdone) {
/* Compute total delta on each axis */
double dx = Math.abs(bottom.x - top.x);
double dy = Math.abs(bottom.y - top.y);
@ -459,23 +514,28 @@ public class HDMap extends MapType {
t_next_z = (top.z - Math.floor(top.z)) * dt_dz;
}
/* Walk through scene */
rslt.setTransparent();
BlockStep laststep = BlockStep.Y_MINUS; /* Last step is down into map */
mapiter.initialize(x, y, z);
int sky_lightlevel = 15;
int emitted_lightlevel = 15;
for (; n > 0; --n) {
int blocktype = mapiter.getBlockTypeID();
if(blocktype != 0) {
Color[] clr = colorScheme.colors[blocktype];
if(clr != null) {
if(laststep == BlockStep.Y_MINUS)
rslt.setColor(odd?clr[0]:clr[2]);
else if((laststep == BlockStep.X_PLUS) || (laststep == BlockStep.X_MINUS))
rslt.setColor(clr[1]);
else
rslt.setColor(clr[3]);
int blockdata = mapiter.getBlockData();
boolean done = true;
for(int i = 0; i < shaderstate.length; i++) {
if(!shaderdone[i])
shaderdone[i] = shaderstate[i].processBlock(blocktype, blockdata, sky_lightlevel, emitted_lightlevel, laststep);
done = done && shaderdone[i];
}
return;
/* If all are done, we're out */
if(done)
return;
}
if(need_skylightlevel)
sky_lightlevel = mapiter.getBlockSkyLight();
if(need_emittedlightlevel)
emitted_lightlevel = mapiter.getBlockEmittedLight();
/* If X step is next best */
if((t_next_x <= t_next_y) && (t_next_x <= t_next_z)) {
x += x_inc;
@ -527,19 +587,21 @@ public class HDMap extends MapType {
@Override
public boolean isBiomeDataNeeded() {
return false;
return need_biomedata;
}
@Override
public boolean isRawBiomeDataNeeded() {
return false;
return need_rawbiomedata;
}
@Override
public List<String> baseZoomFilePrefixes() {
ArrayList<String> s = new ArrayList<String>();
for(HDMapTileRenderer r : renderers) {
for(HDShader r : shaders) {
s.add(r.getName());
if(r.isNightAndDayEnabled())
s.add(r.getName() + "_day");
}
return s;
}
@ -562,8 +624,8 @@ public class HDMap extends MapType {
@Override
public void buildClientConfiguration(JSONObject worldObject) {
for(HDMapTileRenderer renderer : renderers) {
renderer.buildClientConfiguration(worldObject);
for(HDShader shader : shaders) {
shader.buildClientConfiguration(worldObject);
}
}
}

View File

@ -6,31 +6,33 @@ import org.dynmap.MapTile;
public class HDMapTile extends MapTile {
public HDMap map;
public HDMapTileRenderer renderer;
public int tx, ty; /* Tile X and Tile Y are in tile coordinates (pixels/tile-size) */
private String fname;
public HDMapTile(DynmapWorld world, HDMap map, HDMapTileRenderer renderer, int tx, int ty) {
public HDMapTile(DynmapWorld world, HDMap map, int tx, int ty) {
super(world, map);
this.map = map;
this.renderer = renderer;
this.tx = tx;
this.ty = ty;
}
@Override
public String getFilename() {
if(fname == null) {
fname = renderer.getName() + "/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + ".png";
}
return fname;
return getFilename("hdmap");
}
public String getFilename(String shader) {
return shader + "/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + ".png";
}
@Override
public String getDayFilename() {
return getFilename();
return getDayFilename("hdmap");
}
public String getDayFilename(String shader) {
return shader + "_day/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + ".png";
}
@Override
public int hashCode() {
return getFilename().hashCode() ^ getWorld().hashCode();
@ -45,11 +47,11 @@ public class HDMapTile extends MapTile {
}
public boolean equals(HDMapTile o) {
return o.tx == tx && o.ty == ty && o.renderer == o.renderer && o.getWorld().equals(getWorld());
return o.tx == tx && o.ty == ty && o.getWorld().equals(getWorld());
}
public String getKey() {
return getWorld().getName() + "." + renderer.getName();
return getWorld().getName() + ".hdmap";
}
public String toString() {

View File

@ -1,19 +0,0 @@
package org.dynmap.hdmap;
import java.io.File;
import org.dynmap.utils.MapChunkCache;
import org.json.simple.JSONObject;
public interface HDMapTileRenderer {
String getName();
boolean render(MapChunkCache cache, HDMapTile tile, File outputFile);
void buildClientConfiguration(JSONObject worldObject);
boolean isBiomeDataNeeded();
boolean isRawBiomeDataNeeded();
boolean isNightAndDayEnabled();
}

View File

@ -0,0 +1,34 @@
package org.dynmap.hdmap;
import java.io.File;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator;
import org.json.simple.JSONObject;
public interface HDShader {
/* Get renderer name */
String getName();
/**
* Get renderer state object for use rendering a tile
* @param map - map being rendered
* @param cache - chunk cache containing data for tile to be rendered
* @param mapiter - iterator used when traversing rays in tile
* @return state object to use for all rays in tile
*/
HDShaderState getStateInstance(HDMap map, MapChunkCache cache, MapIterator mapiter);
/* Build client configuration for this render instance */
void buildClientConfiguration(JSONObject worldObject);
/* Test if Biome Data is needed for this renderer */
boolean isBiomeDataNeeded();
/* Test if raw biome temperature/rainfall data is needed */
boolean isRawBiomeDataNeeded();
/* 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();
}

View File

@ -0,0 +1,40 @@
package org.dynmap.hdmap;
import org.dynmap.Color;
import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.MapIterator;
/**
* This interface is used to define the operational state of a renderer during raytracing
* All method should be considered performance critical
*/
public interface HDShaderState {
/**
* Reset renderer state for new ray - passes in pixel coordinate for ray
*/
void reset(int x, int y);
/**
* Process next ray step - called for each block on route
* @param blocktype - block type of current block
* @param blockdata - data nibble of current block
* @param skylightlevel - sky light level of previous block (surface on current block)
* @param emittedlightlevel - emitted light level of previous block (surface on current block)
* @param laststep - direction of last step
* @return true if ray is done, false if ray needs to continue
*/
boolean processBlock(int blocktype, int blockdata, int skylightlevel, int emittedlightlevel, HDMap.BlockStep laststep);
/**
* Ray ended - used to report that ray has exited map (called if renderer has not reported complete)
*/
void rayFinished();
/**
* Get result color - get resulting color for ray
* @param c - object to store color value in
* @param index - index of color to request (renderer specific - 0=default, 1=day for night/day renderer
*/
void getRayColor(Color c, int index);
/**
* Clean up state object - called after last ray completed
*/
void cleanup();
}