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