Add night view via ambientlight setting on Flat and Surface maps, add

night-and-day setting to generate both night (default) and day
(prefix+'_day') versions of tiles, and add transparency to generated
PNG files
This commit is contained in:
Mike Primm 2011-05-27 00:56:56 -05:00
parent 993b26beb4
commit d2c947653d
15 changed files with 645 additions and 171 deletions

View File

@ -125,6 +125,9 @@ templates:
title: "Flat" title: "Flat"
prefix: flat prefix: flat
colorscheme: default colorscheme: default
# To render a world as a "night view", set shadowstrength and ambientlight
# shadowstrength: 1.0
# ambientlight: 4
- class: org.dynmap.kzedmap.KzedMap - class: org.dynmap.kzedmap.KzedMap
renderers: renderers:
- class: org.dynmap.kzedmap.DefaultTileRenderer - class: org.dynmap.kzedmap.DefaultTileRenderer
@ -135,6 +138,8 @@ templates:
colorscheme: default colorscheme: default
# Add shadows to world (based on top-down shadows from chunk data) # Add shadows to world (based on top-down shadows from chunk data)
# shadowstrength: 1.0 # shadowstrength: 1.0
# To render a world as a "night view", set shadowstrength and ambientlight
# ambientlight: 4
# Sets the icon to 'images/block_custom.png' # Sets the icon to 'images/block_custom.png'
# icon: custom # icon: custom
#- class: org.dynmap.kzedmap.HighlightTileRenderer #- class: org.dynmap.kzedmap.HighlightTileRenderer
@ -181,6 +186,14 @@ worlds:
# title: "World" # title: "World"
# Use 'enabled: false' to disable a certain world. # Use 'enabled: false' to disable a certain world.
# enabled: false # enabled: false
# # If world isn't contiguous chunks (due to teleporting, for example), fullrender needs to be given other locations to scan for tiles on each patch of chunks
# fullrenderlocations:
# - x: 10000
# y: 64
# z: 20000
# - x: -15000
# y: 64
# z: -5000
# Use 'template: mycustomtemplate' to use the properties specified in the template 'mycustomtemplate' to this world. Default it is set to the environment-name (normal or nether). # Use 'template: mycustomtemplate' to use the properties specified in the template 'mycustomtemplate' to this world. Default it is set to the environment-name (normal or nether).
# template: mycustomtemplate # template: mycustomtemplate
# Rest of comes from template - uncomment to tailor for world specifically # Rest of comes from template - uncomment to tailor for world specifically
@ -194,6 +207,9 @@ worlds:
# title: "Flat" # title: "Flat"
# prefix: flat # prefix: flat
# colorscheme: default # colorscheme: default
# # To render a world as a "night view", set shadowstrength and ambientlight
# # shadowstrength: 1.0
# # ambientlight: 4
# - class: org.dynmap.kzedmap.KzedMap # - class: org.dynmap.kzedmap.KzedMap
# renderers: # renderers:
# - class: org.dynmap.kzedmap.DefaultTileRenderer # - class: org.dynmap.kzedmap.DefaultTileRenderer
@ -204,6 +220,8 @@ worlds:
# colorscheme: default # colorscheme: default
# # Add shadows to world (based on top-down shadows from chunk data) # # Add shadows to world (based on top-down shadows from chunk data)
# # shadowstrength: 1.0 # # shadowstrength: 1.0
# # To render a world as a "night view", set shadowstrength and ambientlight
# # ambientlight: 4
# # Sets the icon to 'images/block_custom.png' # # Sets the icon to 'images/block_custom.png'
# # icon: custom # # icon: custom
# #- class: org.dynmap.kzedmap.HighlightTileRenderer # #- class: org.dynmap.kzedmap.HighlightTileRenderer

View File

@ -0,0 +1,46 @@
package org.dynmap;
/**
* Represents a static, thread-safe snapshot of chunk of blocks
* Purpose is to allow clean, efficient copy of a chunk data to be made, and then handed off for processing in another thread (e.g. map rendering)
*/
public interface ChunkSnapshot {
/**
* Get block type for block at corresponding coordinate in the chunk
*
* @param x 0-15
* @param y 0-127
* @param z 0-15
* @return 0-255
*/
public int getBlockTypeId(int x, int y, int z);
/**
* Get block data for block at corresponding coordinate in the chunk
*
* @param x 0-15
* @param y 0-127
* @param z 0-15
* @return 0-15
*/
public int getBlockData(int x, int y, int z);
/**
* Get sky light level for block at corresponding coordinate in the chunk
*
* @param x 0-15
* @param y 0-127
* @param z 0-15
* @return 0-15
*/
public int getBlockSkyLight(int x, int y, int z);
/**
* Get light level emitted by block at corresponding coordinate in the chunk
*
* @param x 0-15
* @param y 0-127
* @param z 0-15
* @return 0-15
*/
public int getBlockEmittedLight(int x, int y, int z);
public int getHighestBlockYAt(int x, int z);
}

View File

@ -5,7 +5,7 @@ package org.dynmap;
* of them during rendering * of them during rendering
*/ */
public class Color { public class Color {
/* RGBA value */ /* ARGB value */
private int val; private int val;
public static final int TRANSPARENT = 0; public static final int TRANSPARENT = 0;
@ -20,16 +20,16 @@ public class Color {
setTransparent(); setTransparent();
} }
public final int getRed() { public final int getRed() {
return (val >> 24) & 0xFF;
}
public final int getGreen() {
return (val >> 16) & 0xFF; return (val >> 16) & 0xFF;
} }
public final int getBlue() { public final int getGreen() {
return (val >> 8) & 0xFF; return (val >> 8) & 0xFF;
} }
public final int getBlue() {
return val & 0xFF;
}
public final int getAlpha() { public final int getAlpha() {
return (val & 0xFF); return ((val >> 24) & 0xFF);
} }
public final boolean isTransparent() { public final boolean isTransparent() {
return (val == TRANSPARENT); return (val == TRANSPARENT);
@ -41,6 +41,15 @@ public class Color {
val = c.val; val = c.val;
} }
public final void setRGBA(int red, int green, int blue, int alpha) { public final void setRGBA(int red, int green, int blue, int alpha) {
val = ((red & 0xFF) << 24) | ((green & 0xFF) << 16) | ((blue & 0xFF) << 8) | (alpha & 0xFF); val = ((alpha & 0xFF) << 24) | ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF);
}
public final int getARGB() {
return val;
}
public final void setARGB(int c) {
val = c;
}
public final int getComponent(int idx) {
return 0xFF & (val >> ((3-idx)*8));
} }
} }

View File

@ -4,7 +4,7 @@ package org.dynmap;
* Represents a static, thread-safe snapshot of chunk of blocks * Represents a static, thread-safe snapshot of chunk of blocks
* Purpose is to allow clean, efficient copy of a chunk data to be made, and then handed off for processing in another thread (e.g. map rendering) * Purpose is to allow clean, efficient copy of a chunk data to be made, and then handed off for processing in another thread (e.g. map rendering)
*/ */
public class CraftChunkSnapshot { public class CraftChunkSnapshot implements ChunkSnapshot {
private final int x, z; private final int x, z;
private final byte[] buf; /* Flat buffer in uncompressed chunk file format */ private final byte[] buf; /* Flat buffer in uncompressed chunk file format */

View File

@ -4,10 +4,12 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.Location;
public class DynmapWorld { public class DynmapWorld {
public World world; public World world;
public List<MapType> maps = new ArrayList<MapType>(); public List<MapType> maps = new ArrayList<MapType>();
public UpdateQueue updates = new UpdateQueue(); public UpdateQueue updates = new UpdateQueue();
public ConfigurationNode configuration; public ConfigurationNode configuration;
public List<Location> seedloc;
} }

View File

@ -20,9 +20,164 @@ public class MapChunkCache {
private int x_min, x_max, z_min, z_max; private int x_min, x_max, z_min, z_max;
private int x_dim; private int x_dim;
private CraftChunkSnapshot[] snaparray; /* Index = (x-x_min) + ((z-z_min)*x_dim) */ private ChunkSnapshot[] snaparray; /* Index = (x-x_min) + ((z-z_min)*x_dim) */
private LinkedList<DynmapChunk> loadedChunks = new LinkedList<DynmapChunk>(); private LinkedList<DynmapChunk> loadedChunks = new LinkedList<DynmapChunk>();
/**
* Iterator for traversing map chunk cache (base is for non-snapshot)
*/
public class MapIterator {
public int x, y, z;
MapIterator(int x0, int y0, int z0) {
initialize(x0, y0, z0);
}
public void initialize(int x0, int y0, int z0) {
this.x = x0;
this.y = y0;
this.z = z0;
}
public int getBlockTypeID() {
return w.getBlockTypeIdAt(x, y, z);
}
public int getBlockData() {
return w.getBlockAt(x, y, z).getData();
}
public int getHighestBlockYAt() {
return w.getHighestBlockYAt(x, z);
}
public int getBlockSkyLight() {
return 15;
}
public int getBlockEmittedLight() {
return 0;
}
public void incrementX() {
x++;
}
public void decrementX() {
x--;
}
public void incrementY() {
y++;
}
public void decrementY() {
y--;
}
public void incrementZ() {
z++;
}
public void decrementZ() {
z--;
}
public void setY(int y) {
this.y = y;
}
}
/**
* Iterator for snapshot mode
*/
public class SnapshotMapIterator extends MapIterator {
private ChunkSnapshot snap;
private int x4, z4;
public SnapshotMapIterator(int x0, int y0, int z0) {
super(x0, y0, z0);
}
public void initialize(int x0, int y0, int z0) {
super.initialize(x0, y0, z0);
try {
snap = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
} catch (ArrayIndexOutOfBoundsException aioobx) {
snap = EMPTY;
}
x4 = x0 & 0xF;
z4 = z0 & 0xF;
}
public int getBlockTypeID() {
return snap.getBlockTypeId(x4, y, z4);
}
public int getBlockData() {
return snap.getBlockData(x4, y, z4);
}
public int getHighestBlockYAt() {
return snap.getHighestBlockYAt(x4, z4);
}
public int getBlockSkyLight() {
return snap.getBlockSkyLight(x4, y, z4);
}
public int getBlockEmittedLight() {
return snap.getBlockEmittedLight(x4, y, z4);
}
public void incrementX() {
x++; x4 = x & 0xF;
if(x4 == 0) { /* Next chunk? */
try {
snap = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
} catch (ArrayIndexOutOfBoundsException aioobx) {
snap = EMPTY;
}
}
}
public void decrementX() {
x--; x4 = x & 0xF;
if(x4 == 15) { /* Next chunk? */
try {
snap = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
} catch (ArrayIndexOutOfBoundsException aioobx) {
snap = EMPTY;
}
}
}
public void incrementY() {
y++;
}
public void decrementY() {
y--;
}
public void incrementZ() {
z++; z4 = z & 0xF;
if(z4 == 0) { /* Next chunk? */
try {
snap = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
} catch (ArrayIndexOutOfBoundsException aioobx) {
snap = EMPTY;
}
}
}
public void decrementZ() {
z--; z4 = z & 0xF;
if(z4 == 15) { /* Next chunk? */
try {
snap = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
} catch (ArrayIndexOutOfBoundsException aioobx) {
snap = EMPTY;
}
}
}
}
/**
* Chunk cache for representing unloaded chunk
*/
private static class EmptyChunk implements ChunkSnapshot {
public final int getBlockTypeId(int x, int y, int z) {
return 0;
}
public final int getBlockData(int x, int y, int z) {
return 0;
}
public final int getBlockSkyLight(int x, int y, int z) {
return 15;
}
public final int getBlockEmittedLight(int x, int y, int z) {
return 0;
}
public final int getHighestBlockYAt(int x, int z) {
return 1;
}
}
private static final EmptyChunk EMPTY = new EmptyChunk();
/** /**
* Create chunk cache container * Create chunk cache container
* @param w - world * @param w - world
@ -75,7 +230,7 @@ public class MapChunkCache {
Log.info("Chunk snapshot support disabled"); Log.info("Chunk snapshot support disabled");
} }
if(gethandle != null) { /* We can use caching */ if(gethandle != null) { /* We can use caching */
snaparray = new CraftChunkSnapshot[x_dim * (z_max-z_min+1)]; snaparray = new ChunkSnapshot[x_dim * (z_max-z_min+1)];
} }
if(snaparray != null) { if(snaparray != null) {
// Load the required chunks. // Load the required chunks.
@ -110,6 +265,10 @@ public class MapChunkCache {
w.unloadChunk(chunk.x, chunk.z, false, false); w.unloadChunk(chunk.x, chunk.z, false, false);
} }
} }
for(int i = 0; i < snaparray.length; i++) {
if(snaparray[i] == null)
snaparray[i] = EMPTY;
}
} }
else { /* Else, load and keep them loaded for now */ else { /* Else, load and keep them loaded for now */
// Load the required chunks. // Load the required chunks.
@ -154,10 +313,7 @@ public class MapChunkCache {
*/ */
public int getBlockTypeID(int x, int y, int z) { public int getBlockTypeID(int x, int y, int z) {
if(snaparray != null) { if(snaparray != null) {
CraftChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
if(ss == null)
return 0;
else
return ss.getBlockTypeId(x & 0xF, y, z & 0xF); return ss.getBlockTypeId(x & 0xF, y, z & 0xF);
} }
else { else {
@ -169,10 +325,7 @@ public class MapChunkCache {
*/ */
public byte getBlockData(int x, int y, int z) { public byte getBlockData(int x, int y, int z) {
if(snaparray != null) { if(snaparray != null) {
CraftChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
if(ss == null)
return 0;
else
return (byte)ss.getBlockData(x & 0xF, y, z & 0xF); return (byte)ss.getBlockData(x & 0xF, y, z & 0xF);
} }
else { else {
@ -184,11 +337,7 @@ public class MapChunkCache {
*/ */
public int getHighestBlockYAt(int x, int z) { public int getHighestBlockYAt(int x, int z) {
if(snaparray != null) { if(snaparray != null) {
CraftChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
if(ss == null) {
return 1;
}
else
return ss.getHighestBlockYAt(x & 0xF, z & 0xF); return ss.getHighestBlockYAt(x & 0xF, z & 0xF);
} }
else { else {
@ -199,15 +348,31 @@ public class MapChunkCache {
*/ */
public int getBlockSkyLight(int x, int y, int z) { public int getBlockSkyLight(int x, int y, int z) {
if(snaparray != null) { if(snaparray != null) {
CraftChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
if(ss == null) {
return 15;
}
else
return ss.getBlockSkyLight(x & 0xF, y, z & 0xF); return ss.getBlockSkyLight(x & 0xF, y, z & 0xF);
} }
else { else {
return 15; return 15;
} }
} }
/* Get emitted light level
*/
public int getBlockEmittedLight(int x, int y, int z) {
if(snaparray != null) {
ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim];
return ss.getBlockEmittedLight(x & 0xF, y, z & 0xF);
}
else {
return 0;
}
}
/**
* Get cache iterator
*/
public MapIterator getIterator(int x, int y, int z) {
if(snaparray != null)
return new SnapshotMapIterator(x, y, z);
else
return new MapIterator(x, y, z);
}
} }

View File

@ -48,7 +48,7 @@ public class MapManager {
private class FullWorldRenderState implements Runnable { private class FullWorldRenderState implements Runnable {
DynmapWorld world; /* Which world are we rendering */ DynmapWorld world; /* Which world are we rendering */
Location loc; /* Start location */ Location loc;
int map_index = -1; /* Which map are we on */ int map_index = -1; /* Which map are we on */
MapType map; MapType map;
HashSet<MapTile> found = null; HashSet<MapTile> found = null;
@ -100,6 +100,16 @@ public class MapManager {
renderQueue.add(mt); renderQueue.add(mt);
} }
} }
if(world.seedloc != null) {
for(Location seed : world.seedloc) {
for (MapTile mt : map.getTiles(seed)) {
if (!found.contains(mt)) {
found.add(mt);
renderQueue.add(mt);
}
}
}
}
} }
tile = renderQueue.pollFirst(); tile = renderQueue.pollFirst();
} }
@ -215,6 +225,15 @@ public class MapManager {
} }
Log.info("Loaded " + dynmapWorld.maps.size() + " maps of world '" + worldName + "'."); Log.info("Loaded " + dynmapWorld.maps.size() + " maps of world '" + worldName + "'.");
List<ConfigurationNode> loclist = worldConfiguration.getNodes("fullrenderlocations");
dynmapWorld.seedloc = new ArrayList<Location>();
if(loclist != null) {
for(ConfigurationNode loc : loclist) {
Location lx = new Location(w, loc.getDouble("x", 0), loc.getDouble("y", 64), loc.getDouble("z", 0));
dynmapWorld.seedloc.add(lx);
}
}
// TODO: Make this less... weird... // TODO: Make this less... weird...
// Insert the world on the same spot as in the configuration. // Insert the world on the same spot as in the configuration.
HashMap<String, Integer> indexLookup = new HashMap<String, Integer>(); HashMap<String, Integer> indexLookup = new HashMap<String, Integer>();
@ -237,7 +256,6 @@ public class MapManager {
} }
worlds.add(insertIndex, dynmapWorld); worlds.add(insertIndex, dynmapWorld);
} }
worldsLookup.put(w.getName(), dynmapWorld); worldsLookup.put(w.getName(), dynmapWorld);
plug_in.events.trigger("worldactivated", dynmapWorld); plug_in.events.trigger("worldactivated", dynmapWorld);
} }

View File

@ -16,6 +16,8 @@ public abstract class MapTile {
public abstract String getFilename(); public abstract String getFilename();
public abstract String getDayFilename();
public MapTile(World world, MapType map) { public MapTile(World world, MapType map) {
this.world = world; this.world = world;
this.map = map; this.map = map;

View File

@ -31,7 +31,8 @@ public class FlatMap extends MapType {
private String prefix; private String prefix;
private ColorScheme colorScheme; private ColorScheme colorScheme;
private int maximumHeight = 127; private int maximumHeight = 127;
private int ambientlight = 15;;
private int shadowscale[] = null;
public FlatMap(ConfigurationNode configuration) { public FlatMap(ConfigurationNode configuration) {
this.configuration = configuration; this.configuration = configuration;
prefix = (String) configuration.get("prefix"); prefix = (String) configuration.get("prefix");
@ -42,6 +43,25 @@ public class FlatMap extends MapType {
if (maximumHeight > 127) if (maximumHeight > 127)
maximumHeight = 127; maximumHeight = 127;
} }
o = configuration.get("shadowstrength");
if(o != null) {
double shadowweight = Double.parseDouble(String.valueOf(o));
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;
}
}
}
o = configuration.get("ambientlight");
if(o != null) {
ambientlight = Integer.parseInt(String.valueOf(o));
}
} }
@Override @Override
@ -88,46 +108,43 @@ public class FlatMap extends MapType {
boolean rendered = false; boolean rendered = false;
BufferedImage im = KzedMap.allocateBufferedImage(t.size, t.size); BufferedImage im = KzedMap.allocateBufferedImage(t.size, t.size);
WritableRaster raster = im.getRaster(); Color rslt = new Color();
int[] pixel = new int[4]; int[] pixel = new int[4];
for (int x = 0; x < t.size; x++) MapChunkCache.MapIterator mapiter = cache.getIterator(t.x * t.size, 127, t.y * t.size);
for (int y = 0; y < t.size; y++) { for (int x = 0; x < t.size; x++) {
int mx = x + t.x * t.size; mapiter.initialize(t.x * t.size + x, 127, t.y * t.size);
int mz = y + t.y * t.size; for (int y = 0; y < t.size; y++, mapiter.incrementZ()) {
int my;
int blockType; int blockType;
if(isnether) { if(isnether) {
/* Scan until we hit air */ while((blockType = mapiter.getBlockTypeID()) != 0) {
my = 127; mapiter.decrementY();
while((blockType = cache.getBlockTypeID(mx, my, mz)) != 0) { if(mapiter.y < 0) { /* Solid - use top */
my--; mapiter.setY(127);
if(my < 0) { /* Solid - use top */ blockType = mapiter.getBlockTypeID();
my = 127;
blockType = cache.getBlockTypeID(mx, my, mz);
break; break;
} }
} }
if(blockType == 0) { /* Hit air - now find non-air */ if(blockType == 0) { /* Hit air - now find non-air */
while((blockType = cache.getBlockTypeID(mx, my, mz)) == 0) { while((blockType = mapiter.getBlockTypeID()) == 0) {
my--; mapiter.decrementY();
if(my < 0) { if(mapiter.y < 0) {
my = 0; mapiter.setY(0);
break; break;
} }
} }
} }
} }
else { else {
my = cache.getHighestBlockYAt(mx, mz) - 1; int my = mapiter.getHighestBlockYAt() - 1;
if(my > maximumHeight) my = maximumHeight; if(my > maximumHeight) my = maximumHeight;
blockType = cache.getBlockTypeID(mx, my, mz); mapiter.setY(my);
blockType = mapiter.getBlockTypeID();
} }
byte data = 0; int data = 0;
Color[] colors = colorScheme.colors[blockType]; Color[] colors = colorScheme.colors[blockType];
if(colorScheme.datacolors[blockType] != null) { if(colorScheme.datacolors[blockType] != null) {
data = cache.getBlockData(mx, my, mz); data = mapiter.getBlockData();
colors = colorScheme.datacolors[blockType][data]; colors = colorScheme.datacolors[blockType][data];
} }
if (colors == null) if (colors == null)
@ -136,10 +153,24 @@ public class FlatMap extends MapType {
if (c == null) if (c == null)
continue; continue;
boolean below = my < 64; pixel[0] = c.getRed();
pixel[1] = c.getGreen();
pixel[2] = c.getBlue();
/* If ambient light less than 15, do scaling */
if((shadowscale != null) && (ambientlight < 15)) {
if(mapiter.y < 127)
mapiter.incrementY();
int light = Math.max(ambientlight, mapiter.getBlockEmittedLight());
pixel[0] = (pixel[0] * shadowscale[light]) >> 8;
pixel[1] = (pixel[1] * shadowscale[light]) >> 8;
pixel[2] = (pixel[2] * shadowscale[light]) >> 8;
}
else { /* Only do height keying if we're not messing with ambient light */
boolean below = mapiter.y < 64;
// Make height range from 0 - 1 (1 - 0 for below and 0 - 1 above) // Make height range from 0 - 1 (1 - 0 for below and 0 - 1 above)
float height = (below ? 64 - my : my - 64) / 64.0f; float height = (below ? 64 - mapiter.y : mapiter.y - 64) / 64.0f;
// Defines the 'step' in coloring. // Defines the 'step' in coloring.
float step = 10 / 128.0f; float step = 10 / 128.0f;
@ -153,10 +184,6 @@ public class FlatMap extends MapType {
// Don't let the color go fully white or fully black. // Don't let the color go fully white or fully black.
scale *= 0.8f; scale *= 0.8f;
pixel[0] = c.getRed();
pixel[1] = c.getGreen();
pixel[2] = c.getBlue();
if (below) { if (below) {
pixel[0] -= pixel[0] * scale; pixel[0] -= pixel[0] * scale;
pixel[1] -= pixel[1] * scale; pixel[1] -= pixel[1] * scale;
@ -166,10 +193,12 @@ public class FlatMap extends MapType {
pixel[1] += (255-pixel[1]) * scale; pixel[1] += (255-pixel[1]) * scale;
pixel[2] += (255-pixel[2]) * scale; pixel[2] += (255-pixel[2]) * scale;
} }
}
raster.setPixel(t.size-y-1, x, pixel); rslt.setRGBA(pixel[0], pixel[1], pixel[2], 255);
im.setRGB(t.size-y-1, x, rslt.getARGB());
rendered = true; rendered = true;
} }
}
/* Hand encoding and writing file off to MapManager */ /* Hand encoding and writing file off to MapManager */
final File fname = outputFile; final File fname = outputFile;
final MapTile mtile = tile; final MapTile mtile = tile;
@ -211,6 +240,10 @@ public class FlatMap extends MapType {
public String getFilename() { public String getFilename() {
return map.prefix + "_" + size + "_" + -(y+1) + "_" + x + ".png"; return map.prefix + "_" + size + "_" + -(y+1) + "_" + x + ".png";
} }
@Override
public String getDayFilename() {
return map.prefix + "_day_" + size + "_" + -(y+1) + "_" + x + ".png";
}
} }
@Override @Override

View File

@ -12,15 +12,15 @@ public class CaveTileRenderer extends DefaultTileRenderer {
} }
@Override @Override
protected void scan(World world, int x, int y, int z, int seq, boolean isnether, final Color result, protected void scan(World world, int seq, boolean isnether, final Color result, final Color result_day,
MapChunkCache cache) { MapChunkCache.MapIterator mapiter) {
boolean air = true; boolean air = true;
result.setTransparent(); result.setTransparent();
for (;;) { for (;;) {
if (y < 0) if (mapiter.y < 0)
return; return;
int id = cache.getBlockTypeID(x, y, z); int id = mapiter.getBlockTypeID();
if(isnether) { /* Make ceiling into air in nether */ if(isnether) { /* Make ceiling into air in nether */
if(id != 0) if(id != 0)
id = 0; id = 0;
@ -30,16 +30,14 @@ public class CaveTileRenderer extends DefaultTileRenderer {
switch (seq) { switch (seq) {
case 0: case 0:
x--; mapiter.decrementX();
break; break;
case 1: case 1:
y--; case 3:
mapiter.decrementY();
break; break;
case 2: case 2:
z++; mapiter.incrementZ();
break;
case 3:
y--;
break; break;
} }
@ -65,12 +63,12 @@ public class CaveTileRenderer extends DefaultTileRenderer {
int cr, cg, cb; int cr, cg, cb;
int mult = 256; int mult = 256;
if (y < 64) { if (mapiter.y < 64) {
cr = 0; cr = 0;
cg = 64 + y * 3; cg = 64 + mapiter.y * 3;
cb = 255 - y * 4; cb = 255 - mapiter.y * 4;
} else { } else {
cr = (y - 64) * 4; cr = (mapiter.y - 64) * 4;
cg = 255; cg = 255;
cb = 0; cb = 0;
} }

View File

@ -19,6 +19,7 @@ import org.dynmap.Client;
import org.dynmap.Color; import org.dynmap.Color;
import org.dynmap.ColorScheme; import org.dynmap.ColorScheme;
import org.dynmap.ConfigurationNode; import org.dynmap.ConfigurationNode;
import org.dynmap.Log;
import org.dynmap.MapManager; import org.dynmap.MapManager;
import org.dynmap.debug.Debug; import org.dynmap.debug.Debug;
import org.dynmap.MapChunkCache; import org.dynmap.MapChunkCache;
@ -35,6 +36,8 @@ public class DefaultTileRenderer implements MapTileRenderer {
protected Color highlightColor = new Color(255, 0, 0); protected Color highlightColor = new Color(255, 0, 0);
protected int shadowscale[]; /* index=skylight level, value = 256 * scaling value */ 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 */
@Override @Override
public String getName() { public String getName() {
return name; return name;
@ -54,15 +57,29 @@ public class DefaultTileRenderer implements MapTileRenderer {
double shadowweight = Double.parseDouble(String.valueOf(o)); double shadowweight = Double.parseDouble(String.valueOf(o));
if(shadowweight > 0.0) { if(shadowweight > 0.0) {
shadowscale = new int[16]; shadowscale = new int[16];
for(int i = 0; i < 16; i++) { shadowscale[15] = 256;
double v = 256.0 * (1.0 - (shadowweight * (15-i) / 15.0)); /* 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; shadowscale[i] = (int)v;
if(shadowscale[i] > 256) shadowscale[i] = 256; if(shadowscale[i] > 256) shadowscale[i] = 256;
if(shadowscale[i] < 0) shadowscale[i] = 0; if(shadowscale[i] < 0) shadowscale[i] = 0;
} }
} }
} }
o = configuration.get("ambientlight");
if(o != null) {
int v = Integer.parseInt(String.valueOf(o));
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")); colorScheme = ColorScheme.getScheme((String)configuration.get("colorscheme"));
night_and_day = configuration.getBoolean("night-and-day", false);
} }
public boolean render(MapChunkCache cache, KzedMapTile tile, File outputFile) { public boolean render(MapChunkCache cache, KzedMapTile tile, File outputFile) {
@ -70,10 +87,15 @@ public class DefaultTileRenderer implements MapTileRenderer {
boolean isnether = (world.getEnvironment() == Environment.NETHER); boolean isnether = (world.getEnvironment() == Environment.NETHER);
BufferedImage im = KzedMap.allocateBufferedImage(KzedMap.tileWidth, KzedMap.tileHeight); BufferedImage im = KzedMap.allocateBufferedImage(KzedMap.tileWidth, KzedMap.tileHeight);
BufferedImage zim = KzedMap.allocateBufferedImage(KzedMap.tileWidth/2, KzedMap.tileHeight/2); BufferedImage zim = KzedMap.allocateBufferedImage(KzedMap.tileWidth/2, KzedMap.tileHeight/2);
WritableRaster r = im.getRaster();
WritableRaster zr = zim.getRaster();
boolean isempty = true; boolean isempty = true;
BufferedImage im_day = null;
BufferedImage zim_day = null;
if(night_and_day) {
im_day = KzedMap.allocateBufferedImage(KzedMap.tileWidth, KzedMap.tileHeight);
zim_day = KzedMap.allocateBufferedImage(KzedMap.tileWidth/2, KzedMap.tileHeight/2);
}
int ix = KzedMap.anchorx + tile.px / 2 + tile.py / 2 - ((127-maximumHeight)/2); int ix = KzedMap.anchorx + tile.px / 2 + tile.py / 2 - ((127-maximumHeight)/2);
int iy = maximumHeight; int iy = maximumHeight;
int iz = KzedMap.anchorz + tile.px / 2 - tile.py / 2 + ((127-maximumHeight)/2); int iz = KzedMap.anchorz + tile.px / 2 - tile.py / 2 + ((127-maximumHeight)/2);
@ -86,25 +108,40 @@ public class DefaultTileRenderer implements MapTileRenderer {
int x, y; int x, y;
MapChunkCache.MapIterator mapiter = cache.getIterator(ix, iy, iz);
Color c1 = new Color(); Color c1 = new Color();
Color c2 = new Color(); Color c2 = new Color();
int[] rgb = new int[3*KzedMap.tileWidth]; int[] argb = new int[KzedMap.tileWidth];
int[] zrgb = new int[3*KzedMap.tileWidth/2]; int[] zargb = new int[4*KzedMap.tileWidth/2];
Color c1_day = null;
Color c2_day = null;
int[] argb_day = null;
int[] zargb_day = null;
if(night_and_day) {
c1_day = new Color();
c2_day = new Color();
argb_day = new int[KzedMap.tileWidth];
zargb_day = new int[4*KzedMap.tileWidth/2];
}
/* draw the map */ /* draw the map */
for (y = 0; y < KzedMap.tileHeight;) { for (y = 0; y < KzedMap.tileHeight;) {
jx = ix; jx = ix;
jz = iz; jz = iz;
for (x = KzedMap.tileWidth - 1; x >= 0; x -= 2) { for (x = KzedMap.tileWidth - 1; x >= 0; x -= 2) {
scan(world, jx, iy, jz, 0, isnether, c1, cache); mapiter.initialize(jx, iy, jz);
scan(world, jx, iy, jz, 2, isnether, c2, cache); scan(world, 0, isnether, c1, c1_day, mapiter);
mapiter.initialize(jx, iy, jz);
scan(world, 2, isnether, c2, c2_day, mapiter);
rgb[3*x] = c1.getRed(); argb[x] = c1.getARGB();
rgb[3*x+1] = c1.getGreen(); argb[x-1] = c2.getARGB();
rgb[3*x+2] = c1.getBlue();
rgb[3*x-3] = c2.getRed(); if(night_and_day) {
rgb[3*x-2] = c2.getGreen(); argb_day[x] = c1_day.getARGB();
rgb[3*x-1] = c2.getBlue(); argb_day[x-1] = c2_day.getARGB();
}
isempty = isempty && c1.isTransparent() && c2.isTransparent(); isempty = isempty && c1.isTransparent() && c2.isTransparent();
@ -112,12 +149,23 @@ public class DefaultTileRenderer implements MapTileRenderer {
jz++; jz++;
} }
r.setPixels(0, y, KzedMap.tileWidth, 1, rgb); im.setRGB(0, y, KzedMap.tileWidth, 1, argb, 0, KzedMap.tileWidth);
if(night_and_day)
im_day.setRGB(0, y, KzedMap.tileWidth, 1, argb_day, 0, KzedMap.tileWidth);
/* Sum up zoomed pixels - bilinar filter */ /* Sum up zoomed pixels - bilinar filter */
for(x = 0; x < KzedMap.tileWidth / 2; x++) { for(x = 0; x < KzedMap.tileWidth / 2; x++) {
zrgb[3*x] = rgb[6*x] + rgb[6*x+3]; c1.setARGB(argb[2*x]);
zrgb[3*x+1] = rgb[6*x+1] + rgb[6*x+4]; c2.setARGB(argb[2*x+1]);
zrgb[3*x+2] = rgb[6*x+2] + rgb[6*x+5]; for(int i = 0; i < 4; i++)
zargb[4*x+i] = c1.getComponent(i) + c2.getComponent(i);
}
if(night_and_day) {
for(x = 0; x < KzedMap.tileWidth / 2; x++) {
c1.setARGB(argb_day[2*x]);
c2.setARGB(argb_day[2*x+1]);
for(int i = 0; i < 4; i++)
zargb_day[4*x+i] = c1.getComponent(i) + c2.getComponent(i);
}
} }
y++; y++;
@ -126,28 +174,50 @@ public class DefaultTileRenderer implements MapTileRenderer {
jz = iz - 1; jz = iz - 1;
for (x = KzedMap.tileWidth - 1; x >= 0; x -= 2) { for (x = KzedMap.tileWidth - 1; x >= 0; x -= 2) {
scan(world, jx, iy, jz, 2, isnether, c1, cache); mapiter.initialize(jx, iy, jz);
scan(world, 2, isnether, c1, c1_day, mapiter);
jx++; jx++;
jz++; jz++;
scan(world, jx, iy, jz, 0, isnether, c2, cache); mapiter.initialize(jx, iy, jz);
scan(world, 0, isnether, c2, c2_day, mapiter);
rgb[3*x] = c1.getRed(); argb[x] = c1.getARGB();
rgb[3*x+1] = c1.getGreen(); argb[x-1] = c2.getARGB();
rgb[3*x+2] = c1.getBlue();
rgb[3*x-3] = c2.getRed(); if(night_and_day) {
rgb[3*x-2] = c2.getGreen(); argb_day[x] = c1_day.getARGB();
rgb[3*x-1] = c2.getBlue(); argb_day[x-1] = c2_day.getARGB();
}
isempty = isempty && c1.isTransparent() && c2.isTransparent(); isempty = isempty && c1.isTransparent() && c2.isTransparent();
} }
r.setPixels(0, y, KzedMap.tileWidth, 1, rgb); im.setRGB(0, y, KzedMap.tileWidth, 1, argb, 0, KzedMap.tileWidth);
if(night_and_day)
im_day.setRGB(0, y, KzedMap.tileWidth, 1, argb_day, 0, KzedMap.tileWidth);
/* Finish summing values for zoomed pixels */ /* Finish summing values for zoomed pixels */
/* Sum up zoomed pixels - bilinar filter */
for(x = 0; x < KzedMap.tileWidth / 2; x++) { for(x = 0; x < KzedMap.tileWidth / 2; x++) {
zrgb[3*x] = (zrgb[3*x] + rgb[6*x] + rgb[6*x+3]) >> 2; c1.setARGB(argb[2*x]);
zrgb[3*x+1] = (zrgb[3*x+1] + rgb[6*x+1] + rgb[6*x+4]) >> 2; c2.setARGB(argb[2*x+1]);
zrgb[3*x+2] = (zrgb[3*x+2] + rgb[6*x+2] + rgb[6*x+5]) >> 2; for(int i = 0; i < 4; i++)
zargb[4*x+i] = (zargb[4*x+i] + c1.getComponent(i) + c2.getComponent(i)) >> 2;
c1.setRGBA(zargb[4*x+1], zargb[4*x+2], zargb[4*x+3], zargb[4*x]);
zargb[x] = c1.getARGB();
} }
zr.setPixels(0, y/2, KzedMap.tileWidth/2, 1, zrgb); if(night_and_day) {
for(x = 0; x < KzedMap.tileWidth / 2; x++) {
c1.setARGB(argb_day[2*x]);
c2.setARGB(argb_day[2*x+1]);
for(int i = 0; i < 4; i++)
zargb_day[4*x+i] = (zargb_day[4*x+i] + c1.getComponent(i) + c2.getComponent(i)) >> 2;
c1.setRGBA(zargb_day[4*x+1], zargb_day[4*x+2], zargb_day[4*x+3], zargb_day[4*x]);
zargb_day[x] = c1.getARGB();
}
}
zim.setRGB(0, y/2, KzedMap.tileWidth/2, 1, zargb, 0, KzedMap.tileWidth/2);
if(night_and_day)
zim_day.setRGB(0, y/2, KzedMap.tileWidth/2, 1, zargb_day, 0, KzedMap.tileWidth/2);
y++; y++;
@ -160,13 +230,15 @@ public class DefaultTileRenderer implements MapTileRenderer {
final KzedMapTile mtile = tile; final KzedMapTile mtile = tile;
final BufferedImage img = im; final BufferedImage img = im;
final BufferedImage zimg = zim; final BufferedImage zimg = zim;
final BufferedImage img_day = im_day;
final BufferedImage zimg_day = zim_day;
final KzedZoomedMapTile zmtile = new KzedZoomedMapTile(mtile.getWorld(), final KzedZoomedMapTile zmtile = new KzedZoomedMapTile(mtile.getWorld(),
(KzedMap) mtile.getMap(), mtile); (KzedMap) mtile.getMap(), mtile);
final File zoomFile = MapManager.mapman.getTileFile(zmtile); final File zoomFile = MapManager.mapman.getTileFile(zmtile);
MapManager.mapman.enqueueImageWrite(new Runnable() { MapManager.mapman.enqueueImageWrite(new Runnable() {
public void run() { public void run() {
doFileWrites(fname, mtile, img, zmtile, zoomFile, zimg); doFileWrites(fname, mtile, img, img_day, zmtile, zoomFile, zimg, zimg_day);
} }
}); });
@ -174,8 +246,9 @@ public class DefaultTileRenderer implements MapTileRenderer {
} }
private void doFileWrites(final File fname, final KzedMapTile mtile, private void doFileWrites(final File fname, final KzedMapTile mtile,
final BufferedImage img, final KzedZoomedMapTile zmtile, final File zoomFile, final BufferedImage img, final BufferedImage img_day,
final BufferedImage zimg) { final KzedZoomedMapTile zmtile, final File zoomFile,
final BufferedImage zimg, final BufferedImage zimg_day) {
Debug.debug("saving image " + fname.getPath()); Debug.debug("saving image " + fname.getPath());
try { try {
ImageIO.write(img, "png", fname); ImageIO.write(img, "png", fname);
@ -184,8 +257,19 @@ public class DefaultTileRenderer implements MapTileRenderer {
} catch (java.lang.NullPointerException e) { } catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + fname.getPath(), e); Debug.error("Failed to save image (NullPointerException): " + fname.getPath(), e);
} }
img.flush(); KzedMap.freeBufferedImage(img);
if(img_day != null) {
File dfname = new File(fname.getParent(), mtile.getDayFilename());
Debug.debug("saving image " + dfname.getPath());
try {
ImageIO.write(img_day, "png", dfname);
} catch (IOException e) {
Debug.error("Failed to save image: " + dfname.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + dfname.getPath(), e);
}
KzedMap.freeBufferedImage(img_day);
}
mtile.file = fname; mtile.file = fname;
// Since we've already got the new tile, and we're on an async thread, just // Since we've already got the new tile, and we're on an async thread, just
// make the zoomed tile here // make the zoomed tile here
@ -225,8 +309,8 @@ public class DefaultTileRenderer implements MapTileRenderer {
} }
/* blit scaled rendered tile onto zoom-out tile */ /* blit scaled rendered tile onto zoom-out tile */
WritableRaster zim = zIm.getRaster(); int[] pix = zimg.getRGB(0, 0, KzedMap.tileWidth/2, KzedMap.tileHeight/2, null, 0, KzedMap.tileWidth/2);
zim.setRect(ox, oy, zimg.getRaster()); zIm.setRGB(ox, oy, KzedMap.tileWidth/2, KzedMap.tileHeight/2, pix, 0, KzedMap.tileWidth/2);
KzedMap.freeBufferedImage(zimg); KzedMap.freeBufferedImage(zimg);
/* save zoom-out tile */ /* save zoom-out tile */
@ -243,23 +327,71 @@ public class DefaultTileRenderer implements MapTileRenderer {
KzedMap.freeBufferedImage(zIm); KzedMap.freeBufferedImage(zIm);
else else
zIm.flush(); zIm.flush();
if(zimg_day != null) {
File zoomFile_day = new File(zoomFile.getParent(), zmtile.getDayFilename());
zIm = null;
try {
zIm = ImageIO.read(zoomFile_day);
} catch (IOException e) {
} catch (IndexOutOfBoundsException e) {
}
zIm_allocated = false;
if (zIm == null) {
/* create new one */
zIm = KzedMap.allocateBufferedImage(KzedMap.tileWidth, KzedMap.tileHeight);
zIm_allocated = true;
Debug.debug("New zoom-out tile created " + zmtile.getFilename());
} else {
Debug.debug("Loaded zoom-out tile from " + zmtile.getFilename());
}
/* blit scaled rendered tile onto zoom-out tile */
pix = zimg_day.getRGB(0, 0, KzedMap.tileWidth/2, KzedMap.tileHeight/2, null, 0, KzedMap.tileWidth/2);
zIm.setRGB(ox, oy, KzedMap.tileWidth/2, KzedMap.tileHeight/2, pix, 0, KzedMap.tileWidth/2);
KzedMap.freeBufferedImage(zimg_day);
/* save zoom-out tile */
try {
ImageIO.write(zIm, "png", zoomFile_day);
Debug.debug("Saved zoom-out tile at " + zoomFile_day.getName());
} catch (IOException e) {
Debug.error("Failed to save zoom-out tile: " + zoomFile_day.getName(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save zoom-out tile (NullPointerException): " + zoomFile_day.getName(), e);
}
if(zIm_allocated)
KzedMap.freeBufferedImage(zIm);
else
zIm.flush();
}
/* Push updates for both files.*/ /* Push updates for both files.*/
MapManager.mapman.pushUpdate(mtile.getWorld(), MapManager.mapman.pushUpdate(mtile.getWorld(),
new Client.Tile(mtile.getFilename())); new Client.Tile(mtile.getFilename()));
MapManager.mapman.pushUpdate(zmtile.getWorld(), MapManager.mapman.pushUpdate(zmtile.getWorld(),
new Client.Tile(zmtile.getFilename())); new Client.Tile(zmtile.getFilename()));
if(img_day != null) {
MapManager.mapman.pushUpdate(mtile.getWorld(),
new Client.Tile(mtile.getDayFilename()));
MapManager.mapman.pushUpdate(zmtile.getWorld(),
new Client.Tile(zmtile.getDayFilename()));
}
} }
protected void scan(World world, int x, int y, int z, int seq, boolean isnether, final Color result, protected void scan(World world, int seq, boolean isnether, final Color result, final Color result_day,
MapChunkCache cache) { MapChunkCache.MapIterator mapiter) {
int lightlevel = 15; int lightlevel = 15;
int lightlevel_day = 15;
result.setTransparent(); result.setTransparent();
for (;;) { for (;;) {
if (y < 0) { if (mapiter.y < 0) {
return; return;
} }
int id = cache.getBlockTypeID(x, y, z); int id = mapiter.getBlockTypeID();
byte data = 0; int data = 0;
if(isnether) { /* Make bedrock ceiling into air in nether */ if(isnether) { /* Make bedrock ceiling into air in nether */
if(id != 0) { if(id != 0) {
/* Remember first color we see, in case we wind up solid */ /* Remember first color we see, in case we wind up solid */
@ -273,22 +405,40 @@ public class DefaultTileRenderer implements MapTileRenderer {
} }
if(id != 0) { /* No update needed for air */ if(id != 0) { /* No update needed for air */
if(colorScheme.datacolors[id] != null) { /* If data colored */ if(colorScheme.datacolors[id] != null) { /* If data colored */
data = cache.getBlockData(x, y, z); data = mapiter.getBlockData();
} }
if((shadowscale != null) && (y < 127)) { if((shadowscale != null) && (mapiter.y < 127)) {
/* Find light level of previous chunk */ /* Find light level of previous chunk */
switch(seq) { switch(seq) {
case 0: case 0:
lightlevel = cache.getBlockSkyLight(x, y+1, z); case 2:
mapiter.incrementY();
break; break;
case 1: case 1:
lightlevel = cache.getBlockSkyLight(x+1, y, z); mapiter.incrementX();
break;
case 2:
lightlevel = cache.getBlockSkyLight(x, y+1, z);
break; break;
case 3: case 3:
lightlevel = cache.getBlockSkyLight(x, y, z-1); mapiter.decrementZ();
break;
}
lightlevel = lightlevel_day = mapiter.getBlockSkyLight();
if(lightscale != null)
lightlevel = lightscale[lightlevel];
if((lightlevel < 15) || (lightlevel_day < 15)) {
int emitted = mapiter.getBlockEmittedLight();
lightlevel = Math.max(emitted, lightlevel);
lightlevel_day = Math.max(emitted, lightlevel_day);
}
switch(seq) {
case 0:
case 2:
mapiter.decrementY();
break;
case 1:
mapiter.decrementX();
break;
case 3:
mapiter.incrementZ();
break; break;
} }
} }
@ -296,16 +446,14 @@ public class DefaultTileRenderer implements MapTileRenderer {
switch (seq) { switch (seq) {
case 0: case 0:
x--; mapiter.decrementX();
break; break;
case 1: case 1:
y--; case 3:
mapiter.decrementY();
break; break;
case 2: case 2:
z++; mapiter.incrementZ();
break;
case 3:
y--;
break; break;
} }
@ -331,11 +479,20 @@ public class DefaultTileRenderer implements MapTileRenderer {
if(lightlevel < 15) { /* Not full light? */ if(lightlevel < 15) { /* Not full light? */
shadowColor(result, lightlevel); shadowColor(result, lightlevel);
} }
if(result_day != null) {
if(lightlevel_day == lightlevel) /* Same light = same result */
result_day.setColor(result);
else {
result_day.setColor(c);
if(lightlevel_day < 15)
shadowColor(result_day, lightlevel_day);
}
}
return; return;
} }
/* this block is transparent, so recurse */ /* this block is transparent, so recurse */
scan(world, x, y, z, seq, isnether, result, cache); scan(world, seq, isnether, result, result_day, mapiter);
int cr = c.getRed(); int cr = c.getRed();
int cg = c.getGreen(); int cg = c.getGreen();
@ -352,6 +509,23 @@ public class DefaultTileRenderer implements MapTileRenderer {
cb *= ca; cb *= ca;
int na = 255 - ca; int na = 255 - ca;
result.setRGBA((result.getRed() * na + cr) >> 8, (result.getGreen() * na + cg) >> 8, (result.getBlue() * na + cb) >> 8, 255); result.setRGBA((result.getRed() * na + cr) >> 8, (result.getGreen() * na + cg) >> 8, (result.getBlue() * na + cb) >> 8, 255);
/* Handle day also */
if(result_day != null) {
cr = c.getRed();
cg = c.getGreen();
cb = c.getBlue();
if(lightlevel_day < 15) {
int scale = shadowscale[lightlevel_day];
cr = (cr * scale) >> 8;
cg = (cg * scale) >> 8;
cb = (cb * scale) >> 8;
}
cr *= ca;
cg *= ca;
cb *= ca;
result_day.setRGBA((result_day.getRed() * na + cr) >> 8, (result_day.getGreen() * na + cg) >> 8, (result_day.getBlue() * na + cb) >> 8,
255);
}
return; return;
} }
} }
@ -374,6 +548,7 @@ public class DefaultTileRenderer implements MapTileRenderer {
s(o, "title", c.getString("title")); s(o, "title", c.getString("title"));
s(o, "icon", c.getString("icon")); s(o, "icon", c.getString("icon"));
s(o, "prefix", c.getString("prefix")); s(o, "prefix", c.getString("prefix"));
s(o, "nightandday", c.getBoolean("night-and-day", false));
a(worldObject, "maps", o); a(worldObject, "maps", o);
} }
} }

View File

@ -20,15 +20,15 @@ public class HighlightTileRenderer extends DefaultTileRenderer {
} }
@Override @Override
protected void scan(World world, int x, int y, int z, int seq, boolean isnether, final Color result, protected void scan(World world,int seq, boolean isnether, final Color result, final Color result_day,
MapChunkCache cache) { MapChunkCache.MapIterator mapiter) {
result.setTransparent(); result.setTransparent();
for (;;) { for (;;) {
if (y < 0) { if (mapiter.y < 0) {
break; break;
} }
int id = cache.getBlockTypeID(x, y, z); int id = mapiter.getBlockTypeID();
if(isnether) { /* Make bedrock ceiling into air in nether */ if(isnether) { /* Make bedrock ceiling into air in nether */
if(id != 0) { if(id != 0) {
/* Remember first color we see, in case we wind up solid */ /* Remember first color we see, in case we wind up solid */
@ -40,23 +40,21 @@ public class HighlightTileRenderer extends DefaultTileRenderer {
else else
isnether = false; isnether = false;
} }
byte data = 0; int data = 0;
if(colorScheme.datacolors[id] != null) { /* If data colored */ if(colorScheme.datacolors[id] != null) { /* If data colored */
data = cache.getBlockData(x, y, z); data = mapiter.getBlockData();
} }
switch (seq) { switch (seq) {
case 0: case 0:
x--; mapiter.decrementX();
break; break;
case 1: case 1:
y--; case 3:
mapiter.decrementY();
break; break;
case 2: case 2:
z++; mapiter.incrementZ();
break;
case 3:
y--;
break; break;
} }

View File

@ -278,7 +278,7 @@ public class KzedMap extends MapType {
img.setRGB(0, 0, x, y, zerobuf, 0, 0); img.setRGB(0, 0, x, y, zerobuf, 0, 0);
} }
else { else {
img = new BufferedImage(x, y, BufferedImage.TYPE_INT_RGB); img = new BufferedImage(x, y, BufferedImage.TYPE_INT_ARGB);
} }
return img; return img;
} }

View File

@ -26,6 +26,11 @@ public class KzedMapTile extends MapTile {
return renderer.getName() + "_" + px + "_" + py + ".png"; return renderer.getName() + "_" + px + "_" + py + ".png";
} }
@Override
public String getDayFilename() {
return renderer.getName() + "_day_" + px + "_" + py + ".png";
}
@Override @Override
public int hashCode() { public int hashCode() {
return getFilename().hashCode() ^ getWorld().hashCode(); return getFilename().hashCode() ^ getWorld().hashCode();

View File

@ -9,6 +9,11 @@ public class KzedZoomedMapTile extends MapTile {
return "z" + originalTile.renderer.getName() + "_" + getTileX() + "_" + getTileY() + ".png"; return "z" + originalTile.renderer.getName() + "_" + getTileX() + "_" + getTileY() + ".png";
} }
@Override
public String getDayFilename() {
return "z" + originalTile.renderer.getName() + "_day_" + getTileX() + "_" + getTileY() + ".png";
}
public KzedMapTile originalTile; public KzedMapTile originalTile;
public KzedZoomedMapTile(World world, KzedMap map, KzedMapTile original) { public KzedZoomedMapTile(World world, KzedMap map, KzedMapTile original) {