diff --git a/src/main/assembly/package.xml b/src/main/assembly/package.xml
index 6335a1fd..94ef0e8c 100644
--- a/src/main/assembly/package.xml
+++ b/src/main/assembly/package.xml
@@ -32,7 +32,8 @@
perspectives.txt
lightings.txt
configuration.txt.sample-hd
- models.txt
+ models.txt
+ texture.txt
diff --git a/src/main/java/org/dynmap/hdmap/TexturePack.java b/src/main/java/org/dynmap/hdmap/TexturePack.java
index 08bc1fb7..a114dfd4 100644
--- a/src/main/java/org/dynmap/hdmap/TexturePack.java
+++ b/src/main/java/org/dynmap/hdmap/TexturePack.java
@@ -4,9 +4,14 @@ import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
+import java.io.LineNumberReader;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -15,6 +20,7 @@ import javax.imageio.ImageIO;
import org.dynmap.Color;
import org.dynmap.DynmapPlugin;
import org.dynmap.Log;
+import org.dynmap.hdmap.HDPerspectiveState.BlockStep;
import org.dynmap.kzedmap.KzedMap;
/**
@@ -56,6 +62,47 @@ public class TexturePack {
private HashMap scaled_textures;
+
+ public static class HDTextureMap {
+ private short faces[]; /* index in terrain.png of image for each face (indexed by BlockStep.ordinal()) */
+ private List blockids;
+ private int databits;
+ private static HDTextureMap[] texmaps;
+
+ private static void initializeTable() {
+ texmaps = new HDTextureMap[16*256];
+ HDTextureMap blank = new HDTextureMap();
+ for(int i = 0; i < texmaps.length; i++)
+ texmaps[i] = blank;
+ }
+
+ private HDTextureMap() {
+ blockids = Collections.singletonList(Integer.valueOf(0));
+ databits = 0xFFFF;
+ faces = new short[] { -1, -1, -1, -1, -1, -1 };
+
+ for(int i = 0; i < texmaps.length; i++) {
+ texmaps[i] = this;
+ }
+ }
+
+ public HDTextureMap(List blockids, int databits, short[] faces) {
+ this.faces = faces;
+ this.blockids = blockids;
+ this.databits = databits;
+ }
+
+ public void addToTable() {
+ /* Add entries to lookup table */
+ for(Integer blkid : blockids) {
+ for(int i = 0; i < 16; i++) {
+ if((databits & (1 << i)) != 0) {
+ texmaps[16*blkid + i] = this;
+ }
+ }
+ }
+ }
+ }
/** Get or load texture pack */
public static TexturePack getTexturePack(String tpname) {
TexturePack tp = packs.get(tpname);
@@ -378,6 +425,96 @@ public class TexturePack {
BufferedImage img = KzedMap.createBufferedImage(terrain_argb, terrain_width, terrain_height);
ImageIO.write(img, "png", f);
}
+
+ /**
+ * Load texture pack mappings from texture.txt file
+ */
+ public static void loadTextureMapping(File plugindir) {
+ LineNumberReader rdr = null;
+ int cnt = 0;
+ /* Initialize map with blank map for all entries */
+ HDTextureMap.initializeTable();
+
+ try {
+ String line;
+ rdr = new LineNumberReader(new FileReader(new File(plugindir, "texture.txt")));
+ while((line = rdr.readLine()) != null) {
+ if(line.startsWith("block:")) {
+ ArrayList blkids = new ArrayList();
+ int databits = 0;
+ short faces[] = new short[] { -1, -1, -1, -1, -1, -1 };
+ line = line.substring(6);
+ String[] args = line.split(",");
+ for(String a : args) {
+ String[] av = a.split("=");
+ if(av.length < 2) continue;
+ if(av[0].equals("id")) {
+ blkids.add(Integer.parseInt(av[1]));
+ }
+ else if(av[0].equals("data")) {
+ if(av[1].equals("*"))
+ databits = 0xFFFF;
+ else
+ databits |= (1 << Integer.parseInt(av[1]));
+ }
+ else if(av[0].equals("top") || av[0].equals("y-")) {
+ faces[BlockStep.Y_MINUS.ordinal()] = Short.parseShort(av[1]);
+ }
+ else if(av[0].equals("bottom") || av[0].equals("y+")) {
+ faces[BlockStep.Y_PLUS.ordinal()] = Short.parseShort(av[1]);
+ }
+ else if(av[0].equals("north") || av[0].equals("x+")) {
+ faces[BlockStep.X_PLUS.ordinal()] = Short.parseShort(av[1]);
+ }
+ else if(av[0].equals("east") || av[0].equals("z-")) {
+ faces[BlockStep.Z_MINUS.ordinal()] = Short.parseShort(av[1]);
+ }
+ else if(av[0].equals("west") || av[0].equals("z+")) {
+ faces[BlockStep.Z_PLUS.ordinal()] = Short.parseShort(av[1]);
+ }
+ else if(av[0].equals("allfaces")) {
+ short id = Short.parseShort(av[1]);
+ for(int i = 0; i < 6; i++) {
+ faces[i] = id;
+ }
+ }
+ else if(av[0].equals("allsides")) {
+ short id = Short.parseShort(av[1]);
+ faces[BlockStep.X_PLUS.ordinal()] = id;
+ faces[BlockStep.X_MINUS.ordinal()] = id;
+ faces[BlockStep.Z_PLUS.ordinal()] = id;
+ faces[BlockStep.Z_MINUS.ordinal()] = id;
+ }
+ }
+ /* If we have everything, build block */
+ if((blkids.size() > 0) && (databits != 0)) {
+ HDTextureMap map = new HDTextureMap(blkids, databits, faces);
+ map.addToTable();
+ cnt++;
+ }
+ else {
+ Log.severe("Texture mapping missing required parameters = line " + rdr.getLineNumber() + " of texture.txt");
+ }
+ }
+ else if(line.startsWith("#") || line.startsWith(";")) {
+ }
+ }
+ Log.info("Loaded " + cnt + " texture mappings");
+ } catch (IOException iox) {
+ Log.severe("Error reading texture.txt - " + iox.toString());
+ } catch (NumberFormatException nfx) {
+ Log.severe("Format error - line " + rdr.getLineNumber() + " of texture.txt");
+ } finally {
+ if(rdr != null) {
+ try {
+ rdr.close();
+ rdr = null;
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
public static void main(String[] args) {
TexturePack tp = TexturePack.getTexturePack("test");
TexturePack tp2 = tp.resampleTexturePack(4);
diff --git a/src/main/java/org/dynmap/hdmap/TexturePackHDShader.java b/src/main/java/org/dynmap/hdmap/TexturePackHDShader.java
new file mode 100644
index 00000000..13f5c48a
--- /dev/null
+++ b/src/main/java/org/dynmap/hdmap/TexturePackHDShader.java
@@ -0,0 +1,147 @@
+package org.dynmap.hdmap;
+
+import static org.dynmap.JSONUtils.s;
+import org.bukkit.block.Biome;
+import org.dynmap.Color;
+import org.dynmap.ColorScheme;
+import org.dynmap.ConfigurationNode;
+import org.dynmap.Log;
+import org.dynmap.utils.MapChunkCache;
+import org.dynmap.utils.MapIterator;
+import org.json.simple.JSONObject;
+
+public class TexturePackHDShader implements HDShader {
+ private String tpname;
+ private String name;
+ private TexturePack tp;
+
+ public TexturePackHDShader(ConfigurationNode configuration) {
+ tpname = configuration.getString("texturepack", "minecraft");
+ name = configuration.getString("name", tpname);
+ tp = TexturePack.getTexturePack(tpname);
+ if(tp == null) {
+ Log.severe("Error: shader '" + name + "' cannot load texture pack '" + tpname + "'");
+ }
+ }
+
+ @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;
+ protected MapIterator mapiter;
+ protected HDMap map;
+ private boolean air;
+
+ private OurShaderState(MapIterator mapiter, HDMap map) {
+ this.mapiter = mapiter;
+ this.map = map;
+ this.color = new Color();
+ }
+ /**
+ * Get our shader
+ */
+ public HDShader getShader() {
+ return TexturePackHDShader.this;
+ }
+
+ /**
+ * Get our map
+ */
+ public HDMap getMap() {
+ return map;
+ }
+
+ /**
+ * Get our lighting
+ */
+ public HDLighting getLighting() {
+ return map.getLighting();
+ }
+
+ /**
+ * Reset renderer state for new ray
+ */
+ public void reset(HDPerspectiveState ps) {
+ color.setTransparent();
+ air = true;
+ }
+
+ /**
+ * 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();
+ color.setRGBA(0, 0, 0, 255);
+
+ 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);
+ }
+ /**
+ * 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);
+ }
+
+ /* Add shader's contributions to JSON for map object */
+ public void addClientConfiguration(JSONObject mapObject) {
+ s(mapObject, "shader", name);
+ }
+}
diff --git a/texture.txt b/texture.txt
new file mode 100644
index 00000000..63469ca2
--- /dev/null
+++ b/texture.txt
@@ -0,0 +1,72 @@
+# Mapping of texture resources to block ID and data values
+# block:id=,data=,top=,bottom=,north=,south=,east=,west=,allfaces=,allsides=
+# =0-255 (index of patch in terrain.png), -1=clear, 256=patch(38)+biome tint from grasscolor.png,257=stationary water,258=moving water,
+# 259=stationary lava,260=moving lava,261=patch(52)+biome tint from foliagecolor.png,262=patch(132)+biome tint from foliagecolor.png,
+# 263=patch(
+######
+# Stone
+block:id=1,data=*,allfaces=1
+# Grass
+block:id=2,data=*,allsides=3,top=256,bottom=2
+# Dirt
+block:id=3,data=*,allfaces=2
+# Cobblestone
+block:id=4,data=*,allfaces=16
+# Wooden Plank
+block:id=5,data=*,allfaces=4
+# Sapling
+block:id=6,data=0,data=3,allsides=15
+# Sapling (Spruce)
+block:id=6,data=1,allsides=63
+# Sapling (Birch)
+block:id=6,data=2,allsides=79
+# Bedrock
+block:id=7,data=*,allfaces=16
+# Water
+block:id=8,data=*,allfaces=258
+# Stationary water
+block:id=9,data=*,allfaces=257
+# Lava
+block:id=10,data=*,allfaces=260
+# Stationary Lava
+block:id=11,data=*,allfaces=259
+# Sand
+block:id=12,data=*,allfaces=18
+# Gravel
+block:id=13,data=*,allfaces=19
+# Gold Ore
+block:id=14,data=*,allfaces=32
+# Iron Ore
+block:id=15,data=*,allfaces=33
+# Coal Ore
+block:id=16,data=*,allfaces=34
+# Wood (std)
+block:id=17,data=0,allsides=20,top=21,bottom=21
+# Wood (spruce/pine)
+block:id=17,data=1,allsides=116,top=21,bottom=21
+# Wood (birch)
+block:id=17,data=2,allsides=117,top=21,bottom=21
+# Leaves (std)
+block:id=18,data=0,allfaces=261
+# Leaves (spruce/pine)
+block:id=18,data=1,allfaces=262
+# Leaves (birch)
+block:id=18,data=2,allfaces=261
+# Sponge
+block:id=19,data=*,allfaces=48
+# Glass
+block:id=20,data=*,allfaces=49
+# Lapis Lazuli Ore
+block:id=21,data=*,allfaces=160
+# Lapis Lazuli Block
+block:id=22,data=*,allfaces=144
+# Dispenser (facing east)
+block:id=23,data=2,top=62,east=46,south=45,north=45,west=45,bottom=62
+# Dispenser (facing west)
+block:id=23,data=3,top=62,west=46,south=45,north=45,east=45,bottom=62
+# Dispenser (facing north)
+block:id=23,data=4,top=62,north=46,south=45,east=45,west=45,bottom=62
+# Dispenser (facing south)
+block:id=23,data=5,top=62,south=46,north=45,east=45,west=45,bottom=62
+# Sandstone
+block:id=24,data=*,top=176,bottom=208,allsides=192