From c5d5a85a17eb5faad430adb15ce0def6e49e032c Mon Sep 17 00:00:00 2001 From: FrozenCow Date: Thu, 6 Jan 2011 03:30:50 +0100 Subject: [PATCH] Separated rendering from MapTile, removed separate cave logic (integrated in rendering) and temporarily removed/disabled zoom-rendering. --- src/main/java/org/dynmap/MapManager.java | 160 +++----- src/main/java/org/dynmap/MapTile.java | 386 +----------------- .../java/org/dynmap/WebServerRequest.java | 6 - .../org/dynmap/render/CaveTileRenderer.java | 96 +++++ .../dynmap/render/CombinedTileRenderer.java | 18 + .../org/dynmap/render/DayTileRenderer.java | 271 ++++++++++++ .../org/dynmap/render/MapTileRenderer.java | 7 + 7 files changed, 462 insertions(+), 482 deletions(-) create mode 100644 src/main/java/org/dynmap/render/CaveTileRenderer.java create mode 100644 src/main/java/org/dynmap/render/CombinedTileRenderer.java create mode 100644 src/main/java/org/dynmap/render/DayTileRenderer.java create mode 100644 src/main/java/org/dynmap/render/MapTileRenderer.java diff --git a/src/main/java/org/dynmap/MapManager.java b/src/main/java/org/dynmap/MapManager.java index f3608e53..cb4bd1af 100644 --- a/src/main/java/org/dynmap/MapManager.java +++ b/src/main/java/org/dynmap/MapManager.java @@ -26,6 +26,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; +import java.util.Map; import java.util.NoSuchElementException; import java.util.Scanner; import java.util.Vector; @@ -34,6 +35,10 @@ import java.util.logging.Logger; import org.bukkit.*; import org.dynmap.debug.Debugger; +import org.dynmap.render.CaveTileRenderer; +import org.dynmap.render.CombinedTileRenderer; +import org.dynmap.render.DayTileRenderer; +import org.dynmap.render.MapTileRenderer; import javax.imageio.ImageIO; @@ -42,6 +47,7 @@ public class MapManager extends Thread { private World world; private Debugger debugger; + private MapTileRenderer renderer; /* dimensions of a map tile */ public static final int tileWidth = 128; @@ -60,8 +66,6 @@ public class MapManager extends Thread { /* a list of MapTiles to be updated */ private LinkedList staleTiles; - /* a list of MapTiles for which the cave tile is to be updated */ - private LinkedList staleCaveTiles; /* whether the worker thread should be running now */ private boolean running = false; @@ -72,7 +76,7 @@ public class MapManager extends Thread { public static final int anchorz = 0; /* color database: id -> Color */ - public HashMap colors = null; + public Map colors = null; /* path to colors.txt */ private String colorsetpath = "colors.txt"; @@ -94,8 +98,6 @@ public class MapManager extends Thread { /* this list stores the tile updates */ public LinkedList tileUpdates = null; - /* this list stores the cave tile updates */ - public LinkedList caveTileUpdates = null; /* map debugging mode (send debugging messages to this player) */ public String debugPlayer = null; @@ -126,10 +128,15 @@ public class MapManager extends Thread { tileStore = new HashMap(); staleTiles = new LinkedList(); - staleCaveTiles = new LinkedList(); tileUpdates = new LinkedList(); - caveTileUpdates = new LinkedList(); zoomCache = new Cache(zoomCacheSize); + + colors = loadColorSet(colorsetpath); + + renderer = new CombinedTileRenderer(new MapTileRenderer[] { + new DayTileRenderer(colors, tilepath + "t_{X}_{Y}.png"), + new CaveTileRenderer(colors, tilepath + "ct_{X}_{Y}.png") + }); } /* tile X for position x */ @@ -172,46 +179,6 @@ public class MapManager extends Thread { /* initialize and start map manager */ public void startManager() { - colors = new HashMap(); - - /* load colorset */ - File cfile = new File(colorsetpath); - - try { - Scanner scanner = new Scanner(cfile); - int nc = 0; - while(scanner.hasNextLine()) { - String line = scanner.nextLine(); - if (line.startsWith("#") || line.equals("")) { - continue; - } - - String[] split = line.split("\t"); - if (split.length < 17) { - continue; - } - - Integer id = new Integer(split[0]); - - Color[] c = new Color[4]; - - /* store colors by raycast sequence number */ - c[0] = new Color(Integer.parseInt(split[1]), Integer.parseInt(split[2]), Integer.parseInt(split[3]), Integer.parseInt(split[4])); - c[3] = new Color(Integer.parseInt(split[5]), Integer.parseInt(split[6]), Integer.parseInt(split[7]), Integer.parseInt(split[8])); - c[1] = new Color(Integer.parseInt(split[9]), Integer.parseInt(split[10]), Integer.parseInt(split[11]), Integer.parseInt(split[12])); - c[2] = new Color(Integer.parseInt(split[13]), Integer.parseInt(split[14]), Integer.parseInt(split[15]), Integer.parseInt(split[16])); - - colors.put(id, c); - nc += 1; - } - scanner.close(); - - log.info(nc + " colors loaded from " + colorsetpath); - } catch(Exception e) { - log.log(Level.SEVERE, "Failed to load colorset: " + colorsetpath, e); - return; - } - running = true; this.start(); try { @@ -265,7 +232,7 @@ public class MapManager extends Thread { MapTile t = this.popStaleTile(); if(t != null) { - t.render(this); + renderer.render(t); updateUpdates(t, tileUpdates); @@ -277,20 +244,6 @@ public class MapManager extends Thread { found = true; } - MapTile ct = this.popStaleCaveTile(); - if(ct != null) { - ct.renderCave(this); - - updateUpdates(ct, caveTileUpdates); - - try { - this.sleep(renderWait); - } catch(InterruptedException e) { - } - - found = true; - } - if(!found) { try { this.sleep(500); @@ -359,22 +312,6 @@ public class MapManager extends Thread { } } - /* get next MapTile for which the cave map needs to be - * regenerated, or null - * the mapTile is removed from the list of stale cave tiles */ - public MapTile popStaleCaveTile() - { - synchronized(lock) { - try { - MapTile t = staleCaveTiles.removeFirst(); - t.staleCave = false; - return t; - } catch(NoSuchElementException e) { - return null; - } - } - } - /* put a MapTile that needs to be regenerated on the list of stale tiles */ public boolean pushStaleTile(MapTile m) { @@ -390,15 +327,6 @@ public class MapManager extends Thread { ret = true; } - if(!m.staleCave) { - m.staleCave = true; - staleCaveTiles.addLast(m); - - debug(m.toString() + " cave is now stale"); - - ret = true; - } - return ret; } } @@ -431,7 +359,7 @@ public class MapManager extends Thread { public int getStaleCount() { synchronized(lock) { - return staleTiles.size() + staleCaveTiles.size(); + return staleTiles.size(); } } @@ -439,11 +367,12 @@ public class MapManager extends Thread { public int getRecentUpdateCount() { synchronized(lock) { - return tileUpdates.size() + caveTileUpdates.size(); + return tileUpdates.size(); } } - /* regenerate the entire map, starting at position */ + /* + // regenerate the entire map, starting at position public void regenerate(int x, int y, int z) { int dx = x - anchorx; @@ -478,7 +407,7 @@ public class MapManager extends Thread { } } - /* regenerate all zoom tiles, starting at position */ + // regenerate all zoom tiles, starting at position public void regenerateZoom(int x, int y, int z) { int dx = x - anchorx; @@ -556,8 +485,8 @@ public class MapManager extends Thread { } } - /* regenerate zoom-out tile - * returns number of valid subtiles */ + // regenerate zoom-out tile + // returns number of valid subtiles public int regenZoomTile(int zpx, int zpy) { int px1 = zpx + tileWidth; @@ -610,7 +539,7 @@ public class MapManager extends Thread { } String zPath = t1.getZoomPath(this); - /* save zoom-out tile */ + // save zoom-out tile try { File file = new File(zPath); ImageIO.write(zIm, "png", file); @@ -623,4 +552,47 @@ public class MapManager extends Thread { return good; } + */ + + public Map loadColorSet(String colorsetpath) { + Map colors = new HashMap(); + + /* load colorset */ + File cfile = new File(colorsetpath); + + try { + Scanner scanner = new Scanner(cfile); + int nc = 0; + while(scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.startsWith("#") || line.equals("")) { + continue; + } + + String[] split = line.split("\t"); + if (split.length < 17) { + continue; + } + + Integer id = new Integer(split[0]); + + Color[] c = new Color[4]; + + /* store colors by raycast sequence number */ + c[0] = new Color(Integer.parseInt(split[1]), Integer.parseInt(split[2]), Integer.parseInt(split[3]), Integer.parseInt(split[4])); + c[3] = new Color(Integer.parseInt(split[5]), Integer.parseInt(split[6]), Integer.parseInt(split[7]), Integer.parseInt(split[8])); + c[1] = new Color(Integer.parseInt(split[9]), Integer.parseInt(split[10]), Integer.parseInt(split[11]), Integer.parseInt(split[12])); + c[2] = new Color(Integer.parseInt(split[13]), Integer.parseInt(split[14]), Integer.parseInt(split[15]), Integer.parseInt(split[16])); + + colors.put(id, c); + nc += 1; + } + scanner.close(); + + log.info(nc + " colors loaded from " + colorsetpath); + } catch(Exception e) { + log.log(Level.SEVERE, "Failed to load colorset: " + colorsetpath, e); + } + return colors; + } } diff --git a/src/main/java/org/dynmap/MapTile.java b/src/main/java/org/dynmap/MapTile.java index db346947..6e1084e1 100644 --- a/src/main/java/org/dynmap/MapTile.java +++ b/src/main/java/org/dynmap/MapTile.java @@ -47,6 +47,10 @@ public class MapTile { mz = MapManager.anchorz + px / 2 - py / 2; } + public World getWorld() { + return world; + } + /* try to get the server to load the relevant chunks */ public void loadChunks() { @@ -136,386 +140,4 @@ public class MapTile { { return px + "_" + py; } - - /* render this tile */ - public void render(MapManager mgr) - { - mgr.debug("Rendering tile: " + this.toString()); - - //loadChunks(); - if(!isMapLoaded()) - return; - - BufferedImage im = new BufferedImage(MapManager.tileWidth, MapManager.tileHeight, BufferedImage.TYPE_INT_RGB); - - WritableRaster r = im.getRaster(); - - int ix = mx; - int iy = my; - int iz = mz; - int jx, jz; - - int x, y; - - /* draw the map */ - for(y=0; y=0; x-=2) { - Color c1 = scan(mgr, jx, iy, jz, 0); - Color c2 = scan(mgr, jx, iy, jz, 2); - - r.setPixel(x, y, new int[] { c1.getRed(), c1.getGreen(), c1.getBlue() }); - r.setPixel(x-1, y, new int[] { c2.getRed(), c2.getGreen(), c2.getBlue() }); - - jx++; - jz++; - - } - - y ++; - - jx = ix; - jz = iz - 1; - - for(x=MapManager.tileWidth-1; x>=0; x-=2) { - Color c1 = scan(mgr, jx, iy, jz, 2); - jx++; - jz++; - Color c2 = scan(mgr, jx, iy, jz, 0); - - r.setPixel(x, y, new int[] { c1.getRed(), c1.getGreen(), c1.getBlue() }); - r.setPixel(x-1, y, new int[] { c2.getRed(), c2.getGreen(), c2.getBlue() }); - } - - y ++; - - ix ++; - iz --; - } - - /* save the generated tile */ - saveTile(getPath(mgr), im, getZoomPath(mgr), mgr); - } - - /* render cave map for this tile */ - public void renderCave(MapManager mgr) - { - mgr.debug("Rendering cave map: " + this.toString()); - - //loadChunks(); - if(!isMapLoaded()) - return; - - BufferedImage im = new BufferedImage(MapManager.tileWidth, MapManager.tileHeight, BufferedImage.TYPE_INT_RGB); - - WritableRaster r = im.getRaster(); - - int ix = mx; - int iy = my; - int iz = mz; - int jx, jz; - - int x, y; - - /* draw the map */ - for(y=0; y=0; x-=2) { - Color c1 = caveScan(mgr, jx, iy, jz, 0); - Color c2 = caveScan(mgr, jx, iy, jz, 2); - - r.setPixel(x, y, new int[] { c1.getRed(), c1.getGreen(), c1.getBlue() }); - r.setPixel(x-1, y, new int[] { c2.getRed(), c2.getGreen(), c2.getBlue() }); - - jx++; - jz++; - - } - - y ++; - - jx = ix; - jz = iz - 1; - - for(x=MapManager.tileWidth-1; x>=0; x-=2) { - Color c1 = caveScan(mgr, jx, iy, jz, 2); - jx++; - jz++; - Color c2 = caveScan(mgr, jx, iy, jz, 0); - - r.setPixel(x, y, new int[] { c1.getRed(), c1.getGreen(), c1.getBlue() }); - r.setPixel(x-1, y, new int[] { c2.getRed(), c2.getGreen(), c2.getBlue() }); - } - - y ++; - - ix ++; - iz --; - } - - /* save the generated tile */ - saveTile(getCavePath(mgr), im, getZoomCavePath(mgr), mgr); - } - - /* save rendered tile, update zoom-out tile */ - public void saveTile(String tilePath, BufferedImage im, String zoomPath, MapManager mgr) - { - /* save image */ - try { - File file = new File(tilePath); - ImageIO.write(im, "png", file); - } catch(IOException e) { - log.log(Level.SEVERE, "Failed to save tile: " + tilePath, e); - } catch(java.lang.NullPointerException e) { - log.log(Level.SEVERE, "Failed to save tile (NullPointerException): " + tilePath, e); - } - - /* now update zoom-out tile */ - BufferedImage zIm = mgr.zoomCache.get(zoomPath); - - if(zIm == null) { - /* zoom-out tile doesn't exist - try to load it from disk */ - - mgr.debug("Trying to load zoom-out tile: " + zoomPath); - - try { - File file = new File(zoomPath); - zIm = ImageIO.read(file); - } catch(IOException e) { - } - - if(zIm == null) { - mgr.debug("Failed to load zoom-out tile: " + zoomPath); - /* create new one */ - /* TODO: we might use existing tiles that we could load - * to fill the zoomed out tile in... */ - zIm = new BufferedImage(MapManager.tileWidth, MapManager.tileHeight, BufferedImage.TYPE_INT_RGB); - } else { - mgr.debug("Loaded zoom-out tile from " + zoomPath); - } - } else { - mgr.debug("Using zoom-out tile from cache: " + zoomPath); - } - - /* update zoom-out tile */ - - /* scaled size */ - int scw = mgr.tileWidth / 2; - int sch = mgr.tileHeight / 2; - - /* origin in zoomed-out tile */ - int ox = scw; - int oy = 0; - - if(zpx != px) ox = 0; - if(zpy != py) oy = sch; - - /* blit scaled rendered tile onto zoom-out tile */ - WritableRaster zr = zIm.getRaster(); - Graphics2D g2 = zIm.createGraphics(); - g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); - g2.drawImage(im, ox, oy, scw, sch, null); - - /* update zoom-out tile cache */ - BufferedImage oldIm = mgr.zoomCache.put(zoomPath, zIm); - if(oldIm != null && oldIm != zIm) { - oldIm.flush(); - } - - /* save zoom-out tile */ - try { - File file = new File(zoomPath); - ImageIO.write(zIm, "png", file); - mgr.debug("saved zoom-out tile at " + zoomPath); - - //log.info("Saved tile: " + path); - } catch(IOException e) { - log.log(Level.SEVERE, "Failed to save zoom-out tile: " + zoomPath, e); - } catch(java.lang.NullPointerException e) { - log.log(Level.SEVERE, "Failed to save zoom-out tile (NullPointerException): " + zoomPath, e); - } - } - - /* generate a path name for this map tile */ - public String getPath(MapManager mgr) - { - return mgr.tilepath + "t_" + px + "_" + py + ".png"; - } - - /* generate a path name for the zoomed-out tile */ - public String getZoomPath(MapManager mgr) - { - return mgr.tilepath + "zt_" + zpx + "_" + zpy + ".png"; - } - - /* generate a path name for this cave map tile */ - public String getCavePath(MapManager mgr) - { - return mgr.tilepath + "ct_" + px + "_" + py + ".png"; - } - - /* generate a path name for the zoomed-out cave tile */ - public String getZoomCavePath(MapManager mgr) - { - return mgr.tilepath + "czt_" + zpx + "_" + zpy + ".png"; - } - - /* try to load already generated image */ - public BufferedImage loadTile(MapManager mgr) - { - try { - String path = getPath(mgr); - //log.info("Loading tile from " + path); - File file = new File(path); - BufferedImage im = ImageIO.read(file); - //log.info("OK"); - return im; - } catch(IOException e) { - //log.info("failed: " + e.toString()); - } - - return null; - } - - /* cast a ray into the map */ - private Color scan(MapManager mgr, int x, int y, int z, int seq) - { - for(;;) { - if(y < 0) - return Color.BLUE; - - int id = world.getBlockAt(x, y, z).getTypeID(); - - switch(seq) { - case 0: - x--; - break; - case 1: - y--; - break; - case 2: - z++; - break; - case 3: - y--; - break; - } - - seq = (seq + 1) & 3; - - if(id != 0) { - Color[] colors = mgr.colors.get(id); - if(colors != null) { - Color c = colors[seq]; - if(c.getAlpha() > 0) { - /* we found something that isn't transparent! */ - if(c.getAlpha() == 255) { - /* it's opaque - the ray ends here */ - return c; - } - - /* this block is transparent, so recurse */ - Color bg = scan(mgr, x, y, z, seq); - - int cr = c.getRed(); - int cg = c.getGreen(); - int cb = c.getBlue(); - int ca = c.getAlpha(); - cr *= ca; - cg *= ca; - cb *= ca; - int na = 255 - ca; - - return new Color((bg.getRed() * na + cr) >> 8, (bg.getGreen() * na + cg) >> 8, (bg.getBlue() * na + cb) >> 8); - } - } - } - } - } - - /* cast a ray into the caves */ - private Color caveScan(MapManager mgr, int x, int y, int z, int seq) - { - boolean air = true; - - for(;;) { - if(y < 0) - return Color.BLACK; - - int id = world.getBlockAt(x, y, z).getTypeID(); - - switch(seq) { - case 0: - x--; - break; - case 1: - y--; - break; - case 2: - z++; - break; - case 3: - y--; - break; - } - - seq = (seq + 1) & 3; - - switch(id) { - case 20: - case 18: - case 17: - case 78: - case 79: - id = 0; - break; - default: - } - - if(id != 0) { - air = false; - continue; - } - - if(id == 0 && !air) { - int cr, cg, cb; - int mult = 256; - - if(y < 64) { - cr = 0; - cg = 64 + y * 3; - cb = 255 - y * 4; - } else { - cr = (y-64) * 4; - cg = 255; - cb = 0; - } - - switch(seq) { - case 0: - mult = 224; - break; - case 1: - mult = 256; - break; - case 2: - mult = 192; - break; - case 3: - mult = 160; - break; - } - - cr = cr * mult / 256; - cg = cg * mult / 256; - cb = cb * mult / 256; - - return new Color(cr, cg, cb); - } - } - } } diff --git a/src/main/java/org/dynmap/WebServerRequest.java b/src/main/java/org/dynmap/WebServerRequest.java index b0296793..db638b4c 100644 --- a/src/main/java/org/dynmap/WebServerRequest.java +++ b/src/main/java/org/dynmap/WebServerRequest.java @@ -88,12 +88,6 @@ public class WebServerRequest extends Thread { sb.append(tu.tile.px + "_" + tu.tile.py + " " + tu.tile.zpx + "_" + tu.tile.zpy + " t\n"); } } - - for(TileUpdate tu : mgr.caveTileUpdates) { - if(tu.at >= cutoff) { - sb.append(tu.tile.px + "_" + tu.tile.py + " " + tu.tile.zpx + "_" + tu.tile.zpy + " c\n"); - } - } } out.write(sb.toString().getBytes()); diff --git a/src/main/java/org/dynmap/render/CaveTileRenderer.java b/src/main/java/org/dynmap/render/CaveTileRenderer.java new file mode 100644 index 00000000..9f233307 --- /dev/null +++ b/src/main/java/org/dynmap/render/CaveTileRenderer.java @@ -0,0 +1,96 @@ +package org.dynmap.render; + +import java.awt.Color; +import java.util.Map; + +import org.bukkit.World; +import org.dynmap.MapManager; + +public class CaveTileRenderer extends DayTileRenderer { + + public CaveTileRenderer(Map colors, String outputPath) { + super(colors, outputPath); + } + + @Override + protected Color scan(World world, int x, int y, int z, int seq) + { + boolean air = true; + + for(;;) { + if(y < 0) + return Color.BLACK; + + int id = world.getBlockAt(x, y, z).getTypeID(); + + switch(seq) { + case 0: + x--; + break; + case 1: + y--; + break; + case 2: + z++; + break; + case 3: + y--; + break; + } + + seq = (seq + 1) & 3; + + switch(id) { + case 20: + case 18: + case 17: + case 78: + case 79: + id = 0; + break; + default: + } + + if(id != 0) { + air = false; + continue; + } + + if(id == 0 && !air) { + int cr, cg, cb; + int mult = 256; + + if(y < 64) { + cr = 0; + cg = 64 + y * 3; + cb = 255 - y * 4; + } else { + cr = (y-64) * 4; + cg = 255; + cb = 0; + } + + switch(seq) { + case 0: + mult = 224; + break; + case 1: + mult = 256; + break; + case 2: + mult = 192; + break; + case 3: + mult = 160; + break; + } + + cr = cr * mult / 256; + cg = cg * mult / 256; + cb = cb * mult / 256; + + return new Color(cr, cg, cb); + } + } + } +} diff --git a/src/main/java/org/dynmap/render/CombinedTileRenderer.java b/src/main/java/org/dynmap/render/CombinedTileRenderer.java new file mode 100644 index 00000000..76d734a2 --- /dev/null +++ b/src/main/java/org/dynmap/render/CombinedTileRenderer.java @@ -0,0 +1,18 @@ +package org.dynmap.render; + +import org.dynmap.MapTile; + +public class CombinedTileRenderer implements MapTileRenderer { + private MapTileRenderer[] renderers; + + public CombinedTileRenderer(MapTileRenderer[] renderers) { + this.renderers = renderers; + } + @Override + public void render(MapTile tile) { + for(MapTileRenderer renderer : renderers) { + renderer.render(tile); + } + } + +} diff --git a/src/main/java/org/dynmap/render/DayTileRenderer.java b/src/main/java/org/dynmap/render/DayTileRenderer.java new file mode 100644 index 00000000..26218acf --- /dev/null +++ b/src/main/java/org/dynmap/render/DayTileRenderer.java @@ -0,0 +1,271 @@ +package org.dynmap.render; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.awt.image.WritableRaster; +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.imageio.ImageIO; + +import org.bukkit.World; +import org.dynmap.MapManager; +import org.dynmap.MapTile; + +public class DayTileRenderer implements MapTileRenderer { + protected static final Logger log = Logger.getLogger("Minecraft"); + protected String outputPath; + private Map colors; + + public DayTileRenderer(Map colors, String outputPath) { + this.colors = colors; + this.outputPath = outputPath; + } + public void render(MapTile tile) { + World world = tile.getWorld(); + BufferedImage im = new BufferedImage(MapManager.tileWidth, MapManager.tileHeight, BufferedImage.TYPE_INT_RGB); + + WritableRaster r = im.getRaster(); + + int ix = tile.mx; + int iy = tile.my; + int iz = tile.mz; + int jx, jz; + + int x, y; + + /* draw the map */ + for(y=0; y=0; x-=2) { + Color c1 = scan(world, jx, iy, jz, 0); + Color c2 = scan(world, jx, iy, jz, 2); + + r.setPixel(x, y, new int[] { c1.getRed(), c1.getGreen(), c1.getBlue() }); + r.setPixel(x-1, y, new int[] { c2.getRed(), c2.getGreen(), c2.getBlue() }); + + jx++; + jz++; + + } + + y ++; + + jx = ix; + jz = iz - 1; + + for(x=MapManager.tileWidth-1; x>=0; x-=2) { + Color c1 = scan(world, jx, iy, jz, 2); + jx++; + jz++; + Color c2 = scan(world, jx, iy, jz, 0); + + r.setPixel(x, y, new int[] { c1.getRed(), c1.getGreen(), c1.getBlue() }); + r.setPixel(x-1, y, new int[] { c2.getRed(), c2.getGreen(), c2.getBlue() }); + } + + y ++; + + ix ++; + iz --; + } + + /* save the generated tile */ + saveTile(tile, im); + } + + protected Color scan(World world, int x, int y, int z, int seq) + { + for(;;) { + if(y < 0) + return Color.BLUE; + + int id = world.getBlockAt(x, y, z).getTypeID(); + + switch(seq) { + case 0: + x--; + break; + case 1: + y--; + break; + case 2: + z++; + break; + case 3: + y--; + break; + } + + seq = (seq + 1) & 3; + + if(id != 0) { + Color[] colors = this.colors.get(id); + if(colors != null) { + Color c = colors[seq]; + if(c.getAlpha() > 0) { + /* we found something that isn't transparent! */ + if(c.getAlpha() == 255) { + /* it's opaque - the ray ends here */ + return c; + } + + /* this block is transparent, so recurse */ + Color bg = scan(world, x, y, z, seq); + + int cr = c.getRed(); + int cg = c.getGreen(); + int cb = c.getBlue(); + int ca = c.getAlpha(); + cr *= ca; + cg *= ca; + cb *= ca; + int na = 255 - ca; + + return new Color((bg.getRed() * na + cr) >> 8, (bg.getGreen() * na + cg) >> 8, (bg.getBlue() * na + cb) >> 8); + } + } + } + } + } + + /* save rendered tile, update zoom-out tile */ + public void saveTile(MapTile tile, BufferedImage im) + { + String tilePath = outputPath + .replace("{X}", Integer.toString(tile.px)) + .replace("{Y}", Integer.toString(tile.py)); + /* save image */ + try { + File file = new File(tilePath); + ImageIO.write(im, "png", file); + } catch(IOException e) { + log.log(Level.SEVERE, "Failed to save tile: " + tilePath, e); + } catch(java.lang.NullPointerException e) { + log.log(Level.SEVERE, "Failed to save tile (NullPointerException): " + tilePath, e); + } + + /* now update zoom-out tile */ + /*BufferedImage zIm = mgr.zoomCache.get(zoomPath); + + + if(zIm == null) { + // zoom-out tile doesn't exist - try to load it from disk + + mgr.debug("Trying to load zoom-out tile: " + zoomPath); + + try { + File file = new File(zoomPath); + zIm = ImageIO.read(file); + } catch(IOException e) { + } + + if(zIm == null) { + mgr.debug("Failed to load zoom-out tile: " + zoomPath); + // create new one + // TODO: we might use existing tiles that we could load + // to fill the zoomed out tile in... + zIm = new BufferedImage(MapManager.tileWidth, MapManager.tileHeight, BufferedImage.TYPE_INT_RGB); + } else { + mgr.debug("Loaded zoom-out tile from " + zoomPath); + } + } else { + mgr.debug("Using zoom-out tile from cache: " + zoomPath); + } + + // update zoom-out tile + + // scaled size + int scw = mgr.tileWidth / 2; + int sch = mgr.tileHeight / 2; + + // origin in zoomed-out tile + int ox = scw; + int oy = 0; + + if(zpx != px) ox = 0; + if(zpy != py) oy = sch; + + // blit scaled rendered tile onto zoom-out tile + WritableRaster zr = zIm.getRaster(); + Graphics2D g2 = zIm.createGraphics(); + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2.drawImage(im, ox, oy, scw, sch, null); + + // update zoom-out tile cache + BufferedImage oldIm = mgr.zoomCache.put(zoomPath, zIm); + if(oldIm != null && oldIm != zIm) { + oldIm.flush(); + } + + // save zoom-out tile + try { + File file = new File(zoomPath); + ImageIO.write(zIm, "png", file); + mgr.debug("saved zoom-out tile at " + zoomPath); + + //log.info("Saved tile: " + path); + } catch(IOException e) { + log.log(Level.SEVERE, "Failed to save zoom-out tile: " + zoomPath, e); + } catch(java.lang.NullPointerException e) { + log.log(Level.SEVERE, "Failed to save zoom-out tile (NullPointerException): " + zoomPath, e); + }*/ + } + + /* try to load already generated image */ + public BufferedImage loadTile(MapTile tile) + { + try { + String path = getPath(tile); + //log.info("Loading tile from " + path); + File file = new File(path); + BufferedImage im = ImageIO.read(file); + //log.info("OK"); + return im; + } catch(IOException e) { + //log.info("failed: " + e.toString()); + } + + return null; + } + + public String getPath(MapTile tile) + { + return outputPath + .replace("{X}", Integer.toString(tile.px)) + .replace("{Y}", Integer.toString(tile.py)); + } + + /* + // generate a path name for this map tile + public String getPath(MapManager mgr) + { + return mgr.tilepath + "t_" + px + "_" + py + ".png"; + } + + // generate a path name for the zoomed-out tile + public String getZoomPath(MapManager mgr) + { + return mgr.tilepath + "zt_" + zpx + "_" + zpy + ".png"; + } + + // generate a path name for this cave map tile + public String getCavePath(MapManager mgr) + { + return mgr.tilepath + "ct_" + px + "_" + py + ".png"; + } + + // generate a path name for the zoomed-out cave tile + public String getZoomCavePath(MapManager mgr) + { + return mgr.tilepath + "czt_" + zpx + "_" + zpy + ".png"; + } + */ +} diff --git a/src/main/java/org/dynmap/render/MapTileRenderer.java b/src/main/java/org/dynmap/render/MapTileRenderer.java new file mode 100644 index 00000000..7e973cec --- /dev/null +++ b/src/main/java/org/dynmap/render/MapTileRenderer.java @@ -0,0 +1,7 @@ +package org.dynmap.render; + +import org.dynmap.MapTile; + +public interface MapTileRenderer { + void render(MapTile tile); +}