From 9bdf13e46022c6b2309073c68e351745af3961a3 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Sat, 10 Dec 2011 08:20:42 +0800 Subject: [PATCH] Add TopoHDShader for generating altitude based topology maps --- .../org/dynmap/hdmap/IsoHDPerspective.java | 6 +- .../java/org/dynmap/hdmap/TopoHDShader.java | 236 ++++++++++++++++++ src/main/resources/shaders.txt | 16 ++ 3 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/dynmap/hdmap/TopoHDShader.java diff --git a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java index a2d24851..771bc918 100644 --- a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java +++ b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java @@ -1019,11 +1019,13 @@ public class IsoHDPerspective implements HDPerspective { Vector3D corners[] = new Vector3D[8]; int[] chunk_x = new int[8]; int[] chunk_z = new int[8]; + int dx = -1, dy = -1; for(int x = t.tx, idx = 0; x <= (t.tx+1); x++) { + dy = -1; for(int y = t.ty; y <= (t.ty+1); y++) { for(int z = 0; z <= 1; z++) { corners[idx] = new Vector3D(); - corners[idx].x = x*tileWidth; corners[idx].y = y*tileHeight; corners[idx].z = z*128; + corners[idx].x = x*tileWidth + dx; corners[idx].y = y*tileHeight + dy; corners[idx].z = z*128; map_to_world.transform(corners[idx]); /* Compute chunk coordinates of corner */ chunk_x[idx] = (int)Math.floor(corners[idx].x / 16); @@ -1035,7 +1037,9 @@ public class IsoHDPerspective implements HDPerspective { if(max_chunk_z < chunk_z[idx]) max_chunk_z = chunk_z[idx]; idx++; } + dy = 1; } + dx = 1; } /* Make rectangles of X-Z projection of each side of the tile volume, 0 = top, 1 = bottom, 2 = left, 3 = right, * 4 = upper, 5 = lower */ diff --git a/src/main/java/org/dynmap/hdmap/TopoHDShader.java b/src/main/java/org/dynmap/hdmap/TopoHDShader.java new file mode 100644 index 00000000..02dbce18 --- /dev/null +++ b/src/main/java/org/dynmap/hdmap/TopoHDShader.java @@ -0,0 +1,236 @@ +package org.dynmap.hdmap; + +import static org.dynmap.JSONUtils.s; + +import org.bukkit.World.Environment; +import org.dynmap.Color; +import org.dynmap.ConfigurationNode; +import org.dynmap.Log; +import org.dynmap.MapManager; +import org.dynmap.utils.MapChunkCache; +import org.dynmap.utils.MapIterator; +import org.dynmap.utils.MapIterator.BlockStep; +import org.json.simple.JSONObject; + +public class TopoHDShader implements HDShader { + private String name; + private Color linecolor; /* Color for topo lines */ + private Color fillcolor[]; /* Color for nontopo surfaces */ + private Color watercolor; + + private Color readColor(String id, ConfigurationNode cfg) { + String lclr = cfg.getString(id, null); + if((lclr != null) && (lclr.startsWith("#"))) { + try { + int c = Integer.parseInt(lclr.substring(1), 16); + return new Color((c>>16)&0xFF, (c>>8)&0xFF, c&0xFF); + } catch (NumberFormatException nfx) { + Log.severe("Invalid color value: " + lclr + " for '" + id + "'"); + } + } + return null; + } + public TopoHDShader(ConfigurationNode configuration) { + name = (String) configuration.get("name"); + + fillcolor = new Color[128]; /* Color by Y */ + /* Load defined colors from parameters */ + for(int i = 0; i < 128; i++) { + fillcolor[i] = readColor("color" + i, configuration); + } + linecolor = readColor("linecolor", configuration); + watercolor = readColor("watercolor", configuration); + /* Now, interpolate missing colors */ + if(fillcolor[0] == null) { + fillcolor[0] = new Color(0, 0, 0); + } + if(fillcolor[127] == null) { + fillcolor[127] = new Color(255, 255, 255); + } + int starty = 0; + for(int i = 1; i < 128; i++) { + if(fillcolor[i] != null) { /* Found color? */ + int delta = i - starty; + Color c0 = fillcolor[starty]; + Color c1 = fillcolor[i]; + /* Interpolate missing colors since last one */ + for(int j = 1; j < delta; j++) { + fillcolor[starty + j] = new Color((c0.getRed()*(delta-j) + c1.getRed()*j)/delta, (c0.getGreen()*(delta-j) + c1.getGreen()*j)/delta, (c0.getBlue()*(delta-j) + c1.getBlue()*j)/delta); + } + starty = i; /* New start color */ + } + } + } + + @Override + public boolean isBiomeDataNeeded() { + return false; + } + + @Override + public boolean isRawBiomeDataNeeded() { + return false; + } + + @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[]; + private Color tmpcolor[]; + private Color c; + protected MapIterator mapiter; + protected HDMap map; + private HDLighting lighting; + private int scale; + + private OurShaderState(MapIterator mapiter, HDMap map, MapChunkCache cache) { + this.mapiter = mapiter; + this.map = map; + 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() }; + } + scale = (int)map.getPerspective().getScale(); + c = new Color(); + } + /** + * Get our shader + */ + public HDShader getShader() { + return TopoHDShader.this; + } + + /** + * Get our map + */ + public HDMap getMap() { + return map; + } + + /** + * Get our lighting + */ + public HDLighting getLighting() { + return lighting; + } + + /** + * Reset renderer state for new ray + */ + public void reset(HDPerspectiveState ps) { + for(int i = 0; i < color.length; i++) + color[i].setTransparent(); + } + + /** + * Process next ray step - called for each block on route + * @return true if ray is done, false if ray needs to continue + */ + public boolean processBlock(HDPerspectiveState ps) { + int blocktype = ps.getBlockTypeID(); + + if(blocktype == 0) { + return false; + } + /* See if we're close to an edge */ + int[] xyz = ps.getSubblockCoord(); + /* See which face we're on (only do lines on top face) */ + switch(ps.getLastBlockStep()) { + case Y_MINUS: + case Y_PLUS: + if((linecolor != null) && + (((xyz[0] == 0) && (mapiter.getBlockTypeIDAt(BlockStep.X_MINUS) == 0)) || + ((xyz[0] == (scale-1)) && (mapiter.getBlockTypeIDAt(BlockStep.X_PLUS) == 0)) || + ((xyz[2] == 0) && (mapiter.getBlockTypeIDAt(BlockStep.Z_MINUS) == 0)) || + ((xyz[2] == (scale-1)) && (mapiter.getBlockTypeIDAt(BlockStep.Z_PLUS) == 0)))) { + c.setColor(linecolor); + } + else if((watercolor != null) && ((blocktype == 8) || (blocktype == 9))) { + c.setColor(watercolor); + } + else { + c.setColor(fillcolor[mapiter.getY()]); + } + break; + default: + if((linecolor != null) && (xyz[1] == (scale-1))) + c.setColor(linecolor); + else if((watercolor != null) && ((blocktype == 8) || (blocktype == 9))) { + c.setColor(watercolor); + } + else + c.setColor(fillcolor[mapiter.getY()]); + break; + } + /* Handle light level, if needed */ + lighting.applyLighting(ps, this, c, tmpcolor); + + for(int i = 0; i < color.length; i++) + color[i] = tmpcolor[i]; + + return true; + } + /** + * Ray ended - used to report that ray has exited map (called if renderer has not reported complete) + */ + public void rayFinished(HDPerspectiveState ps) { + } + /** + * 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) { + c.setColor(color[index]); + } + /** + * Clean up state object - called after last ray completed + */ + public void cleanup() { + } + } + + /** + * 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) { + return new OurShaderState(mapiter, map, cache); + } + + /* Add shader's contributions to JSON for map object */ + public void addClientConfiguration(JSONObject mapObject) { + s(mapObject, "shader", name); + } +} diff --git a/src/main/resources/shaders.txt b/src/main/resources/shaders.txt index e13fae30..e0d86c5a 100644 --- a/src/main/resources/shaders.txt +++ b/src/main/resources/shaders.txt @@ -58,3 +58,19 @@ shaders: name: stdtexture-nobiome texturepack: standard biomeshaded: false + + # Topological map shader + - class: org.dynmap.hdmap.TopoHDShader + name: topo + color127: "#FFFFFF" + color111: "#8B4513" + color95: "#D2B48C" + color79: "#FFFF00" + color63: "#008000" + color47: "#228B22" + color31: "#104010" + color15: "#6B8E23" + color0: "#696969" + linecolor: "#000000" + watercolor: "#0000FF" + \ No newline at end of file