Merge pull request #232 from mikeprimm/master

Add support for configurable extra zoom out levels on each world - generates more tiers of zoomed images
This commit is contained in:
mikeprimm 2011-06-22 23:10:35 -07:00
commit 6d6a5f4db0
14 changed files with 398 additions and 35 deletions

View File

@ -73,6 +73,9 @@ display-whitelist: false
# How often a tile gets rendered (in seconds).
renderinterval: 1
# Zoom-out tile update period - how often to scan for and process tile updates into zoom-out tiles (in seconds)
zoomoutperiod: 60
# Tile hashing is used to minimize tile file updates when no changes have occurred - set to false to disable
enabletilehash: true
@ -133,6 +136,8 @@ templates:
enabled: true
# # If bigworld set to true, use alternate directory layout better suited to large worlds
# bigworld: true
# # Number of extra zoom-out levels for world (each level is twice as big as the previous one)
# extrazoomout: 3
center:
x: 0
y: 64
@ -209,6 +214,8 @@ templates:
enabled: true
# # If bigworld set to true, use alternate directory layout better suited to large worlds
# bigworld: true
# # Number of extra zoom-out levels for world (each level is twice as big as the previous one)
# extrazoomout: 3
center:
x: 0
y: 64
@ -238,6 +245,8 @@ templates:
enabled: true
# # If bigworld set to true, use alternate directory layout better suited to large worlds
# bigworld: true
# # Number of extra zoom-out levels for world (each level is twice as big as the previous one)
# extrazoomout: 3
center:
x: 0
y: 64
@ -312,6 +321,8 @@ worlds:
# z: 0
# # If bigworld set to true, use alternate directory layout better suited to large worlds
# bigworld: true
# # Number of extra zoom-out levels for world (each level is twice as big as the previous one)
# extrazoomout: 3
# maps:
# - class: org.dynmap.flat.FlatMap
# name: flat
@ -381,6 +392,8 @@ worlds:
# x: 0
# y: 64
# z: 0
# # Number of extra zoom-out levels for world (each level is twice as big as the previous one)
# extrazoomout: 3
# maps:
# - class: org.dynmap.flat.FlatMap
# name: flat

View File

@ -33,6 +33,7 @@ public class ClientConfigurationComponent extends Component {
s(wo, "center/y", wn.getFloat("center/y", 64.0f));
s(wo, "center/z", wn.getFloat("center/z", 0.0f));
s(wo, "bigworld", world.bigworld);
s(wo, "extrazoomout", world.extrazoomoutlevels);
a(t, "worlds", wo);
for(MapType mt : world.maps) {

View File

@ -5,8 +5,20 @@ import java.util.List;
import org.bukkit.World;
import org.bukkit.Location;
import org.dynmap.debug.Debug;
import org.dynmap.kzedmap.KzedMap;
import org.dynmap.kzedmap.KzedMap.KzedBufferedImage;
import org.dynmap.utils.FileLockManager;
import org.dynmap.utils.MapChunkCache;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.HashMap;
import javax.imageio.ImageIO;
public class DynmapWorld {
public World world;
public List<MapType> maps = new ArrayList<MapType>();
@ -19,4 +31,251 @@ public class DynmapWorld {
public boolean sendposition;
public boolean sendhealth;
public boolean bigworld; /* If true, deeper directory hierarchy */
public int extrazoomoutlevels; /* Number of additional zoom out levels to generate */
public File worldtilepath;
private static class DirFilter implements FilenameFilter {
public boolean accept(File f, String n) {
if(!n.equals("..") && !n.equals(".")) {
File fn = new File(f, n);
return fn.isDirectory();
}
return false;
}
}
private static class PNGFileFilter implements FilenameFilter {
String prefix;
public PNGFileFilter(String pre) { prefix = pre; }
public boolean accept(File f, String n) {
if(n.endsWith(".png") && n.startsWith(prefix)) {
File fn = new File(f, n);
return fn.isFile();
}
return false;
}
}
public void freshenZoomOutFiles() {
for(int i = 0; i < extrazoomoutlevels; i++) {
freshenZoomOutFilesByLevel(i);
}
}
private static class PrefixData {
int stepsize;
int[] stepseq;
boolean neg_step_x;
String baseprefix;
int zoomlevel;
String zoomprefix;
String fnprefix;
String zfnprefix;
}
public void freshenZoomOutFilesByLevel(int zoomlevel) {
int cnt = 0;
Debug.debug("freshenZoomOutFiles(" + world.getName() + "," + zoomlevel + ")");
if(worldtilepath.exists() == false) /* Quit if not found */
return;
HashMap<String, PrefixData> maptab = new HashMap<String, PrefixData>();
/* Build table of file prefixes and step sizes */
for(MapType mt : maps) {
List<String> pfx = mt.baseZoomFilePrefixes();
int stepsize = mt.baseZoomFileStepSize();
boolean neg_step_x = false;
if(stepsize < 0) {
stepsize = -stepsize;
neg_step_x = true;
}
int[] stepseq = mt.zoomFileStepSequence();
for(String p : pfx) {
PrefixData pd = new PrefixData();
pd.stepsize = stepsize;
pd.neg_step_x = neg_step_x;
pd.stepseq = stepseq;
pd.baseprefix = p;
pd.zoomlevel = zoomlevel;
pd.zoomprefix = "zzzzzzzzzzzz".substring(0, zoomlevel);
if(bigworld) {
if(zoomlevel > 0) {
pd.zoomprefix += "_";
pd.zfnprefix = "z" + pd.zoomprefix;
}
else {
pd.zfnprefix = "z_";
}
pd.fnprefix = pd.zoomprefix;
}
else {
pd.fnprefix = pd.zoomprefix + pd.baseprefix;
pd.zfnprefix = "z" + pd.fnprefix;
}
maptab.put(p, pd);
}
}
if(bigworld) { /* If big world, next directories are map name specific */
DirFilter df = new DirFilter();
for(String pfx : maptab.keySet()) { /* Walk through prefixes, as directories */
PrefixData pd = maptab.get(pfx);
File dname = new File(worldtilepath, pfx);
/* Now, go through subdirectories under this one, and process them */
String[] subdir = dname.list(df);
if(subdir == null) continue;
for(String s : subdir) {
File sdname = new File(dname, s);
cnt += processZoomDirectory(sdname, pd);
}
}
}
else { /* Else, classic file layout */
for(String pfx : maptab.keySet()) { /* Walk through prefixes, as directories */
cnt += processZoomDirectory(worldtilepath, maptab.get(pfx));
}
}
Debug.debug("freshenZoomOutFiles(" + world.getName() + "," + zoomlevel + ") - done (" + cnt + " updated files)");
}
private static class ProcessTileRec {
File zf;
String zfname;
int x, y;
}
private String makeFilePath(PrefixData pd, int x, int y, boolean zoomed) {
if(bigworld)
return pd.baseprefix + "/" + ((x/pd.stepsize) >> 5) + "_" + ((y/pd.stepsize) >> 5) + "/" + (zoomed?pd.zfnprefix:pd.fnprefix) + x + "_" + y + ".png";
else
return (zoomed?pd.zfnprefix:pd.fnprefix) + "_" + x + "_" + y + ".png";
}
private int processZoomDirectory(File dir, PrefixData pd) {
Debug.debug("processZoomDirectory(" + dir.getPath() + "," + pd.baseprefix + ")");
HashMap<String, ProcessTileRec> toprocess = new HashMap<String, ProcessTileRec>();
int step = pd.stepsize << pd.zoomlevel;
String[] files = dir.list(new PNGFileFilter(pd.fnprefix));
if(files == null)
return 0;
for(String fn : files) {
/* Build file object */
File f = new File(dir, fn);
/* Parse filename to predict zoomed out file */
fn = fn.substring(0, fn.lastIndexOf('.')); /* Strip off extension */
String[] tok = fn.split("_"); /* Split by underscores */
int x = 0;
int y = 0;
boolean parsed = false;
if(tok.length >= 2) {
try {
x = Integer.parseInt(tok[tok.length-2]);
y = Integer.parseInt(tok[tok.length-1]);
parsed = true;
} catch (NumberFormatException nfx) {
}
}
if(!parsed)
continue;
if(pd.neg_step_x) x = -x;
if(x >= 0)
x = x - (x % (2*step));
else
x = x + (x % (2*step));
if(pd.neg_step_x) x = -x;
if(y >= 0)
y = y - (y % (2*step));
else
y = y + (y % (2*step));
/* Make name of corresponding zoomed tile */
String zfname = makeFilePath(pd, x, y, true);
File zf = new File(worldtilepath, zfname);
/* If zoom file exists and is older than our file, nothing to do */
if(zf.exists() && (zf.lastModified() >= f.lastModified())) {
continue;
}
String zfpath = zf.getPath();
if(!toprocess.containsKey(zfpath)) {
ProcessTileRec rec = new ProcessTileRec();
rec.zf = zf;
rec.x = x;
rec.y = y;
rec.zfname = zfname;
toprocess.put(zfpath, rec);
}
}
int cnt = 0;
/* Do processing */
for(ProcessTileRec s : toprocess.values()) {
processZoomTile(pd, dir, s.zf, s.zfname, s.x - (pd.neg_step_x?step:0), s.y);
cnt++;
}
Debug.debug("processZoomDirectory(" + dir.getPath() + "," + pd.baseprefix + ") - done (" + cnt + " files)");
return cnt;
}
private void processZoomTile(PrefixData pd, File dir, File zf, String zfname, int tx, int ty) {
Debug.debug("processZoomFile(" + pd.baseprefix + "," + dir.getPath() + "," + zf.getPath() + "," + tx + "," + ty + ")");
int width = 128, height = 128;
BufferedImage zIm = null;
KzedBufferedImage kzIm = null;
int[] argb = new int[width*height];
int step = pd.stepsize << pd.zoomlevel;
/* create image buffer */
kzIm = KzedMap.allocateBufferedImage(width, height);
zIm = kzIm.buf_img;
for(int i = 0; i < 4; i++) {
File f = new File(worldtilepath, makeFilePath(pd, (tx + step*(1&pd.stepseq[i])), (ty + step*(pd.stepseq[i]>>1)), false));
if(f.exists()) {
BufferedImage im = null;
FileLockManager.getReadLock(f);
try {
im = ImageIO.read(f);
} catch (IOException e) {
} catch (IndexOutOfBoundsException e) {
}
FileLockManager.releaseReadLock(f);
if(im != null) {
im.getRGB(0, 0, width, height, argb, 0, width); /* Read data */
im.flush();
/* Do binlinear scale to 64x64 */
Color c1 = new Color();
for(int y = 0; y < height; y += 2) {
for(int x = 0; x < width; x += 2) {
int red = 0;
int green = 0;
int blue = 0;
int alpha = 0;
for(int yy = y; yy < y+2; yy++) {
for(int xx = x; xx < x+2; xx++) {
c1.setARGB(argb[(yy*width)+xx]);
red += c1.getRed();
green += c1.getGreen();
blue += c1.getBlue();
alpha += c1.getAlpha();
}
}
c1.setRGBA(red>>2, green>>2, blue>>2, alpha>>2);
argb[(y*width/2) + (x/2)] = c1.getARGB();
}
}
/* blit scaled rendered tile onto zoom-out tile */
zIm.setRGB(((i>>1) != 0)?0:width/2, (i & 1) * height/2, width/2, height/2, argb, 0, width);
}
}
}
FileLockManager.getWriteLock(zf);
try {
if(!zf.getParentFile().exists())
zf.getParentFile().mkdirs();
FileLockManager.imageIOWrite(zIm, "png", zf);
Debug.debug("Saved zoom-out tile at " + zf.getPath());
} catch (IOException e) {
Debug.error("Failed to save zoom-out tile: " + zf.getName(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save zoom-out tile (NullPointerException): " + zf.getName(), e);
}
FileLockManager.releaseWriteLock(zf);
KzedMap.freeBufferedImage(kzIm);
MapManager.mapman.pushUpdate(this.world, new Client.Tile(zfname));
}
}

View File

@ -26,13 +26,15 @@ public class MapManager {
public AsynchronousQueue<MapTile> tileQueue;
private static final int DEFAULT_CHUNKS_PER_TICK = 200;
private static final int DEFAULT_ZOOMOUT_PERIOD = 60;
public List<DynmapWorld> worlds = new ArrayList<DynmapWorld>();
public Map<String, DynmapWorld> worldsLookup = new HashMap<String, DynmapWorld>();
private BukkitScheduler scheduler;
private DynmapPlugin plug_in;
private long timeslice_int = 0; /* In milliseconds */
private int max_chunk_loads_per_tick = DEFAULT_CHUNKS_PER_TICK;
private int zoomout_period = DEFAULT_ZOOMOUT_PERIOD; /* Zoom-out tile processing period, in seconds */
/* Which fullrenders are active */
private HashMap<String, FullWorldRenderState> active_renders = new HashMap<String, FullWorldRenderState>();
/* List of MapChunkCache requests to be processed */
@ -261,6 +263,17 @@ public class MapManager {
}
}
private class DoZoomOutProcessing implements Runnable {
public void run() {
Debug.debug("DoZoomOutProcessing started");
for(DynmapWorld w : worlds) {
w.freshenZoomOutFiles();
}
renderpool.schedule(this, zoomout_period, TimeUnit.SECONDS);
Debug.debug("DoZoomOutProcessing finished");
}
}
public MapManager(DynmapPlugin plugin, ConfigurationNode configuration) {
plug_in = plugin;
mapman = this;
@ -276,6 +289,10 @@ public class MapManager {
timeslice_int = (long)(configuration.getDouble("timesliceinterval", 0.0) * 1000);
max_chunk_loads_per_tick = configuration.getInteger("maxchunkspertick", DEFAULT_CHUNKS_PER_TICK);
if(max_chunk_loads_per_tick < 5) max_chunk_loads_per_tick = 5;
/* Get zoomout processing periond in seconds */
zoomout_period = configuration.getInteger("zoomoutperiod", DEFAULT_ZOOMOUT_PERIOD);
if(zoomout_period < 5) zoomout_period = 5;
scheduler = plugin.getServer().getScheduler();
hashman = new TileHashManager(DynmapPlugin.tilesDirectory, configuration.getBoolean("enabletilehash", true));
@ -288,6 +305,7 @@ public class MapManager {
scheduler.scheduleSyncRepeatingTask(plugin, new CheckWorldTimes(), 5*20, 5*20); /* Check very 5 seconds */
scheduler.scheduleSyncRepeatingTask(plugin, new ProcessChunkLoads(), 1, 1); /* Chunk loader task */
}
void renderFullWorld(Location l, CommandSender sender) {
@ -343,6 +361,8 @@ public class MapManager {
dynmapWorld.sendposition = worldConfiguration.getBoolean("sendposition", true);
dynmapWorld.sendhealth = worldConfiguration.getBoolean("sendhealth", true);
dynmapWorld.bigworld = worldConfiguration.getBoolean("bigworld", false);
dynmapWorld.extrazoomoutlevels = worldConfiguration.getInteger("extrazoomout", 0);
dynmapWorld.worldtilepath = new File(plug_in.tilesDirectory, w.getName());
if(loclist != null) {
for(ConfigurationNode loc : loclist) {
Location lx = new Location(w, loc.getDouble("x", 0), loc.getDouble("y", 64), loc.getDouble("z", 0));
@ -422,6 +442,7 @@ public class MapManager {
public void startRendering() {
tileQueue.start();
renderpool = new DynmapScheduledThreadPoolExecutor();
renderpool.schedule(new DoZoomOutProcessing(), 60000, TimeUnit.MILLISECONDS);
}
public void stopRendering() {

View File

@ -28,4 +28,11 @@ public abstract class MapType {
public boolean isRawBiomeDataNeeded() { return false; }
public boolean isBlockTypeDataNeeded() { return true; }
public abstract List<String> baseZoomFilePrefixes();
public abstract int baseZoomFileStepSize();
/**
* Step sequence for creating zoomed file: first index is top-left, second top-right, third bottom-left, forth bottom-right
* Values correspond to tile X,Y (0), X+step,Y (1), X,Y+step (2), X+step,Y+step (3)
*/
public abstract int[] zoomFileStepSequence();
}

View File

@ -300,7 +300,7 @@ public class FlatMap extends MapType {
/* If day too, handle it */
if(night_and_day) {
File dayfile = new File(outputFile.getParent(), tile.getDayFilename());
File dayfile = new File(tile.getDynmapWorld().worldtilepath, tile.getDayFilename());
FileLockManager.getWriteLock(dayfile);
crc = hashman.calculateTileHash(argb_buf_day);
if((!dayfile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), "day", t.x, t.y))) {
@ -406,6 +406,19 @@ public class FlatMap extends MapType {
return prefix;
}
public List<String> baseZoomFilePrefixes() {
ArrayList<String> s = new ArrayList<String>();
s.add(getName() + "_128");
if(night_and_day)
s.add(getName()+"_day_128");
return s;
}
public int baseZoomFileStepSize() { return 1; }
private static final int[] stepseq = { 1, 3, 0, 2 };
public int[] zoomFileStepSequence() { return stepseq; }
public static class FlatMapTile extends MapTile {
FlatMap map;
@ -427,7 +440,7 @@ public class FlatMap extends MapType {
public String getFilename() {
if(fname == null) {
if(world.bigworld)
fname = map.prefix + "/" + ((-(y+1))>>5) + "_" + (x>>5) + "/" + size + "_" + -(y+1) + "_" + x + ".png";
fname = map.prefix + "_" + size + "/" + ((-(y+1))>>5) + "_" + (x>>5) + "/" + -(y+1) + "_" + x + ".png";
else
fname = map.prefix + "_" + size + "_" + -(y+1) + "_" + x + ".png";
}
@ -437,7 +450,7 @@ public class FlatMap extends MapType {
public String getDayFilename() {
if(fname_day == null) {
if(world.bigworld)
fname_day = map.prefix + "_day/" + ((-(y+1))>>5) + "_" + (x>>5) + "/" + size + "_" + -(y+1) + "_" + x + ".png";
fname_day = map.prefix + "_day_" + size + "/" + ((-(y+1))>>5) + "_" + (x>>5) + "/" + -(y+1) + "_" + x + ".png";
else
fname_day = map.prefix + "_day_" + size + "_" + -(y+1) + "_" + x + ".png";
}

View File

@ -11,6 +11,8 @@ public class CaveTileRenderer extends DefaultTileRenderer {
super(configuration);
}
public boolean isNightAndDayEnabled() { return false; }
@Override
protected void scan(World world, int seq, boolean isnether, final Color result, final Color result_day,
MapIterator mapiter) {

View File

@ -48,6 +48,8 @@ public class DefaultTileRenderer implements MapTileRenderer {
return name;
}
public boolean isNightAndDayEnabled() { return night_and_day; }
public DefaultTileRenderer(ConfigurationNode configuration) {
this.configuration = configuration;
name = (String) configuration.get("prefix");
@ -282,7 +284,8 @@ public class DefaultTileRenderer implements MapTileRenderer {
mtile.file = fname;
boolean updated_dfname = false;
File dfname = new File(fname.getParent(), mtile.getDayFilename());
File dfname = new File(mtile.getDynmapWorld().worldtilepath, mtile.getDayFilename());
if(img_day != null) {
FileLockManager.getWriteLock(dfname);
crc = hashman.calculateTileHash(img.argb_buf);
@ -311,7 +314,7 @@ public class DefaultTileRenderer implements MapTileRenderer {
boolean ztile_updated = false;
FileLockManager.getWriteLock(zoomFile);
if(updated_fname || (!zoomFile.exists())) {
saveZoomedTile(zmtile, zoomFile, zimg, ox, oy);
saveZoomedTile(zmtile, zoomFile, zimg, ox, oy, null);
MapManager.mapman.pushUpdate(zmtile.getWorld(),
new Client.Tile(zmtile.getFilename()));
ztile_updated = true;
@ -321,11 +324,11 @@ public class DefaultTileRenderer implements MapTileRenderer {
MapManager.mapman.updateStatistics(zmtile, null, true, ztile_updated, !rendered);
if(zimg_day != null) {
File zoomFile_day = new File(zoomFile.getParent(), zmtile.getDayFilename());
File zoomFile_day = new File(zmtile.getDynmapWorld().worldtilepath, zmtile.getDayFilename());
ztile_updated = false;
FileLockManager.getWriteLock(zoomFile_day);
if(updated_dfname || (!zoomFile_day.exists())) {
saveZoomedTile(zmtile, zoomFile_day, zimg_day, ox, oy);
saveZoomedTile(zmtile, zoomFile_day, zimg_day, ox, oy, "day");
MapManager.mapman.pushUpdate(zmtile.getWorld(),
new Client.Tile(zmtile.getDayFilename()));
ztile_updated = true;
@ -337,7 +340,7 @@ public class DefaultTileRenderer implements MapTileRenderer {
}
private void saveZoomedTile(final KzedZoomedMapTile zmtile, final File zoomFile,
final KzedBufferedImage zimg, int ox, int oy) {
final KzedBufferedImage zimg, int ox, int oy, String subkey) {
BufferedImage zIm = null;
KzedBufferedImage kzIm = null;
try {
@ -372,6 +375,7 @@ public class DefaultTileRenderer implements MapTileRenderer {
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save zoom-out tile (NullPointerException): " + zoomFile.getName(), e);
}
if(zIm_allocated)
KzedMap.freeBufferedImage(kzIm);
else

View File

@ -326,6 +326,22 @@ public class KzedMap extends MapType {
return false;
}
public List<String> baseZoomFilePrefixes() {
ArrayList<String> s = new ArrayList<String>();
for(MapTileRenderer r : renderers) {
s.add("z" + r.getName());
if(r.isNightAndDayEnabled())
s.add("z" + r.getName() + "_day");
}
return s;
}
/* Return negative to flag negative X walk */
public int baseZoomFileStepSize() { return -zTileWidth; }
private static final int[] stepseq = { 0, 2, 1, 3 };
public int[] zoomFileStepSequence() { return stepseq; }
public String getName() {
return "KzedMap";
}

View File

@ -15,4 +15,5 @@ public interface MapTileRenderer {
boolean isBiomeDataNeeded();
boolean isRawBiomeDataNeeded();
boolean isNightAndDayEnabled();
}

View File

@ -72,10 +72,7 @@ public class RegionHandler extends FileHandler {
/* If not in list, remove it */
if(!idlist.contains(id)) {
regionData.remove(id);
log.info("discard " + id);
}
else
log.info("keep " + id);
}
}
try {

View File

@ -117,6 +117,7 @@ public class FileLockManager {
while(!done) {
try {
ImageIO.write(img, type, fname);
fname.setLastModified(System.currentTimeMillis());
done = true;
} catch (FileNotFoundException fnfx) { /* This seems to be what we get when file is locked by reader */
if(retrycnt < MAX_WRITE_RETRIES) {

View File

@ -1,5 +1,6 @@
function FlatProjection() {}
FlatProjection.prototype = {
extrazoom: 0,
fromLatLngToPoint: function(latLng) {
return new google.maps.Point(latLng.lat()*config.tileWidth, latLng.lng()*config.tileHeight);
},
@ -7,7 +8,7 @@ FlatProjection.prototype = {
return new google.maps.LatLng(point.x/config.tileWidth, point.y/config.tileHeight);
},
fromWorldToLatLng: function(x, y, z) {
return new google.maps.LatLng(-z / config.tileWidth, x / config.tileHeight);
return new google.maps.LatLng(-z / config.tileWidth / (1 << this.extrazoom), x / config.tileHeight / (1 << this.extrazoom));
}
};
@ -28,13 +29,25 @@ FlatMapType.prototype = $.extend(new DynMapType(), {
var dnprefix = '';
if(this.dynmap.map.mapTypes[this.dynmap.map.mapTypeId].nightandday && this.dynmap.serverday)
dnprefix = '_day';
var extrazoom = this.dynmap.world.extrazoomout;
if(zoom < extrazoom) {
var scale = 1 << (extrazoom-zoom);
var zprefix = "zzzzzzzzzzzz".substring(0, extrazoom-zoom);
if(this.dynmap.world.bigworld)
tileName = this.prefix + dnprefix + '/' + (coord.x >> 5) + '_' + (coord.y >> 5) +
'/128_' + coord.x + '_' + coord.y + '.png';
tileName = this.prefix + dnprefix + '_128/' + ((scale*coord.x) >> 5) + '_' + ((scale*coord.y) >> 5) +
'/' + zprefix + "_" + (scale*coord.x) + '_' + (scale*coord.y) + '.png';
else
tileName = zprefix + this.prefix + dnprefix + '_128_' + (scale*coord.x) + '_' + (scale*coord.y) + '.png';
imgSize = 128;
}
else {
if(this.dynmap.world.bigworld)
tileName = this.prefix + dnprefix + '_128/' + (coord.x >> 5) + '_' + (coord.y >> 5) +
'/' + coord.x + '_' + coord.y + '.png';
else
tileName = this.prefix + dnprefix + '_128_' + coord.x + '_' + coord.y + '.png';
imgSize = Math.pow(2, 7+zoom);
imgSize = Math.pow(2, 7+zoom-extrazoom);
}
var tile = $('<div/>')
.addClass('tile')
.css({
@ -58,7 +71,15 @@ FlatMapType.prototype = $.extend(new DynMapType(), {
},
updateTileSize: function(zoom) {
var size;
size = Math.pow(2, 7+zoom);
var extrazoom = this.dynmap.world.extrazoomout;
this.projection.extrazoom = extrazoom;
this.maxZoom = 3 + extrazoom;
if (zoom <= extrazoom) {
size = 128;
}
else {
size = Math.pow(2, 7+zoom-extrazoom);
}
this.tileSize = new google.maps.Size(size, size);
}
});

View File

@ -1,5 +1,6 @@
function KzedProjection() {}
KzedProjection.prototype = {
extrazoom: 0,
fromLatLngToPoint: function(latLng) {
var x = latLng.lng() * config.tileWidth;
var y = latLng.lat() * config.tileHeight;
@ -18,9 +19,10 @@ KzedProjection.prototype = {
var dz = +z;
var px = dx + dz;
var py = dx - dz - dy;
var scale = 2 << this.extrazoom;
var lng = -px / config.tileWidth / 2 + 0.5;
var lat = py / config.tileHeight / 2;
var lng = -px / config.tileWidth / scale + (1.0 / scale);
var lat = py / config.tileHeight / scale;
return new google.maps.LatLng(lat, lng);
}
@ -46,24 +48,26 @@ KzedMapType.prototype = $.extend(new DynMapType(), {
var dnprefix = '';
if(this.dynmap.map.mapTypes[this.dynmap.map.mapTypeId].nightandday && this.dynmap.serverday)
dnprefix = '_day';
if (zoom == 0) {
var extrazoom = this.dynmap.world.extrazoomout;
if (zoom <= extrazoom) {
var zpre = 'zzzzzzzzzzzzzzzz'.substring(0, extrazoom-zoom+1);
// Most zoomed out tiles.
tileSize = 128;
imgSize = tileSize;
var tilescale = 2 << (extrazoom-zoom);
if (this.dynmap.world.bigworld) {
tileName = 'z' + this.prefix + dnprefix + '/' + ((-coord.x * tileSize*2)>>12) +
'_' + ((coord.y * tileSize*2) >> 12) + '/' +
(-coord.x * tileSize*2) + '_' + (coord.y * tileSize*2) + '.png';
tileName = zpre + this.prefix + dnprefix + '/' + ((-coord.x * tileSize*tilescale)>>12) +
'_' + ((coord.y * tileSize*tilescale) >> 12) + '/' +
(-coord.x * tileSize*tilescale) + '_' + (coord.y * tileSize*tilescale) + '.png';
}
else {
tileName = 'z' + this.prefix + dnprefix + '_' + (-coord.x * tileSize*2) + '_' + (coord.y * tileSize*2) + '.png';
tileName = zpre + this.prefix + dnprefix + '_' + (-coord.x * tileSize*tilescale) + '_' + (coord.y * tileSize*tilescale) + '.png';
}
} else {
// Other zoom levels.
tileSize = 128;
imgSize = Math.pow(2, 6+zoom);
imgSize = Math.pow(2, 6+zoom-extrazoom);
if(this.dynmap.world.bigworld) {
tileName = this.prefix + dnprefix + '/' + ((-coord.x*tileSize) >> 12) + '_' +
((coord.y*tileSize)>>12) + '/' +
@ -109,10 +113,13 @@ KzedMapType.prototype = $.extend(new DynMapType(), {
},
updateTileSize: function(zoom) {
var size;
if (zoom == 0) {
var extrazoom = this.dynmap.world.extrazoomout;
this.projection.extrazoom = extrazoom;
this.maxZoom = 3 + extrazoom;
if (zoom <= extrazoom) {
size = 128;
} else {
size = Math.pow(2, 6+zoom);
size = Math.pow(2, 6+zoom-extrazoom);
}
this.tileSize = new google.maps.Size(size, size);
}