mirror of
https://github.com/webbukkit/dynmap.git
synced 2024-11-25 03:35:18 +01:00
Merge pull request #264 from mikeprimm/hdrender
First drop of HD Renderer
This commit is contained in:
commit
88fde1fcd6
30
lightings.txt
Normal file
30
lightings.txt
Normal file
@ -0,0 +1,30 @@
|
||||
lightings:
|
||||
# Default lighting - no effects, shadows, day/night
|
||||
- class: org.dynmap.hdmap.DefaultHDLighting
|
||||
name: default
|
||||
# Shadows enabled day mode
|
||||
- class: org.dynmap.hdmap.ShadowHDLighting
|
||||
name: shadows
|
||||
shadowstrength: 1.0
|
||||
# Night view (default moonight level is 4)
|
||||
- class: org.dynmap.hdmap.ShadowHDLighting
|
||||
name: night
|
||||
shadowstrength: 1.0
|
||||
ambientlight: 4
|
||||
# A 'bright' night view (easier to see unlit landscape dimly)
|
||||
- class: org.dynmap.hdmap.ShadowHDLighting
|
||||
name: brightnight
|
||||
shadowstrength: 1.0
|
||||
ambientlight: 8
|
||||
# Night and day view
|
||||
- class: org.dynmap.hdmap.ShadowHDLighting
|
||||
name: nightandday
|
||||
shadowstrength: 1.0
|
||||
ambientlight: 4
|
||||
night-and-day: true
|
||||
# 'Bright' Night and day view
|
||||
- class: org.dynmap.hdmap.ShadowHDLighting
|
||||
name: brightnightandday
|
||||
shadowstrength: 1.0
|
||||
ambientlight: 8
|
||||
night-and-day: true
|
308
perspectives.txt
Normal file
308
perspectives.txt
Normal file
@ -0,0 +1,308 @@
|
||||
perspectives:
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_S_60_lowres
|
||||
azimuth: 180
|
||||
inclination: 60
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_S_60_medres
|
||||
azimuth: 180
|
||||
inclination: 60
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_S_60_hires
|
||||
azimuth: 180
|
||||
inclination: 60
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_SE_60_lowres
|
||||
azimuth: 135
|
||||
inclination: 60
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_SE_60_medres
|
||||
azimuth: 135
|
||||
inclination: 60
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_SE_60_hires
|
||||
azimuth: 135
|
||||
inclination: 60
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_E_60_lowres
|
||||
azimuth: 90
|
||||
inclination: 60
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_E_60_medres
|
||||
azimuth: 90
|
||||
inclination: 60
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_E_60_hires
|
||||
azimuth: 90
|
||||
inclination: 60
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_NE_60_lowres
|
||||
azimuth: 45
|
||||
inclination: 60
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_NE_60_medres
|
||||
azimuth: 45
|
||||
inclination: 60
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_NE_60_hires
|
||||
azimuth: 45
|
||||
inclination: 60
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_N_60_lowres
|
||||
azimuth: 0
|
||||
inclination: 60
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_N_60_medres
|
||||
azimuth: 0
|
||||
inclination: 60
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_N_60_hires
|
||||
azimuth: 0
|
||||
inclination: 60
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_NW_60_lowres
|
||||
azimuth: 315
|
||||
inclination: 60
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_NW_60_medres
|
||||
azimuth: 315
|
||||
inclination: 60
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_NW_60_hires
|
||||
azimuth: 315
|
||||
inclination: 60
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_W_60_lowres
|
||||
azimuth: 270
|
||||
inclination: 60
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_W_60_medres
|
||||
azimuth: 270
|
||||
inclination: 60
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_W_60_hires
|
||||
azimuth: 270
|
||||
inclination: 60
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_SW_60_lowres
|
||||
azimuth: 225
|
||||
inclination: 60
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_SW_60_medres
|
||||
azimuth: 225
|
||||
inclination: 60
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_SW_60_hires
|
||||
azimuth: 225
|
||||
inclination: 60
|
||||
scale: 16
|
||||
|
||||
# Low angle perspectives (30 degrees)
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_S_30_lowres
|
||||
azimuth: 180
|
||||
inclination: 30
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_S_30_medres
|
||||
azimuth: 180
|
||||
inclination: 30
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_S_30_hires
|
||||
azimuth: 180
|
||||
inclination: 30
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_SE_30_lowres
|
||||
azimuth: 135
|
||||
inclination: 30
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_SE_30_medres
|
||||
azimuth: 135
|
||||
inclination: 30
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_SE_30_hires
|
||||
azimuth: 135
|
||||
inclination: 30
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_E_30_lowres
|
||||
azimuth: 90
|
||||
inclination: 30
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_E_30_medres
|
||||
azimuth: 90
|
||||
inclination: 30
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_E_30_hires
|
||||
azimuth: 90
|
||||
inclination: 30
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_NE_30_lowres
|
||||
azimuth: 45
|
||||
inclination: 30
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_NE_30_medres
|
||||
azimuth: 45
|
||||
inclination: 30
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_NE_30_hires
|
||||
azimuth: 45
|
||||
inclination: 30
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_N_30_lowres
|
||||
azimuth: 0
|
||||
inclination: 30
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_N_30_medres
|
||||
azimuth: 0
|
||||
inclination: 30
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_N_30_hires
|
||||
azimuth: 0
|
||||
inclination: 30
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_NW_30_lowres
|
||||
azimuth: 315
|
||||
inclination: 30
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_NW_30_medres
|
||||
azimuth: 315
|
||||
inclination: 30
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_NW_30_hires
|
||||
azimuth: 315
|
||||
inclination: 30
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_W_30_lowres
|
||||
azimuth: 270
|
||||
inclination: 30
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_W_30_medres
|
||||
azimuth: 270
|
||||
inclination: 30
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_W_30_hires
|
||||
azimuth: 270
|
||||
inclination: 30
|
||||
scale: 16
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_SW_30_lowres
|
||||
azimuth: 225
|
||||
inclination: 30
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_SW_30_medres
|
||||
azimuth: 225
|
||||
inclination: 30
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_SW_30_hires
|
||||
azimuth: 225
|
||||
inclination: 30
|
||||
scale: 16
|
||||
|
||||
# Vertical perspectives (90 deg)
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_N_90_lowres
|
||||
azimuth: 0
|
||||
inclination: 90
|
||||
scale: 4
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_N_90_medres
|
||||
azimuth: 0
|
||||
inclination: 90
|
||||
scale: 8
|
||||
|
||||
- class: org.dynmap.hdmap.IsoHDPerspective
|
||||
name: iso_N_90_hires
|
||||
azimuth: 0
|
||||
inclination: 90
|
||||
scale: 16
|
36
shaders.txt
Normal file
36
shaders.txt
Normal file
@ -0,0 +1,36 @@
|
||||
shaders:
|
||||
- class: org.dynmap.hdmap.DefaultHDShader
|
||||
name: default
|
||||
colorscheme: default
|
||||
|
||||
- class: org.dynmap.hdmap.DefaultHDShader
|
||||
name: ovocean
|
||||
colorscheme: ovocean
|
||||
|
||||
- class: org.dynmap.hdmap.DefaultHDShader
|
||||
name: flames
|
||||
colorscheme: flames
|
||||
|
||||
- class: org.dynmap.hdmap.DefaultHDShader
|
||||
name: sk89q
|
||||
colorscheme: sk89q
|
||||
|
||||
- class: org.dynmap.hdmap.DefaultHDShader
|
||||
name: biome
|
||||
biomecolored: biome
|
||||
|
||||
- class: org.dynmap.hdmap.DefaultHDShader
|
||||
name: temperature
|
||||
biomecolored: temperature
|
||||
|
||||
- class: org.dynmap.hdmap.DefaultHDShader
|
||||
name: rainfall
|
||||
biomecolored: rainfall
|
||||
|
||||
- class: org.dynmap.hdmap.DefaultHDShader
|
||||
name: no_transparency
|
||||
colorscheme: default
|
||||
transparency: false
|
||||
|
||||
- class: org.dynmap.hdmap.CaveHDShader
|
||||
name: cave
|
@ -27,7 +27,10 @@
|
||||
<directory>${project.basedir}</directory>
|
||||
<outputDirectory>/dynmap/</outputDirectory>
|
||||
<includes>
|
||||
<include>configuration.txt</include></includes></fileSet>
|
||||
<include>configuration.txt</include>
|
||||
<include>shaders.txt</include>
|
||||
<include>perspectives.txt</include>
|
||||
<include>lightings.txt</include></includes></fileSet>
|
||||
</fileSets>
|
||||
<files>
|
||||
<file>
|
||||
|
@ -37,7 +37,7 @@ public class ClientConfigurationComponent extends Component {
|
||||
a(t, "worlds", wo);
|
||||
|
||||
for(MapType mt : world.maps) {
|
||||
mt.buildClientConfiguration(wo);
|
||||
mt.buildClientConfiguration(wo, world);
|
||||
}
|
||||
}
|
||||
s(t, "defaultworld", c.getString("defaultworld", defaultWorld == null ? "world" : defaultWorld.world.getName()));
|
||||
|
@ -46,6 +46,9 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
public MapManager mapManager = null;
|
||||
public PlayerList playerList;
|
||||
public ConfigurationNode configuration;
|
||||
public ConfigurationNode shaderconfig;
|
||||
public ConfigurationNode perspectiveconfig;
|
||||
public ConfigurationNode lightingsconfig;
|
||||
public HashSet<String> enabledTriggers = new HashSet<String>();
|
||||
public PermissionProvider permissions;
|
||||
public ComponentManager componentManager = new ComponentManager();
|
||||
@ -77,6 +80,16 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
org.bukkit.util.config.Configuration bukkitConfiguration = new org.bukkit.util.config.Configuration(new File(this.getDataFolder(), "configuration.txt"));
|
||||
bukkitConfiguration.load();
|
||||
configuration = new ConfigurationNode(bukkitConfiguration);
|
||||
/* Load shaders and perspectives */
|
||||
org.bukkit.util.config.Configuration bukkitShaderConfig = new org.bukkit.util.config.Configuration(new File(this.getDataFolder(), "shaders.txt"));
|
||||
bukkitShaderConfig.load();
|
||||
shaderconfig = new ConfigurationNode(bukkitShaderConfig);
|
||||
org.bukkit.util.config.Configuration bukkitPerspectiveConfig = new org.bukkit.util.config.Configuration(new File(this.getDataFolder(), "perspectives.txt"));
|
||||
bukkitPerspectiveConfig.load();
|
||||
perspectiveconfig = new ConfigurationNode(bukkitPerspectiveConfig);
|
||||
org.bukkit.util.config.Configuration bukkitLightingsConfig = new org.bukkit.util.config.Configuration(new File(this.getDataFolder(), "lightings.txt"));
|
||||
bukkitLightingsConfig.load();
|
||||
lightingsconfig = new ConfigurationNode(bukkitLightingsConfig);
|
||||
|
||||
Log.verbose = configuration.getBoolean("verbose", true);
|
||||
|
||||
@ -90,7 +103,7 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
playerList = new PlayerList(getServer(), getFile("hiddenplayers.txt"), configuration);
|
||||
playerList.load();
|
||||
|
||||
mapManager = new MapManager(this, configuration);
|
||||
mapManager = new MapManager(this, configuration, shaderconfig, perspectiveconfig, lightingsconfig);
|
||||
mapManager.startRendering();
|
||||
|
||||
loadWebserver();
|
||||
|
@ -41,7 +41,8 @@ public class DynmapWorld {
|
||||
private int extrazoomoutlevels; /* Number of additional zoom out levels to generate */
|
||||
public File worldtilepath;
|
||||
private Object lock = new Object();
|
||||
private HashSet<String> zoomoutupdates[];
|
||||
@SuppressWarnings("unchecked")
|
||||
private HashSet<String> zoomoutupdates[] = new HashSet[0];
|
||||
private boolean checkts = true; /* Check timestamps on first run with new configuration */
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -59,15 +60,25 @@ public class DynmapWorld {
|
||||
}
|
||||
|
||||
private void enqueueZoomOutUpdate(File f, int level) {
|
||||
if(level >= extrazoomoutlevels)
|
||||
return;
|
||||
synchronized(lock) {
|
||||
if(level >= zoomoutupdates.length) {
|
||||
@SuppressWarnings("unchecked")
|
||||
HashSet<String> new_zoomout[] = new HashSet[level+1];
|
||||
System.arraycopy(zoomoutupdates, 0, new_zoomout, 0, zoomoutupdates.length);
|
||||
for(int i = 0; i < new_zoomout.length; i++) {
|
||||
if(i < zoomoutupdates.length)
|
||||
new_zoomout[i] = zoomoutupdates[i];
|
||||
else
|
||||
new_zoomout[i] = new HashSet<String>();
|
||||
}
|
||||
zoomoutupdates = new_zoomout;
|
||||
}
|
||||
zoomoutupdates[level].add(f.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean popQueuedUpdate(File f, int level) {
|
||||
if(level >= extrazoomoutlevels)
|
||||
if(level >= zoomoutupdates.length)
|
||||
return false;
|
||||
synchronized(lock) {
|
||||
return zoomoutupdates[level].remove(f.getPath());
|
||||
@ -97,8 +108,15 @@ public class DynmapWorld {
|
||||
}
|
||||
|
||||
public void freshenZoomOutFiles() {
|
||||
for(int i = 0; i < extrazoomoutlevels; i++) {
|
||||
freshenZoomOutFilesByLevel(i);
|
||||
boolean done = false;
|
||||
int last_done = 0;
|
||||
for(int i = 0; (!done); i++) {
|
||||
done = freshenZoomOutFilesByLevel(i);
|
||||
last_done = i;
|
||||
}
|
||||
/* Purge updates for levels above what any map needs */
|
||||
for(int i = last_done; i < zoomoutupdates.length; i++) {
|
||||
zoomoutupdates[i].clear();
|
||||
}
|
||||
checkts = false; /* Just handle queued updates after first scan */
|
||||
}
|
||||
@ -107,25 +125,27 @@ public class DynmapWorld {
|
||||
int stepsize;
|
||||
int[] stepseq;
|
||||
boolean neg_step_x;
|
||||
boolean neg_step_y;
|
||||
String baseprefix;
|
||||
int zoomlevel;
|
||||
String zoomprefix;
|
||||
String fnprefix;
|
||||
String zfnprefix;
|
||||
int bigworldshift;
|
||||
boolean isbigmap;
|
||||
}
|
||||
|
||||
public void freshenZoomOutFilesByLevel(int zoomlevel) {
|
||||
public boolean freshenZoomOutFilesByLevel(int zoomlevel) {
|
||||
int cnt = 0;
|
||||
Debug.debug("freshenZoomOutFiles(" + world.getName() + "," + zoomlevel + ")");
|
||||
if(worldtilepath.exists() == false) /* Quit if not found */
|
||||
return;
|
||||
return true;
|
||||
HashMap<String, PrefixData> maptab = buildPrefixData(zoomlevel);
|
||||
|
||||
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 */
|
||||
for(String pfx : maptab.keySet()) { /* Walk through prefixes */
|
||||
PrefixData pd = maptab.get(pfx);
|
||||
if(pd.isbigmap) { /* If big world, next directories are map name specific */
|
||||
File dname = new File(worldtilepath, pfx);
|
||||
/* Now, go through subdirectories under this one, and process them */
|
||||
String[] subdir = dname.list(df);
|
||||
@ -135,38 +155,53 @@ public class DynmapWorld {
|
||||
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)");
|
||||
/* Return true when we have none left at the level */
|
||||
return (maptab.size() == 0);
|
||||
}
|
||||
|
||||
private HashMap<String, PrefixData> buildPrefixData(int zoomlevel) {
|
||||
HashMap<String, PrefixData> maptab = new HashMap<String, PrefixData>();
|
||||
/* Build table of file prefixes and step sizes */
|
||||
for(MapType mt : maps) {
|
||||
/* If level is above top needed for this map, skip */
|
||||
if(zoomlevel > (this.extrazoomoutlevels + mt.getMapZoomOutLevels()))
|
||||
continue;
|
||||
List<String> pfx = mt.baseZoomFilePrefixes();
|
||||
int stepsize = mt.baseZoomFileStepSize();
|
||||
int bigworldshift = mt.getBigWorldShift();
|
||||
boolean neg_step_x = false;
|
||||
if(stepsize < 0) {
|
||||
stepsize = -stepsize;
|
||||
boolean neg_step_y = false;
|
||||
switch(mt.zoomFileMapStep()) {
|
||||
case X_PLUS_Y_PLUS:
|
||||
break;
|
||||
case X_MINUS_Y_PLUS:
|
||||
neg_step_x = true;
|
||||
break;
|
||||
case X_PLUS_Y_MINUS:
|
||||
neg_step_y = true;
|
||||
break;
|
||||
case X_MINUS_Y_MINUS:
|
||||
neg_step_x = neg_step_y = true;
|
||||
break;
|
||||
}
|
||||
int[] stepseq = mt.zoomFileStepSequence();
|
||||
for(String p : pfx) {
|
||||
PrefixData pd = new PrefixData();
|
||||
pd.stepsize = stepsize;
|
||||
pd.neg_step_x = neg_step_x;
|
||||
pd.neg_step_y = neg_step_y;
|
||||
pd.stepseq = stepseq;
|
||||
pd.baseprefix = p;
|
||||
pd.zoomlevel = zoomlevel;
|
||||
pd.zoomprefix = "zzzzzzzzzzzz".substring(0, zoomlevel);
|
||||
pd.zoomprefix = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz".substring(0, zoomlevel);
|
||||
pd.bigworldshift = bigworldshift;
|
||||
if(bigworld) {
|
||||
pd.isbigmap = mt.isBigWorldMap(this);
|
||||
if(pd.isbigmap) {
|
||||
if(zoomlevel > 0) {
|
||||
pd.zoomprefix += "_";
|
||||
pd.zfnprefix = "z" + pd.zoomprefix;
|
||||
@ -194,7 +229,7 @@ public class DynmapWorld {
|
||||
}
|
||||
|
||||
private String makeFilePath(PrefixData pd, int x, int y, boolean zoomed) {
|
||||
if(bigworld)
|
||||
if(pd.isbigmap)
|
||||
return pd.baseprefix + "/" + (x >> pd.bigworldshift) + "_" + (y >> pd.bigworldshift) + "/" + (zoomed?pd.zfnprefix:pd.fnprefix) + x + "_" + y + ".png";
|
||||
else
|
||||
return (zoomed?pd.zfnprefix:pd.fnprefix) + "_" + x + "_" + y + ".png";
|
||||
@ -255,10 +290,12 @@ public class DynmapWorld {
|
||||
else
|
||||
x = x + (x % (2*step));
|
||||
if(pd.neg_step_x) x = -x;
|
||||
if(pd.neg_step_y) y = -y;
|
||||
if(y >= 0)
|
||||
y = y - (y % (2*step));
|
||||
else
|
||||
y = y + (y % (2*step));
|
||||
if(pd.neg_step_y) y = -y;
|
||||
/* Make name of corresponding zoomed tile */
|
||||
String zfname = makeFilePath(pd, x, y, true);
|
||||
File zf = new File(worldtilepath, zfname);
|
||||
@ -285,7 +322,9 @@ public class DynmapWorld {
|
||||
int[] argb = new int[width*height];
|
||||
int step = pd.stepsize << pd.zoomlevel;
|
||||
int ztx = tx;
|
||||
int zty = ty;
|
||||
tx = tx - (pd.neg_step_x?step:0); /* Adjust for negative step */
|
||||
ty = ty - (pd.neg_step_y?step:0); /* Adjust for negative step */
|
||||
|
||||
/* create image buffer */
|
||||
kzIm = KzedMap.allocateBufferedImage(width, height);
|
||||
@ -338,7 +377,7 @@ public class DynmapWorld {
|
||||
TileHashManager hashman = MapManager.mapman.hashman;
|
||||
long crc = hashman.calculateTileHash(kzIm.argb_buf); /* Get hash of tile */
|
||||
int tilex = ztx/step/2;
|
||||
int tiley = ty/step/2;
|
||||
int tiley = zty/step/2;
|
||||
String key = world.getName()+".z"+pd.zoomprefix+pd.baseprefix;
|
||||
if((!zf.exists()) || (crc != MapManager.mapman.hashman.getImageHashCode(key, null, tilex, tiley))) {
|
||||
try {
|
||||
|
@ -21,6 +21,7 @@ import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.dynmap.DynmapWorld.AutoGenerateOption;
|
||||
import org.dynmap.debug.Debug;
|
||||
import org.dynmap.hdmap.HDMapManager;
|
||||
import org.dynmap.utils.LegacyMapChunkCache;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
import org.dynmap.utils.NewMapChunkCache;
|
||||
@ -48,6 +49,7 @@ public class MapManager {
|
||||
public static final Object lock = new Object();
|
||||
|
||||
public static MapManager mapman; /* Our singleton */
|
||||
public HDMapManager hdmapman;
|
||||
|
||||
/* Thread pool for processing renders */
|
||||
private DynmapScheduledThreadPoolExecutor renderpool;
|
||||
@ -99,7 +101,6 @@ public class MapManager {
|
||||
}
|
||||
@Override
|
||||
public void execute(final Runnable r) {
|
||||
final Runnable rr = r;
|
||||
try {
|
||||
super.execute(new Runnable() {
|
||||
public void run() {
|
||||
@ -222,21 +223,20 @@ public class MapManager {
|
||||
}
|
||||
World w = world.world;
|
||||
/* Fetch chunk cache from server thread */
|
||||
MapType mt = tile.getMap();
|
||||
List<DynmapChunk> requiredChunks = mt.getRequiredChunks(tile);
|
||||
MapChunkCache cache = createMapChunkCache(world, requiredChunks, mt.isBlockTypeDataNeeded(),
|
||||
mt.isHightestBlockYDataNeeded(), mt.isBiomeDataNeeded(),
|
||||
mt.isRawBiomeDataNeeded());
|
||||
List<DynmapChunk> requiredChunks = tile.getRequiredChunks();
|
||||
MapChunkCache cache = createMapChunkCache(world, requiredChunks, tile.isBlockTypeDataNeeded(),
|
||||
tile.isHightestBlockYDataNeeded(), tile.isBiomeDataNeeded(),
|
||||
tile.isRawBiomeDataNeeded());
|
||||
if(cache == null) {
|
||||
cleanup();
|
||||
return; /* Cancelled/aborted */
|
||||
}
|
||||
if(tile0 != null) { /* Single tile? */
|
||||
if(cache.isEmpty() == false)
|
||||
render(cache, tile); /* Just render */
|
||||
tile.render(cache);
|
||||
}
|
||||
else {
|
||||
if ((cache.isEmpty() == false) && render(cache, tile)) {
|
||||
if ((cache.isEmpty() == false) && tile.render(cache)) {
|
||||
found.remove(tile);
|
||||
rendered.add(tile);
|
||||
for (MapTile adjTile : map.getAdjecentTiles(tile)) {
|
||||
@ -319,9 +319,15 @@ public class MapManager {
|
||||
}
|
||||
}
|
||||
|
||||
public MapManager(DynmapPlugin plugin, ConfigurationNode configuration) {
|
||||
public MapManager(DynmapPlugin plugin, ConfigurationNode configuration, ConfigurationNode shadercfg, ConfigurationNode perspectivecfg,
|
||||
ConfigurationNode lightingscfg) {
|
||||
plug_in = plugin;
|
||||
mapman = this;
|
||||
/* Initialize HD map manager */
|
||||
hdmapman = new HDMapManager();
|
||||
hdmapman.loadHDShaders(shadercfg);
|
||||
hdmapman.loadHDPerspectives(perspectivecfg);
|
||||
hdmapman.loadHDLightings(lightingscfg);
|
||||
|
||||
this.tileQueue = new AsynchronousQueue<MapTile>(new Handler<MapTile>() {
|
||||
@Override
|
||||
@ -383,19 +389,12 @@ public class MapManager {
|
||||
}
|
||||
String worldName = w.getName();
|
||||
|
||||
Event.Listener<MapTile> invalitateListener = new Event.Listener<MapTile>() {
|
||||
@Override
|
||||
public void triggered(MapTile t) {
|
||||
invalidateTile(t);
|
||||
}
|
||||
};
|
||||
|
||||
DynmapWorld dynmapWorld = new DynmapWorld();
|
||||
dynmapWorld.world = w;
|
||||
dynmapWorld.configuration = worldConfiguration;
|
||||
Log.verboseinfo("Loading maps of world '" + worldName + "'...");
|
||||
for(MapType map : worldConfiguration.<MapType>createInstances("maps", new Class<?>[0], new Object[0])) {
|
||||
map.onTileInvalidated.addListener(invalitateListener);
|
||||
if(map.getName() != null)
|
||||
dynmapWorld.maps.add(map);
|
||||
}
|
||||
Log.info("Loaded " + dynmapWorld.maps.size() + " maps of world '" + worldName + "'.");
|
||||
@ -407,7 +406,7 @@ public class MapManager {
|
||||
dynmapWorld.sendhealth = worldConfiguration.getBoolean("sendhealth", true);
|
||||
dynmapWorld.bigworld = worldConfiguration.getBoolean("bigworld", false);
|
||||
dynmapWorld.setExtraZoomOutLevels(worldConfiguration.getInteger("extrazoomout", 0));
|
||||
dynmapWorld.worldtilepath = new File(plug_in.tilesDirectory, w.getName());
|
||||
dynmapWorld.worldtilepath = new File(DynmapPlugin.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));
|
||||
@ -509,13 +508,6 @@ public class MapManager {
|
||||
tileQueue.stop();
|
||||
}
|
||||
|
||||
public boolean render(MapChunkCache cache, MapTile tile) {
|
||||
boolean result = tile.getMap().render(cache, tile, getTileFile(tile));
|
||||
//Do update after async file write
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private HashMap<World, File> worldTileDirectories = new HashMap<World, File>();
|
||||
public File getTileFile(MapTile tile) {
|
||||
World world = tile.getWorld();
|
||||
|
@ -1,10 +1,18 @@
|
||||
package org.dynmap;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.dynmap.kzedmap.MapTileRenderer;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
|
||||
public abstract class MapTile {
|
||||
protected DynmapWorld world;
|
||||
private MapType map;
|
||||
|
||||
public abstract boolean render(MapChunkCache cache);
|
||||
public abstract List<DynmapChunk> getRequiredChunks();
|
||||
public abstract MapTile[] getAdjecentTiles();
|
||||
|
||||
public World getWorld() {
|
||||
return world.world;
|
||||
@ -14,17 +22,12 @@ public abstract class MapTile {
|
||||
return world;
|
||||
}
|
||||
|
||||
public MapType getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
public abstract String getFilename();
|
||||
|
||||
public abstract String getDayFilename();
|
||||
|
||||
public MapTile(DynmapWorld world, MapType map) {
|
||||
public MapTile(DynmapWorld world) {
|
||||
this.world = world;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -41,7 +44,11 @@ public abstract class MapTile {
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return world.world.getName() + "." + map.getName();
|
||||
}
|
||||
public abstract String getKey();
|
||||
|
||||
public boolean isBiomeDataNeeded() { return false; }
|
||||
public boolean isHightestBlockYDataNeeded() { return false; }
|
||||
public boolean isRawBiomeDataNeeded() { return false; }
|
||||
public boolean isBlockTypeDataNeeded() { return true; }
|
||||
|
||||
}
|
||||
|
@ -8,8 +8,6 @@ import org.dynmap.utils.MapChunkCache;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public abstract class MapType {
|
||||
public Event<MapTile> onTileInvalidated = new Event<MapTile>();
|
||||
|
||||
public abstract MapTile[] getTiles(Location l);
|
||||
|
||||
public abstract MapTile[] getAdjecentTiles(MapTile tile);
|
||||
@ -18,21 +16,26 @@ public abstract class MapType {
|
||||
|
||||
public abstract boolean render(MapChunkCache cache, MapTile tile, File outputFile);
|
||||
|
||||
public void buildClientConfiguration(JSONObject worldObject) {
|
||||
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld w) {
|
||||
}
|
||||
|
||||
public abstract String getName();
|
||||
|
||||
public boolean isBiomeDataNeeded() { return false; }
|
||||
public boolean isHightestBlockYDataNeeded() { return false; }
|
||||
public boolean isRawBiomeDataNeeded() { return false; }
|
||||
public boolean isBlockTypeDataNeeded() { return true; }
|
||||
|
||||
public enum MapStep {
|
||||
X_PLUS_Y_PLUS,
|
||||
X_PLUS_Y_MINUS,
|
||||
X_MINUS_Y_PLUS,
|
||||
X_MINUS_Y_MINUS
|
||||
}
|
||||
public abstract MapStep zoomFileMapStep();
|
||||
public abstract List<String> baseZoomFilePrefixes();
|
||||
public abstract int baseZoomFileStepSize();
|
||||
/* How many bits of coordinate are shifted off to make big world directory name */
|
||||
public abstract int getBigWorldShift();
|
||||
|
||||
/* Returns true if big world file structure is in effect for this map */
|
||||
public abstract boolean isBigWorldMap(DynmapWorld w);
|
||||
/* Return number of zoom levels needed by this map (before extra levels from extrazoomout) */
|
||||
public int getMapZoomOutLevels() { return 0; }
|
||||
/**
|
||||
* 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)
|
||||
|
@ -22,6 +22,7 @@ import org.dynmap.MapManager;
|
||||
import org.dynmap.TileHashManager;
|
||||
import org.dynmap.MapTile;
|
||||
import org.dynmap.MapType;
|
||||
import org.dynmap.MapType.MapStep;
|
||||
import org.dynmap.debug.Debug;
|
||||
import org.dynmap.kzedmap.KzedMap;
|
||||
import org.dynmap.kzedmap.KzedMap.KzedBufferedImage;
|
||||
@ -41,6 +42,7 @@ public class FlatMap extends MapType {
|
||||
protected boolean transparency;
|
||||
private enum Texture { NONE, SMOOTH, DITHER };
|
||||
private Texture textured = Texture.NONE;
|
||||
private boolean isbigmap;
|
||||
|
||||
public FlatMap(ConfigurationNode configuration) {
|
||||
this.configuration = configuration;
|
||||
@ -80,6 +82,7 @@ public class FlatMap extends MapType {
|
||||
textured = Texture.DITHER;
|
||||
else
|
||||
textured = Texture.SMOOTH;
|
||||
isbigmap = configuration.getBoolean("isbigmap", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -117,11 +120,6 @@ public class FlatMap extends MapType {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHightestBlockYDataNeeded() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean render(MapChunkCache cache, MapTile tile, File outputFile) {
|
||||
FlatMapTile t = (FlatMapTile) tile;
|
||||
@ -426,11 +424,19 @@ public class FlatMap extends MapType {
|
||||
|
||||
private static final int[] stepseq = { 1, 3, 0, 2 };
|
||||
|
||||
public MapStep zoomFileMapStep() { return MapStep.X_PLUS_Y_PLUS; }
|
||||
|
||||
public int[] zoomFileStepSequence() { return stepseq; }
|
||||
|
||||
/* How many bits of coordinate are shifted off to make big world directory name */
|
||||
public int getBigWorldShift() { return 5; }
|
||||
|
||||
/* Returns true if big world file structure is in effect for this map */
|
||||
@Override
|
||||
public boolean isBigWorldMap(DynmapWorld w) {
|
||||
return w.bigworld || isbigmap;
|
||||
}
|
||||
|
||||
public static class FlatMapTile extends MapTile {
|
||||
FlatMap map;
|
||||
public int x;
|
||||
@ -440,7 +446,7 @@ public class FlatMap extends MapType {
|
||||
private String fname_day;
|
||||
|
||||
public FlatMapTile(DynmapWorld world, FlatMap map, int x, int y, int size) {
|
||||
super(world, map);
|
||||
super(world);
|
||||
this.map = map;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
@ -470,10 +476,33 @@ public class FlatMap extends MapType {
|
||||
public String toString() {
|
||||
return getWorld().getName() + ":" + getFilename();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean render(MapChunkCache cache) {
|
||||
return map.render(cache, this, MapManager.mapman.getTileFile(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildClientConfiguration(JSONObject worldObject) {
|
||||
public List<DynmapChunk> getRequiredChunks() {
|
||||
return map.getRequiredChunks(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapTile[] getAdjecentTiles() {
|
||||
return map.getAdjecentTiles(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return world.world.getName() + "." + map.getName();
|
||||
}
|
||||
|
||||
public boolean isHightestBlockYDataNeeded() { return true; }
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld world) {
|
||||
ConfigurationNode c = configuration;
|
||||
JSONObject o = new JSONObject();
|
||||
s(o, "type", "FlatMapType");
|
||||
@ -485,6 +514,7 @@ public class FlatMap extends MapType {
|
||||
s(o, "nightandday", c.getBoolean("night-and-day",false));
|
||||
s(o, "backgroundday", c.getString("backgroundday"));
|
||||
s(o, "backgroundnight", c.getString("backgroundnight"));
|
||||
s(o, "bigmap", this.isBigWorldMap(world));
|
||||
a(worldObject, "maps", o);
|
||||
}
|
||||
}
|
||||
|
184
src/main/java/org/dynmap/hdmap/CaveHDShader.java
Normal file
184
src/main/java/org/dynmap/hdmap/CaveHDShader.java
Normal file
@ -0,0 +1,184 @@
|
||||
package org.dynmap.hdmap;
|
||||
|
||||
import static org.dynmap.JSONUtils.s;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.dynmap.Color;
|
||||
import org.dynmap.ColorScheme;
|
||||
import org.dynmap.ConfigurationNode;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
import org.dynmap.utils.MapIterator;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class CaveHDShader implements HDShader {
|
||||
private String name;
|
||||
|
||||
|
||||
public CaveHDShader(ConfigurationNode configuration) {
|
||||
name = (String) configuration.get("name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBiomeDataNeeded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRawBiomeDataNeeded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHightestBlockYDataNeeded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlockTypeDataNeeded() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSkyLightLevelNeeded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmittedLightLevelNeeded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private class OurShaderState implements HDShaderState {
|
||||
private Color color;
|
||||
protected MapIterator mapiter;
|
||||
protected HDMap map;
|
||||
private boolean air;
|
||||
|
||||
private OurShaderState(MapIterator mapiter, HDMap map) {
|
||||
this.mapiter = mapiter;
|
||||
this.map = map;
|
||||
this.color = new Color();
|
||||
}
|
||||
/**
|
||||
* Get our shader
|
||||
*/
|
||||
public HDShader getShader() {
|
||||
return CaveHDShader.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get our map
|
||||
*/
|
||||
public HDMap getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get our lighting
|
||||
*/
|
||||
public HDLighting getLighting() {
|
||||
return map.getLighting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset renderer state for new ray
|
||||
*/
|
||||
public void reset(HDPerspectiveState ps) {
|
||||
color.setTransparent();
|
||||
air = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process next ray step - called for each block on route
|
||||
* @return true if ray is done, false if ray needs to continue
|
||||
*/
|
||||
public boolean processBlock(HDPerspectiveState ps) {
|
||||
int blocktype = ps.getBlockTypeID();
|
||||
switch (blocktype) {
|
||||
case 0:
|
||||
case 20:
|
||||
case 18:
|
||||
case 17:
|
||||
case 78:
|
||||
case 79:
|
||||
break;
|
||||
default:
|
||||
air = false;
|
||||
return false;
|
||||
}
|
||||
if (!air) {
|
||||
int cr, cg, cb;
|
||||
int mult = 256;
|
||||
|
||||
if (mapiter.getY() < 64) {
|
||||
cr = 0;
|
||||
cg = 64 + mapiter.getY() * 3;
|
||||
cb = 255 - mapiter.getY() * 4;
|
||||
} else {
|
||||
cr = (mapiter.getY() - 64) * 4;
|
||||
cg = 255;
|
||||
cb = 0;
|
||||
}
|
||||
/* Figure out which color to use */
|
||||
switch(ps.getLastBlockStep()) {
|
||||
case X_PLUS:
|
||||
case X_MINUS:
|
||||
mult = 224;
|
||||
break;
|
||||
case Z_PLUS:
|
||||
case Z_MINUS:
|
||||
mult = 256;
|
||||
break;
|
||||
default:
|
||||
mult = 160;
|
||||
break;
|
||||
}
|
||||
cr = cr * mult / 256;
|
||||
cg = cg * mult / 256;
|
||||
cb = cb * mult / 256;
|
||||
|
||||
color.setRGBA(cr, cg, cb, 255);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Ray ended - used to report that ray has exited map (called if renderer has not reported complete)
|
||||
*/
|
||||
public void rayFinished(HDPerspectiveState ps) {
|
||||
}
|
||||
/**
|
||||
* Get result color - get resulting color for ray
|
||||
* @param c - object to store color value in
|
||||
* @param index - index of color to request (renderer specific - 0=default, 1=day for night/day renderer
|
||||
*/
|
||||
public void getRayColor(Color c, int index) {
|
||||
c.setColor(color);
|
||||
}
|
||||
/**
|
||||
* Clean up state object - called after last ray completed
|
||||
*/
|
||||
public void cleanup() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get renderer state object for use rendering a tile
|
||||
* @param map - map being rendered
|
||||
* @param cache - chunk cache containing data for tile to be rendered
|
||||
* @param mapiter - iterator used when traversing rays in tile
|
||||
* @return state object to use for all rays in tile
|
||||
*/
|
||||
public HDShaderState getStateInstance(HDMap map, MapChunkCache cache, MapIterator mapiter) {
|
||||
return new OurShaderState(mapiter, map);
|
||||
}
|
||||
|
||||
/* Add shader's contributions to JSON for map object */
|
||||
public void addClientConfiguration(JSONObject mapObject) {
|
||||
s(mapObject, "shader", name);
|
||||
}
|
||||
}
|
54
src/main/java/org/dynmap/hdmap/DefaultHDLighting.java
Normal file
54
src/main/java/org/dynmap/hdmap/DefaultHDLighting.java
Normal file
@ -0,0 +1,54 @@
|
||||
package org.dynmap.hdmap;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.dynmap.Color;
|
||||
import org.dynmap.ColorScheme;
|
||||
import org.dynmap.ConfigurationNode;
|
||||
import org.dynmap.hdmap.DefaultHDShader.BiomeColorOption;
|
||||
import org.json.simple.JSONObject;
|
||||
import static org.dynmap.JSONUtils.s;
|
||||
|
||||
public class DefaultHDLighting implements HDLighting {
|
||||
private String name;
|
||||
|
||||
public DefaultHDLighting(ConfigurationNode configuration) {
|
||||
name = (String) configuration.get("name");
|
||||
}
|
||||
|
||||
/* Get lighting name */
|
||||
public String getName() { return name; }
|
||||
|
||||
/* Apply lighting to given pixel colors (1 outcolor if normal, 2 if night/day) */
|
||||
public void applyLighting(HDPerspectiveState ps, HDShaderState ss, Color incolor, Color[] outcolor) {
|
||||
for(Color oc: outcolor)
|
||||
oc.setColor(incolor);
|
||||
}
|
||||
|
||||
/* Test if Biome Data is needed for this renderer */
|
||||
public boolean isBiomeDataNeeded() { return false; }
|
||||
|
||||
/* Test if raw biome temperature/rainfall data is needed */
|
||||
public boolean isRawBiomeDataNeeded() { return false; }
|
||||
|
||||
/* Test if highest block Y data is needed */
|
||||
public boolean isHightestBlockYDataNeeded() { return false; }
|
||||
|
||||
/* Tet if block type data needed */
|
||||
public boolean isBlockTypeDataNeeded() { return false; }
|
||||
|
||||
/* Test if night/day is enabled for this renderer */
|
||||
public boolean isNightAndDayEnabled() { return false; }
|
||||
|
||||
/* Test if sky light level needed */
|
||||
public boolean isSkyLightLevelNeeded() { return false; }
|
||||
|
||||
/* Test if emitted light level needed */
|
||||
public boolean isEmittedLightLevelNeeded() { return false; }
|
||||
|
||||
/* Add shader's contributions to JSON for map object */
|
||||
public void addClientConfiguration(JSONObject mapObject) {
|
||||
s(mapObject, "lighting", name);
|
||||
s(mapObject, "nightandday", isNightAndDayEnabled());
|
||||
}
|
||||
}
|
267
src/main/java/org/dynmap/hdmap/DefaultHDShader.java
Normal file
267
src/main/java/org/dynmap/hdmap/DefaultHDShader.java
Normal file
@ -0,0 +1,267 @@
|
||||
package org.dynmap.hdmap;
|
||||
|
||||
import static org.dynmap.JSONUtils.s;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.dynmap.Color;
|
||||
import org.dynmap.ColorScheme;
|
||||
import org.dynmap.ConfigurationNode;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
import org.dynmap.utils.MapIterator;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class DefaultHDShader implements HDShader {
|
||||
private String name;
|
||||
protected ColorScheme colorScheme;
|
||||
|
||||
protected boolean transparency; /* Is transparency support active? */
|
||||
public enum BiomeColorOption {
|
||||
NONE, BIOME, TEMPERATURE, RAINFALL
|
||||
}
|
||||
protected BiomeColorOption biomecolored = BiomeColorOption.NONE; /* Use biome for coloring */
|
||||
|
||||
public DefaultHDShader(ConfigurationNode configuration) {
|
||||
name = (String) configuration.get("name");
|
||||
colorScheme = ColorScheme.getScheme(configuration.getString("colorscheme", "default"));
|
||||
transparency = configuration.getBoolean("transparency", true); /* Default on */
|
||||
String biomeopt = configuration.getString("biomecolored", "none");
|
||||
if(biomeopt.equals("biome")) {
|
||||
biomecolored = BiomeColorOption.BIOME;
|
||||
}
|
||||
else if(biomeopt.equals("temperature")) {
|
||||
biomecolored = BiomeColorOption.TEMPERATURE;
|
||||
}
|
||||
else if(biomeopt.equals("rainfall")) {
|
||||
biomecolored = BiomeColorOption.RAINFALL;
|
||||
}
|
||||
else {
|
||||
biomecolored = BiomeColorOption.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBiomeDataNeeded() {
|
||||
return biomecolored == BiomeColorOption.BIOME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRawBiomeDataNeeded() {
|
||||
return (biomecolored == BiomeColorOption.RAINFALL) || (biomecolored == BiomeColorOption.TEMPERATURE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHightestBlockYDataNeeded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlockTypeDataNeeded() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSkyLightLevelNeeded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmittedLightLevelNeeded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private class OurShaderState implements HDShaderState {
|
||||
private Color color[];
|
||||
protected MapIterator mapiter;
|
||||
protected HDMap map;
|
||||
private Color tmpcolor[];
|
||||
private int pixelodd;
|
||||
private HDLighting lighting;
|
||||
|
||||
private OurShaderState(MapIterator mapiter, HDMap map) {
|
||||
this.mapiter = mapiter;
|
||||
this.map = map;
|
||||
this.lighting = map.getLighting();
|
||||
if(lighting.isNightAndDayEnabled()) {
|
||||
color = new Color[] { new Color(), new Color() };
|
||||
tmpcolor = new Color[] { new Color(), new Color() };
|
||||
}
|
||||
else {
|
||||
color = new Color[] { new Color() };
|
||||
tmpcolor = new Color[] { new Color() };
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get our shader
|
||||
*/
|
||||
public HDShader getShader() {
|
||||
return DefaultHDShader.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get our map
|
||||
*/
|
||||
public HDMap getMap() {
|
||||
return map;
|
||||
}
|
||||
/**
|
||||
* Get our lighting
|
||||
*/
|
||||
public HDLighting getLighting() {
|
||||
return lighting;
|
||||
}
|
||||
/**
|
||||
* Reset renderer state for new ray
|
||||
*/
|
||||
public void reset(HDPerspectiveState ps) {
|
||||
for(Color c: color)
|
||||
c.setTransparent();
|
||||
pixelodd = (ps.getPixelX() & 0x3) + (ps.getPixelY()<<1);
|
||||
}
|
||||
|
||||
protected Color[] getBlockColors(int blocktype, int blockdata) {
|
||||
if((blockdata != 0) && (colorScheme.datacolors[blocktype] != null))
|
||||
return colorScheme.datacolors[blocktype][blockdata];
|
||||
else
|
||||
return colorScheme.colors[blocktype];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process next ray step - called for each block on route
|
||||
* @return true if ray is done, false if ray needs to continue
|
||||
*/
|
||||
public boolean processBlock(HDPerspectiveState ps) {
|
||||
int i;
|
||||
int blocktype = ps.getBlockTypeID();
|
||||
if(blocktype == 0)
|
||||
return false;
|
||||
Color[] colors = getBlockColors(blocktype, ps.getBlockData());
|
||||
|
||||
if (colors != null) {
|
||||
int seq;
|
||||
/* Figure out which color to use */
|
||||
switch(ps.getLastBlockStep()) {
|
||||
case X_PLUS:
|
||||
case X_MINUS:
|
||||
seq = 0;
|
||||
break;
|
||||
case Z_PLUS:
|
||||
case Z_MINUS:
|
||||
seq = 2;
|
||||
break;
|
||||
default:
|
||||
if(((pixelodd + mapiter.getY()) & 0x03) == 0)
|
||||
seq = 3;
|
||||
else
|
||||
seq = 1;
|
||||
break;
|
||||
}
|
||||
Color c = colors[seq];
|
||||
if (c.getAlpha() > 0) {
|
||||
/* Handle light level, if needed */
|
||||
lighting.applyLighting(ps, this, c, tmpcolor);
|
||||
/* Blend color with accumulated color (weighted by alpha) */
|
||||
if(!transparency) { /* No transparency support */
|
||||
for(i = 0; i < color.length; i++)
|
||||
color[i].setARGB(tmpcolor[i].getARGB() | 0xFF000000);
|
||||
return true; /* We're done */
|
||||
}
|
||||
/* If no previous color contribution, use new color */
|
||||
else if(color[0].isTransparent()) {
|
||||
for(i = 0; i < color.length; i++)
|
||||
color[i].setColor(tmpcolor[i]);
|
||||
return (color[0].getAlpha() == 255);
|
||||
}
|
||||
/* Else, blend and generate new alpha */
|
||||
else {
|
||||
int alpha = color[0].getAlpha();
|
||||
int alpha2 = tmpcolor[0].getAlpha() * (255-alpha) / 255;
|
||||
int talpha = alpha + alpha2;
|
||||
for(i = 0; i < color.length; i++)
|
||||
color[i].setRGBA((tmpcolor[i].getRed()*alpha2 + color[i].getRed()*alpha) / talpha,
|
||||
(tmpcolor[i].getGreen()*alpha2 + color[i].getGreen()*alpha) / talpha,
|
||||
(tmpcolor[i].getBlue()*alpha2 + color[i].getBlue()*alpha) / talpha, talpha);
|
||||
return (talpha >= 254); /* If only one short, no meaningful contribution left */
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Ray ended - used to report that ray has exited map (called if renderer has not reported complete)
|
||||
*/
|
||||
public void rayFinished(HDPerspectiveState ps) {
|
||||
}
|
||||
/**
|
||||
* Get result color - get resulting color for ray
|
||||
* @param c - object to store color value in
|
||||
* @param index - index of color to request (renderer specific - 0=default, 1=day for night/day renderer
|
||||
*/
|
||||
public void getRayColor(Color c, int index) {
|
||||
c.setColor(color[index]);
|
||||
}
|
||||
/**
|
||||
* Clean up state object - called after last ray completed
|
||||
*/
|
||||
public void cleanup() {
|
||||
}
|
||||
}
|
||||
|
||||
private class OurBiomeShaderState extends OurShaderState {
|
||||
private OurBiomeShaderState(MapIterator mapiter, HDMap map) {
|
||||
super(mapiter, map);
|
||||
}
|
||||
protected Color[] getBlockColors(int blocktype, int blockdata) {
|
||||
Biome bio = mapiter.getBiome();
|
||||
if(bio != null)
|
||||
return colorScheme.biomecolors[bio.ordinal()];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class OurBiomeRainfallShaderState extends OurShaderState {
|
||||
private OurBiomeRainfallShaderState(MapIterator mapiter, HDMap map) {
|
||||
super(mapiter, map);
|
||||
}
|
||||
protected Color[] getBlockColors(int blocktype, int blockdata) {
|
||||
return colorScheme.getRainColor(mapiter.getRawBiomeRainfall());
|
||||
}
|
||||
}
|
||||
|
||||
private class OurBiomeTempShaderState extends OurShaderState {
|
||||
private OurBiomeTempShaderState(MapIterator mapiter, HDMap map) {
|
||||
super(mapiter, map);
|
||||
}
|
||||
protected Color[] getBlockColors(int blocktype, int blockdata) {
|
||||
return colorScheme.getTempColor(mapiter.getRawBiomeTemperature());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get renderer state object for use rendering a tile
|
||||
* @param map - map being rendered
|
||||
* @param cache - chunk cache containing data for tile to be rendered
|
||||
* @param mapiter - iterator used when traversing rays in tile
|
||||
* @return state object to use for all rays in tile
|
||||
*/
|
||||
public HDShaderState getStateInstance(HDMap map, MapChunkCache cache, MapIterator mapiter) {
|
||||
switch(biomecolored) {
|
||||
case NONE:
|
||||
return new OurShaderState(mapiter, map);
|
||||
case BIOME:
|
||||
return new OurBiomeShaderState(mapiter, map);
|
||||
case RAINFALL:
|
||||
return new OurBiomeRainfallShaderState(mapiter, map);
|
||||
case TEMPERATURE:
|
||||
return new OurBiomeTempShaderState(mapiter, map);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Add shader's contributions to JSON for map object */
|
||||
public void addClientConfiguration(JSONObject mapObject) {
|
||||
s(mapObject, "shader", name);
|
||||
}
|
||||
}
|
29
src/main/java/org/dynmap/hdmap/HDLighting.java
Normal file
29
src/main/java/org/dynmap/hdmap/HDLighting.java
Normal file
@ -0,0 +1,29 @@
|
||||
package org.dynmap.hdmap;
|
||||
|
||||
import org.dynmap.Color;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
import org.dynmap.utils.MapIterator;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public interface HDLighting {
|
||||
/* Get lighting name */
|
||||
String getName();
|
||||
/* Apply lighting to given pixel colors (1 outcolor if normal, 2 if night/day) */
|
||||
void applyLighting(HDPerspectiveState ps, HDShaderState ss, Color incolor, Color[] outcolor);
|
||||
/* Test if Biome Data is needed for this renderer */
|
||||
boolean isBiomeDataNeeded();
|
||||
/* Test if raw biome temperature/rainfall data is needed */
|
||||
boolean isRawBiomeDataNeeded();
|
||||
/* Test if highest block Y data is needed */
|
||||
boolean isHightestBlockYDataNeeded();
|
||||
/* Tet if block type data needed */
|
||||
boolean isBlockTypeDataNeeded();
|
||||
/* Test if night/day is enabled for this renderer */
|
||||
boolean isNightAndDayEnabled();
|
||||
/* Test if sky light level needed */
|
||||
boolean isSkyLightLevelNeeded();
|
||||
/* Test if emitted light level needed */
|
||||
boolean isEmittedLightLevelNeeded();
|
||||
/* Add shader's contributions to JSON for map object */
|
||||
void addClientConfiguration(JSONObject mapObject);
|
||||
}
|
154
src/main/java/org/dynmap/hdmap/HDMap.java
Normal file
154
src/main/java/org/dynmap/hdmap/HDMap.java
Normal file
@ -0,0 +1,154 @@
|
||||
package org.dynmap.hdmap;
|
||||
|
||||
import static org.dynmap.JSONUtils.a;
|
||||
import static org.dynmap.JSONUtils.s;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.bukkit.Location;
|
||||
import org.dynmap.ConfigurationNode;
|
||||
import org.dynmap.DynmapChunk;
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.MapManager;
|
||||
import org.dynmap.MapTile;
|
||||
import org.dynmap.MapType;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class HDMap extends MapType {
|
||||
private String name;
|
||||
private String prefix;
|
||||
private HDPerspective perspective;
|
||||
private HDShader shader;
|
||||
private HDLighting lighting;
|
||||
private ConfigurationNode configuration;
|
||||
private int mapzoomout;
|
||||
|
||||
public HDMap(ConfigurationNode configuration) {
|
||||
name = configuration.getString("name", null);
|
||||
if(name == null) {
|
||||
Log.severe("HDMap missing required attribute 'name' - disabled");
|
||||
return;
|
||||
}
|
||||
String perspectiveid = configuration.getString("perspective", "default");
|
||||
perspective = MapManager.mapman.hdmapman.perspectives.get(perspectiveid);
|
||||
if(perspective == null) {
|
||||
Log.severe("HDMap '"+name+"' loading invalid perspective '" + perspectiveid + "' - map disabled");
|
||||
name = null;
|
||||
return;
|
||||
}
|
||||
String shaderid = configuration.getString("shader", "default");
|
||||
shader = MapManager.mapman.hdmapman.shaders.get(shaderid);
|
||||
if(shader == null) {
|
||||
Log.severe("HDMap '"+name+"' loading invalid shader '" + shaderid + "' - map disabled");
|
||||
name = null;
|
||||
return;
|
||||
}
|
||||
String lightingid = configuration.getString("lighting", "default");
|
||||
lighting = MapManager.mapman.hdmapman.lightings.get(lightingid);
|
||||
if(lighting == null) {
|
||||
Log.severe("HDMap '"+name+"' loading invalid lighting '" + lighting + "' - map disabled");
|
||||
name = null;
|
||||
return;
|
||||
}
|
||||
prefix = configuration.getString("prefix", name);
|
||||
this.configuration = configuration;
|
||||
|
||||
/* Compute extra zoom outs needed for this map */
|
||||
double scale = perspective.getScale();
|
||||
mapzoomout = 0;
|
||||
while(scale >= 1.0) {
|
||||
mapzoomout++;
|
||||
scale = scale / 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
public HDShader getShader() { return shader; }
|
||||
public HDPerspective getPerspective() { return perspective; }
|
||||
public HDLighting getLighting() { return lighting; }
|
||||
|
||||
@Override
|
||||
public MapTile[] getTiles(Location loc) {
|
||||
return perspective.getTiles(loc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapTile[] getAdjecentTiles(MapTile tile) {
|
||||
return perspective.getAdjecentTiles(tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DynmapChunk> getRequiredChunks(MapTile tile) {
|
||||
return perspective.getRequiredChunks(tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean render(MapChunkCache cache, MapTile tile, File bogus) {
|
||||
if(tile instanceof HDMapTile)
|
||||
return perspective.render(cache, (HDMapTile)tile);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> baseZoomFilePrefixes() {
|
||||
ArrayList<String> s = new ArrayList<String>();
|
||||
s.add(prefix);
|
||||
if(lighting.isNightAndDayEnabled())
|
||||
s.add(prefix + "_day");
|
||||
return s;
|
||||
}
|
||||
|
||||
public int baseZoomFileStepSize() { return 1; }
|
||||
|
||||
private static final int[] stepseq = { 3, 1, 2, 0 };
|
||||
|
||||
public MapStep zoomFileMapStep() { return MapStep.X_PLUS_Y_MINUS; }
|
||||
|
||||
public int[] zoomFileStepSequence() { return stepseq; }
|
||||
|
||||
/* How many bits of coordinate are shifted off to make big world directory name */
|
||||
public int getBigWorldShift() { return 5; }
|
||||
|
||||
/* Returns true if big world file structure is in effect for this map */
|
||||
@Override
|
||||
public boolean isBigWorldMap(DynmapWorld w) { return true; } /* We always use it on these maps */
|
||||
|
||||
/* Return number of zoom levels needed by this map (before extra levels from extrazoomout) */
|
||||
public int getMapZoomOutLevels() {
|
||||
return mapzoomout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld world) {
|
||||
ConfigurationNode c = configuration;
|
||||
JSONObject o = new JSONObject();
|
||||
s(o, "type", "HDMapType");
|
||||
s(o, "name", name);
|
||||
s(o, "title", c.getString("title"));
|
||||
s(o, "icon", c.getString("icon"));
|
||||
s(o, "prefix", prefix);
|
||||
s(o, "background", c.getString("background"));
|
||||
s(o, "backgroundday", c.getString("backgroundday"));
|
||||
s(o, "backgroundnight", c.getString("backgroundnight"));
|
||||
s(o, "bigmap", true);
|
||||
s(o, "mapzoomout", (world.getExtraZoomOutLevels()+mapzoomout));
|
||||
perspective.addClientConfiguration(o);
|
||||
shader.addClientConfiguration(o);
|
||||
lighting.addClientConfiguration(o);
|
||||
|
||||
a(worldObject, "maps", o);
|
||||
|
||||
}
|
||||
}
|
136
src/main/java/org/dynmap/hdmap/HDMapManager.java
Normal file
136
src/main/java/org/dynmap/hdmap/HDMapManager.java
Normal file
@ -0,0 +1,136 @@
|
||||
package org.dynmap.hdmap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.dynmap.ConfigurationNode;
|
||||
import org.dynmap.DynmapChunk;
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.MapManager;
|
||||
import org.dynmap.MapTile;
|
||||
import org.dynmap.MapType;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
import org.dynmap.utils.MapIterator;
|
||||
|
||||
public class HDMapManager {
|
||||
public HashMap<String, HDShader> shaders = new HashMap<String, HDShader>();
|
||||
public HashMap<String, HDPerspective> perspectives = new HashMap<String, HDPerspective>();
|
||||
public HashMap<String, HDLighting> lightings = new HashMap<String, HDLighting>();
|
||||
public HashSet<HDMap> maps = new HashSet<HDMap>();
|
||||
public HashMap<String, ArrayList<HDMap>> maps_by_world_perspective = new HashMap<String, ArrayList<HDMap>>();
|
||||
|
||||
public void loadHDShaders(ConfigurationNode shadercfg) {
|
||||
Log.verboseinfo("Loading shaders...");
|
||||
for(HDShader shader : shadercfg.<HDShader>createInstances("shaders", new Class<?>[0], new Object[0])) {
|
||||
if(shader.getName() == null) continue;
|
||||
if(shaders.containsKey(shader.getName())) {
|
||||
Log.severe("Duplicate shader name '" + shader.getName() + "' - shader ignored");
|
||||
}
|
||||
else {
|
||||
shaders.put(shader.getName(), shader);
|
||||
}
|
||||
}
|
||||
Log.info("Loaded " + shaders.size() + " shaders.");
|
||||
}
|
||||
|
||||
public void loadHDPerspectives(ConfigurationNode perspectivecfg) {
|
||||
Log.verboseinfo("Loading perspectives...");
|
||||
for(HDPerspective perspective : perspectivecfg.<HDPerspective>createInstances("perspectives", new Class<?>[0], new Object[0])) {
|
||||
if(perspective.getName() == null) continue;
|
||||
if(perspectives.containsKey(perspective.getName())) {
|
||||
Log.severe("Duplicate perspective name '" + perspective.getName() + "' - perspective ignored");
|
||||
}
|
||||
else {
|
||||
perspectives.put(perspective.getName(), perspective);
|
||||
}
|
||||
}
|
||||
Log.info("Loaded " + perspectives.size() + " perspectives.");
|
||||
}
|
||||
|
||||
public void loadHDLightings(ConfigurationNode lightingcfg) {
|
||||
Log.verboseinfo("Loading lightings...");
|
||||
for(HDLighting lighting : lightingcfg.<HDLighting>createInstances("lightings", new Class<?>[0], new Object[0])) {
|
||||
if(lighting.getName() == null) continue;
|
||||
if(lightings.containsKey(lighting.getName())) {
|
||||
Log.severe("Duplicate lighting name '" + lighting.getName() + "' - lighting ignored");
|
||||
}
|
||||
else {
|
||||
lightings.put(lighting.getName(), lighting);
|
||||
}
|
||||
}
|
||||
Log.info("Loaded " + lightings.size() + " lightings.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize shader states for all shaders for given tile
|
||||
*/
|
||||
public HDShaderState[] getShaderStateForTile(HDMapTile tile, MapChunkCache cache, MapIterator mapiter) {
|
||||
DynmapWorld w = MapManager.mapman.worldsLookup.get(tile.getWorld().getName());
|
||||
if(w == null) return new HDShaderState[0];
|
||||
ArrayList<HDShaderState> shaders = new ArrayList<HDShaderState>();
|
||||
for(MapType map : w.maps) {
|
||||
if(map instanceof HDMap) {
|
||||
HDMap hdmap = (HDMap)map;
|
||||
if(hdmap.getPerspective() == tile.perspective) {
|
||||
shaders.add(hdmap.getShader().getStateInstance(hdmap, cache, mapiter));
|
||||
}
|
||||
}
|
||||
}
|
||||
return shaders.toArray(new HDShaderState[shaders.size()]);
|
||||
}
|
||||
|
||||
private static final int BIOMEDATAFLAG = 0;
|
||||
private static final int HIGHESTZFLAG = 1;
|
||||
private static final int RAWBIOMEFLAG = 2;
|
||||
private static final int BLOCKTYPEFLAG = 3;
|
||||
|
||||
public boolean isBiomeDataNeeded(HDMapTile t) {
|
||||
return getCachedFlags(t)[BIOMEDATAFLAG];
|
||||
}
|
||||
|
||||
public boolean isHightestBlockYDataNeeded(HDMapTile t) {
|
||||
return getCachedFlags(t)[HIGHESTZFLAG];
|
||||
}
|
||||
|
||||
public boolean isRawBiomeDataNeeded(HDMapTile t) {
|
||||
return getCachedFlags(t)[RAWBIOMEFLAG];
|
||||
}
|
||||
|
||||
public boolean isBlockTypeDataNeeded(HDMapTile t) {
|
||||
return getCachedFlags(t)[BLOCKTYPEFLAG];
|
||||
}
|
||||
|
||||
private HashMap<String, boolean[]> cached_data_flags_by_world_perspective = new HashMap<String, boolean[]>();
|
||||
|
||||
private boolean[] getCachedFlags(HDMapTile t) {
|
||||
String w = t.getWorld().getName();
|
||||
String k = w + "/" + t.perspective.getName();
|
||||
boolean[] flags = cached_data_flags_by_world_perspective.get(k);
|
||||
if(flags != null)
|
||||
return flags;
|
||||
flags = new boolean[4];
|
||||
cached_data_flags_by_world_perspective.put(k, flags);
|
||||
DynmapWorld dw = MapManager.mapman.worldsLookup.get(w);
|
||||
if(dw == null) return flags;
|
||||
|
||||
for(MapType map : dw.maps) {
|
||||
if(map instanceof HDMap) {
|
||||
HDMap hdmap = (HDMap)map;
|
||||
if(hdmap.getPerspective() == t.perspective) {
|
||||
HDShader sh = hdmap.getShader();
|
||||
HDLighting lt = hdmap.getLighting();
|
||||
flags[BIOMEDATAFLAG] |= sh.isBiomeDataNeeded() | lt.isBiomeDataNeeded();
|
||||
flags[HIGHESTZFLAG] |= sh.isHightestBlockYDataNeeded() | lt.isHightestBlockYDataNeeded();
|
||||
flags[RAWBIOMEFLAG] |= sh.isRawBiomeDataNeeded() | lt.isRawBiomeDataNeeded();
|
||||
flags[BLOCKTYPEFLAG] |= sh.isBlockTypeDataNeeded() | lt.isBlockTypeDataNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
}
|
89
src/main/java/org/dynmap/hdmap/HDMapTile.java
Normal file
89
src/main/java/org/dynmap/hdmap/HDMapTile.java
Normal file
@ -0,0 +1,89 @@
|
||||
package org.dynmap.hdmap;
|
||||
|
||||
import org.dynmap.DynmapChunk;
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.MapManager;
|
||||
|
||||
import java.util.List;
|
||||
import org.dynmap.MapTile;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
|
||||
public class HDMapTile extends MapTile {
|
||||
public HDPerspective perspective;
|
||||
public int tx, ty; /* Tile X and Tile Y are in tile coordinates (pixels/tile-size) */
|
||||
|
||||
public HDMapTile(DynmapWorld world, HDPerspective perspective, int tx, int ty) {
|
||||
super(world);
|
||||
this.perspective = perspective;
|
||||
this.tx = tx;
|
||||
this.ty = ty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return getFilename("hdmap");
|
||||
}
|
||||
|
||||
public String getFilename(String prefix) {
|
||||
return prefix + "/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + ".png";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDayFilename() {
|
||||
return getDayFilename("hdmap");
|
||||
}
|
||||
|
||||
public String getDayFilename(String prefix) {
|
||||
return prefix + "_day/" + (tx >> 5) + '_' + (ty >> 5) + '/' + tx + "_" + ty + ".png";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return perspective.getName().hashCode() ^ getWorld().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof HDMapTile) {
|
||||
return equals((HDMapTile) obj);
|
||||
}
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
public boolean equals(HDMapTile o) {
|
||||
return o.tx == tx && o.ty == ty && o.getWorld().equals(getWorld()) && (perspective.equals(o.perspective));
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return getWorld().getName() + "." + perspective.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getWorld().getName() + ":" + getFilename();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBiomeDataNeeded() { return MapManager.mapman.hdmapman.isBiomeDataNeeded(this); }
|
||||
|
||||
@Override
|
||||
public boolean isHightestBlockYDataNeeded() { return MapManager.mapman.hdmapman.isHightestBlockYDataNeeded(this); }
|
||||
|
||||
@Override
|
||||
public boolean isRawBiomeDataNeeded() { return MapManager.mapman.hdmapman.isRawBiomeDataNeeded(this); }
|
||||
|
||||
@Override
|
||||
public boolean isBlockTypeDataNeeded() { return MapManager.mapman.hdmapman.isBlockTypeDataNeeded(this); }
|
||||
|
||||
public boolean render(MapChunkCache cache) {
|
||||
return perspective.render(cache, this);
|
||||
}
|
||||
|
||||
public List<DynmapChunk> getRequiredChunks() {
|
||||
return perspective.getRequiredChunks(this);
|
||||
}
|
||||
|
||||
public MapTile[] getAdjecentTiles() {
|
||||
return perspective.getAdjecentTiles(this);
|
||||
}
|
||||
}
|
31
src/main/java/org/dynmap/hdmap/HDPerspective.java
Normal file
31
src/main/java/org/dynmap/hdmap/HDPerspective.java
Normal file
@ -0,0 +1,31 @@
|
||||
package org.dynmap.hdmap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.dynmap.DynmapChunk;
|
||||
import org.dynmap.MapTile;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public interface HDPerspective {
|
||||
/* Get name of perspective */
|
||||
String getName();
|
||||
/* Get tiles invalidated by change at given location */
|
||||
MapTile[] getTiles(Location loc);
|
||||
/* Get tiles adjacent to given tile */
|
||||
MapTile[] getAdjecentTiles(MapTile tile);
|
||||
/* Get chunks needed for given tile */
|
||||
List<DynmapChunk> getRequiredChunks(MapTile tile);
|
||||
/* Render given tile */
|
||||
boolean render(MapChunkCache cache, HDMapTile tile);
|
||||
|
||||
public boolean isBiomeDataNeeded();
|
||||
public boolean isHightestBlockYDataNeeded();
|
||||
public boolean isRawBiomeDataNeeded();
|
||||
public boolean isBlockTypeDataNeeded();
|
||||
|
||||
double getScale();
|
||||
|
||||
public void addClientConfiguration(JSONObject mapObject);
|
||||
}
|
55
src/main/java/org/dynmap/hdmap/HDPerspectiveState.java
Normal file
55
src/main/java/org/dynmap/hdmap/HDPerspectiveState.java
Normal file
@ -0,0 +1,55 @@
|
||||
package org.dynmap.hdmap;
|
||||
|
||||
import org.dynmap.utils.Vector3D;
|
||||
|
||||
public interface HDPerspectiveState {
|
||||
/* Represents last step of movement of the ray */
|
||||
public enum BlockStep {
|
||||
X_PLUS,
|
||||
Y_PLUS,
|
||||
Z_PLUS,
|
||||
X_MINUS,
|
||||
Y_MINUS,
|
||||
Z_MINUS
|
||||
};
|
||||
/**
|
||||
* Get sky light level - only available if shader requested it
|
||||
*/
|
||||
int getSkyLightLevel();
|
||||
/**
|
||||
* Get emitted light level - only available if shader requested it
|
||||
*/
|
||||
int getEmittedLightLevel();
|
||||
/**
|
||||
* Get current block type ID
|
||||
*/
|
||||
int getBlockTypeID();
|
||||
/**
|
||||
* Get current block data
|
||||
*/
|
||||
int getBlockData();
|
||||
/**
|
||||
* Get direction of last block step
|
||||
*/
|
||||
BlockStep getLastBlockStep();
|
||||
/**
|
||||
* Get perspective scale
|
||||
*/
|
||||
double getScale();
|
||||
/**
|
||||
* Get start of current ray, in world coordinates
|
||||
*/
|
||||
Vector3D getRayStart();
|
||||
/**
|
||||
* Get end of current ray, in world coordinates
|
||||
*/
|
||||
Vector3D getRayEnd();
|
||||
/**
|
||||
* Get pixel X coordinate
|
||||
*/
|
||||
int getPixelX();
|
||||
/**
|
||||
* Get pixel Y coordinate
|
||||
*/
|
||||
int getPixelY();
|
||||
}
|
36
src/main/java/org/dynmap/hdmap/HDShader.java
Normal file
36
src/main/java/org/dynmap/hdmap/HDShader.java
Normal file
@ -0,0 +1,36 @@
|
||||
package org.dynmap.hdmap;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
import org.dynmap.utils.MapIterator;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public interface HDShader {
|
||||
/* Get shader name */
|
||||
String getName();
|
||||
/**
|
||||
* Get renderer state object for use rendering a tile
|
||||
* @param map - map being rendered
|
||||
* @param cache - chunk cache containing data for tile to be rendered
|
||||
* @param mapiter - iterator used when traversing rays in tile
|
||||
* @return state object to use for all rays in tile
|
||||
*/
|
||||
HDShaderState getStateInstance(HDMap map, MapChunkCache cache, MapIterator mapiter);
|
||||
/* Test if Biome Data is needed for this renderer */
|
||||
boolean isBiomeDataNeeded();
|
||||
/* Test if raw biome temperature/rainfall data is needed */
|
||||
boolean isRawBiomeDataNeeded();
|
||||
/* Test if highest block Y data is needed */
|
||||
boolean isHightestBlockYDataNeeded();
|
||||
/* Tet if block type data needed */
|
||||
boolean isBlockTypeDataNeeded();
|
||||
/* Test if sky light level needed */
|
||||
boolean isSkyLightLevelNeeded();
|
||||
/* Test if emitted light level needed */
|
||||
boolean isEmittedLightLevelNeeded();
|
||||
/* Add shader's contributions to JSON for map object */
|
||||
void addClientConfiguration(JSONObject mapObject);
|
||||
|
||||
}
|
46
src/main/java/org/dynmap/hdmap/HDShaderState.java
Normal file
46
src/main/java/org/dynmap/hdmap/HDShaderState.java
Normal file
@ -0,0 +1,46 @@
|
||||
package org.dynmap.hdmap;
|
||||
|
||||
import org.dynmap.Color;
|
||||
import org.dynmap.utils.Vector3D;
|
||||
|
||||
/**
|
||||
* This interface is used to define the operational state of a renderer during raytracing
|
||||
* All method should be considered performance critical
|
||||
*/
|
||||
public interface HDShaderState {
|
||||
/**
|
||||
* Get our shader
|
||||
*/
|
||||
HDShader getShader();
|
||||
/**
|
||||
* Get our lighting
|
||||
*/
|
||||
HDLighting getLighting();
|
||||
/**
|
||||
* Get our map
|
||||
*/
|
||||
HDMap getMap();
|
||||
/**
|
||||
* Reset renderer state for new ray - passes in pixel coordinate for ray
|
||||
*/
|
||||
void reset(HDPerspectiveState ps);
|
||||
/**
|
||||
* Process next ray step - called for each block on route
|
||||
* @return true if ray is done, false if ray needs to continue
|
||||
*/
|
||||
boolean processBlock(HDPerspectiveState ps);
|
||||
/**
|
||||
* Ray ended - used to report that ray has exited map (called if renderer has not reported complete)
|
||||
*/
|
||||
void rayFinished(HDPerspectiveState ps);
|
||||
/**
|
||||
* Get result color - get resulting color for ray
|
||||
* @param c - object to store color value in
|
||||
* @param index - index of color to request (renderer specific - 0=default, 1=day for night/day renderer
|
||||
*/
|
||||
void getRayColor(Color c, int index);
|
||||
/**
|
||||
* Clean up state object - called after last ray completed
|
||||
*/
|
||||
void cleanup();
|
||||
}
|
683
src/main/java/org/dynmap/hdmap/IsoHDPerspective.java
Normal file
683
src/main/java/org/dynmap/hdmap/IsoHDPerspective.java
Normal file
@ -0,0 +1,683 @@
|
||||
package org.dynmap.hdmap;
|
||||
|
||||
import static org.dynmap.JSONUtils.s;
|
||||
|
||||
import org.dynmap.DynmapWorld;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.dynmap.Client;
|
||||
import org.dynmap.Color;
|
||||
import org.dynmap.ConfigurationNode;
|
||||
import org.dynmap.DynmapChunk;
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.MapManager;
|
||||
import org.dynmap.MapTile;
|
||||
import org.dynmap.TileHashManager;
|
||||
import org.dynmap.debug.Debug;
|
||||
import org.dynmap.hdmap.HDPerspectiveState.BlockStep;
|
||||
import org.dynmap.kzedmap.KzedMap.KzedBufferedImage;
|
||||
import org.dynmap.kzedmap.KzedMap;
|
||||
import org.dynmap.utils.FileLockManager;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
import org.dynmap.utils.MapIterator;
|
||||
import org.dynmap.utils.Matrix3D;
|
||||
import org.dynmap.utils.Vector3D;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class IsoHDPerspective implements HDPerspective {
|
||||
private String name;
|
||||
/* View angles */
|
||||
public double azimuth; /* Angle in degrees from looking north (0), east (90), south (180), or west (270) */
|
||||
public double inclination; /* Angle in degrees from horizontal (0) to vertical (90) */
|
||||
public double scale; /* Scale - tile pixel widths per block */
|
||||
|
||||
/* Coordinate space for tiles consists of a plane (X, Y), corresponding to the projection of each tile on to the
|
||||
* plane of the bottom of the world (X positive to the right, Y positive to the top), with Z+ corresponding to the
|
||||
* height above this plane on a vector towards the viewer). Logically, this makes the parallelogram representing the
|
||||
* space contributing to the tile have consistent tile-space X,Y coordinate pairs for both the top and bottom faces
|
||||
* Note that this is a classic right-hand coordinate system, while minecraft's world coordinates are left handed
|
||||
* (X+ is south, Y+ is up, Z+ is east).
|
||||
*/
|
||||
/* Transformation matrix for taking coordinate in world-space (x, y, z) and finding coordinate in tile space (x, y, z) */
|
||||
private Matrix3D world_to_map;
|
||||
private Matrix3D map_to_world;
|
||||
|
||||
/* dimensions of a map tile */
|
||||
public static final int tileWidth = 128;
|
||||
public static final int tileHeight = 128;
|
||||
|
||||
/* Maximum and minimum inclinations */
|
||||
public static final double MAX_INCLINATION = 90.0;
|
||||
public static final double MIN_INCLINATION = 20.0;
|
||||
|
||||
/* Maximum and minimum scale */
|
||||
public static final double MAX_SCALE = 64;
|
||||
public static final double MIN_SCALE = 1;
|
||||
|
||||
private boolean need_skylightlevel = false;
|
||||
private boolean need_emittedlightlevel = false;
|
||||
private boolean need_biomedata = false;
|
||||
private boolean need_rawbiomedata = false;
|
||||
|
||||
private class OurPerspectiveState implements HDPerspectiveState {
|
||||
int skylightlevel = 15;
|
||||
int emittedlightlevel = 0;
|
||||
int blocktypeid = 0;
|
||||
int blockdata = 0;
|
||||
Vector3D top, bottom;
|
||||
int px, py;
|
||||
BlockStep laststep = BlockStep.Y_MINUS;
|
||||
/**
|
||||
* Get sky light level - only available if shader requested it
|
||||
*/
|
||||
public final int getSkyLightLevel() { return skylightlevel; }
|
||||
/**
|
||||
* Get emitted light level - only available if shader requested it
|
||||
*/
|
||||
public final int getEmittedLightLevel() { return emittedlightlevel; }
|
||||
/**
|
||||
* Get current block type ID
|
||||
*/
|
||||
public final int getBlockTypeID() { return blocktypeid; }
|
||||
/**
|
||||
* Get current block data
|
||||
*/
|
||||
public final int getBlockData() { return blockdata; }
|
||||
/**
|
||||
* Get direction of last block step
|
||||
*/
|
||||
public final BlockStep getLastBlockStep() { return laststep; }
|
||||
/**
|
||||
* Get perspective scale
|
||||
*/
|
||||
public final double getScale() { return scale; }
|
||||
/**
|
||||
* Get start of current ray, in world coordinates
|
||||
*/
|
||||
public final Vector3D getRayStart() { return top; }
|
||||
/**
|
||||
* Get end of current ray, in world coordinates
|
||||
*/
|
||||
public final Vector3D getRayEnd() { return bottom; }
|
||||
/**
|
||||
* Get pixel X coordinate
|
||||
*/
|
||||
public final int getPixelX() { return px; }
|
||||
/**
|
||||
* Get pixel Y coordinate
|
||||
*/
|
||||
public final int getPixelY() { return py; }
|
||||
|
||||
}
|
||||
|
||||
public IsoHDPerspective(ConfigurationNode configuration) {
|
||||
name = configuration.getString("name", null);
|
||||
if(name == null) {
|
||||
Log.severe("Perspective definition missing name - must be defined and unique");
|
||||
return;
|
||||
}
|
||||
azimuth = configuration.getDouble("azimuth", 135.0); /* Get azimuth (default to classic kzed POV */
|
||||
inclination = configuration.getDouble("inclination", 60.0);
|
||||
if(inclination > MAX_INCLINATION) inclination = MAX_INCLINATION;
|
||||
if(inclination < MIN_INCLINATION) inclination = MIN_INCLINATION;
|
||||
scale = configuration.getDouble("scale", MIN_SCALE);
|
||||
if(scale < MIN_SCALE) scale = MIN_SCALE;
|
||||
if(scale > MAX_SCALE) scale = MAX_SCALE;
|
||||
Log.info("azimuth=" + azimuth + ", inclination=" + inclination + ", scale=" + scale);
|
||||
|
||||
/* Generate transform matrix for world-to-tile coordinate mapping */
|
||||
/* First, need to fix basic coordinate mismatches before rotation - we want zero azimuth to have north to top
|
||||
* (world -X -> tile +Y) and east to right (world -Z to tile +X), with height being up (world +Y -> tile +Z)
|
||||
*/
|
||||
Matrix3D transform = new Matrix3D(0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0);
|
||||
/* Next, rotate world counterclockwise around Z axis by azumuth angle */
|
||||
transform.rotateXY(180-azimuth);
|
||||
/* Next, rotate world by (90-inclination) degrees clockwise around +X axis */
|
||||
transform.rotateYZ(90.0-inclination);
|
||||
/* Finally, shear along Z axis to normalize Z to be height above map plane */
|
||||
transform.shearZ(0, Math.tan(Math.toRadians(90.0-inclination)));
|
||||
/* And scale Z to be same scale as world coordinates, and scale X and Y based on setting */
|
||||
transform.scale(scale, scale, Math.sin(Math.toRadians(inclination)));
|
||||
world_to_map = transform;
|
||||
/* Now, generate map to world tranform, by doing opposite actions in reverse order */
|
||||
transform = new Matrix3D();
|
||||
transform.scale(1.0/scale, 1.0/scale, 1/Math.sin(Math.toRadians(inclination)));
|
||||
transform.shearZ(0, -Math.tan(Math.toRadians(90.0-inclination)));
|
||||
transform.rotateYZ(-(90.0-inclination));
|
||||
transform.rotateXY(-180+azimuth);
|
||||
Matrix3D coordswap = new Matrix3D(0.0, -1.0, 0.0, 0.0, 0.0, 1.0, -1.0, 0.0, 0.0);
|
||||
transform.multiply(coordswap);
|
||||
map_to_world = transform;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapTile[] getTiles(Location loc) {
|
||||
DynmapWorld world = MapManager.mapman.getWorld(loc.getWorld().getName());
|
||||
HashSet<MapTile> tiles = new HashSet<MapTile>();
|
||||
Vector3D block = new Vector3D();
|
||||
block.setFromLocation(loc); /* Get coordinate for block */
|
||||
Vector3D corner = new Vector3D();
|
||||
/* Loop through corners of the cube */
|
||||
for(int i = 0; i < 2; i++) {
|
||||
double inity = block.y;
|
||||
for(int j = 0; j < 2; j++) {
|
||||
double initz = block.z;
|
||||
for(int k = 0; k < 2; k++) {
|
||||
world_to_map.transform(block, corner); /* Get map coordinate of corner */
|
||||
addTile(tiles, world, (int)Math.floor(corner.x/tileWidth), (int)Math.floor(corner.y/tileHeight));
|
||||
|
||||
block.z += 1;
|
||||
}
|
||||
block.z = initz;
|
||||
block.y += 1;
|
||||
}
|
||||
block.y = inity;
|
||||
block.x += 1;
|
||||
}
|
||||
MapTile[] result = tiles.toArray(new MapTile[tiles.size()]);
|
||||
Log.info("processed update for " + loc);
|
||||
for(MapTile mt : result)
|
||||
Log.info("need to render " + mt);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapTile[] getAdjecentTiles(MapTile tile) {
|
||||
HDMapTile t = (HDMapTile) tile;
|
||||
DynmapWorld w = t.getDynmapWorld();
|
||||
int x = t.tx;
|
||||
int y = t.ty;
|
||||
return new MapTile[] {
|
||||
new HDMapTile(w, this, x, y - 1),
|
||||
new HDMapTile(w, this, x + 1, y),
|
||||
new HDMapTile(w, this, x, y + 1),
|
||||
new HDMapTile(w, this, x - 1, y) };
|
||||
}
|
||||
|
||||
public void addTile(HashSet<MapTile> tiles, DynmapWorld world, int tx, int ty) {
|
||||
tiles.add(new HDMapTile(world, this, tx, ty));
|
||||
}
|
||||
|
||||
private static class Rectangle {
|
||||
double r0x, r0z; /* Coord of corner of rectangle */
|
||||
double s1x, s1z; /* Side vector for one edge */
|
||||
double s2x, s2z; /* Side vector for other edge */
|
||||
public Rectangle(Vector3D v1, Vector3D v2, Vector3D v3) {
|
||||
r0x = v1.x;
|
||||
r0z = v1.z;
|
||||
s1x = v2.x - v1.x;
|
||||
s1z = v2.z - v1.z;
|
||||
s2x = v3.x - v1.x;
|
||||
s2z = v3.z - v1.z;
|
||||
}
|
||||
public Rectangle() {
|
||||
}
|
||||
public void setSquare(double rx, double rz, double s) {
|
||||
this.r0x = rx;
|
||||
this.r0z = rz;
|
||||
this.s1x = s;
|
||||
this.s1z = 0;
|
||||
this.s2x = 0;
|
||||
this.s2z = s;
|
||||
}
|
||||
double getX(int idx) {
|
||||
return r0x + (((idx & 1) == 0)?0:s1x) + (((idx & 2) != 0)?0:s2x);
|
||||
}
|
||||
double getZ(int idx) {
|
||||
return r0z + (((idx & 1) == 0)?0:s1z) + (((idx & 2) != 0)?0:s2z);
|
||||
}
|
||||
/**
|
||||
* Test for overlap of projection of one vector on to anoter
|
||||
*/
|
||||
boolean testoverlap(double rx, double rz, double sx, double sz, Rectangle r) {
|
||||
double rmin_dot_s0 = Double.MAX_VALUE;
|
||||
double rmax_dot_s0 = Double.MIN_VALUE;
|
||||
/* Project each point from rectangle on to vector: find lowest and highest */
|
||||
for(int i = 0; i < 4; i++) {
|
||||
double r_x = r.getX(i) - rx; /* Get relative positon of second vector start to origin */
|
||||
double r_z = r.getZ(i) - rz;
|
||||
double r_dot_s0 = r_x*sx + r_z*sz; /* Projection of start of vector */
|
||||
if(r_dot_s0 < rmin_dot_s0) rmin_dot_s0 = r_dot_s0;
|
||||
if(r_dot_s0 > rmax_dot_s0) rmax_dot_s0 = r_dot_s0;
|
||||
}
|
||||
/* Compute dot products */
|
||||
double s0_dot_s0 = sx*sx + sz*sz; /* End of our side */
|
||||
if((rmax_dot_s0 < 0.0) || (rmin_dot_s0 > s0_dot_s0))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Test if two rectangles intersect
|
||||
* Based on separating axis theorem
|
||||
*/
|
||||
boolean testRectangleIntesectsRectangle(Rectangle r) {
|
||||
/* Test if projection of each edge of one rectangle on to each edge of the other yields overlap */
|
||||
if(testoverlap(r0x, r0z, s1x, s1z, r) && testoverlap(r0x, r0z, s2x, s2z, r) &&
|
||||
testoverlap(r0x+s1x, r0z+s1z, s2x, s2z, r) && testoverlap(r0x+s2x, r0z+s2z, s1x, s1z, r) &&
|
||||
r.testoverlap(r.r0x, r.r0z, r.s1x, r.s1z, this) && r.testoverlap(r.r0x, r.r0z, r.s2x, r.s2z, this) &&
|
||||
r.testoverlap(r.r0x+r.s1x, r.r0z+r.s1z, r.s2x, r.s2z, this) && r.testoverlap(r.r0x+r.s2x, r.r0z+r.s2z, r.s1x, r.s1z, this)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public String toString() {
|
||||
return "{ " + r0x + "," + r0z + "}x{" + (r0x+s1x) + ","+ + (r0z+s1z) + "}x{" + (r0x+s2x) + "," + (r0z+s2z) + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DynmapChunk> getRequiredChunks(MapTile tile) {
|
||||
if (!(tile instanceof HDMapTile))
|
||||
return Collections.emptyList();
|
||||
|
||||
HDMapTile t = (HDMapTile) tile;
|
||||
int min_chunk_x = Integer.MAX_VALUE;
|
||||
int max_chunk_x = Integer.MIN_VALUE;
|
||||
int min_chunk_z = Integer.MAX_VALUE;
|
||||
int max_chunk_z = Integer.MIN_VALUE;
|
||||
|
||||
/* Make corners for volume: 0 = bottom-lower-left, 1 = top-lower-left, 2=bottom-upper-left, 3=top-upper-left
|
||||
* 4 = bottom-lower-right, 5 = top-lower-right, 6 = bottom-upper-right, 7 = top-upper-right */
|
||||
Vector3D corners[] = new Vector3D[8];
|
||||
int[] chunk_x = new int[8];
|
||||
int[] chunk_z = new int[8];
|
||||
for(int x = t.tx, idx = 0; x <= (t.tx+1); x++) {
|
||||
for(int y = t.ty; y <= (t.ty+1); y++) {
|
||||
for(int z = 0; z <= 1; z++) {
|
||||
corners[idx] = new Vector3D();
|
||||
corners[idx].x = x*tileWidth; corners[idx].y = y*tileHeight; corners[idx].z = z*128;
|
||||
map_to_world.transform(corners[idx]);
|
||||
/* Compute chunk coordinates of corner */
|
||||
chunk_x[idx] = (int)Math.floor(corners[idx].x / 16);
|
||||
chunk_z[idx] = (int)Math.floor(corners[idx].z / 16);
|
||||
/* Compute min/max of chunk coordinates */
|
||||
if(min_chunk_x > chunk_x[idx]) min_chunk_x = chunk_x[idx];
|
||||
if(max_chunk_x < chunk_x[idx]) max_chunk_x = chunk_x[idx];
|
||||
if(min_chunk_z > chunk_z[idx]) min_chunk_z = chunk_z[idx];
|
||||
if(max_chunk_z < chunk_z[idx]) max_chunk_z = chunk_z[idx];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Make rectangles of X-Z projection of each side of the tile volume, 0 = top, 1 = bottom, 2 = left, 3 = right,
|
||||
* 4 = upper, 5 = lower */
|
||||
Rectangle rect[] = new Rectangle[6];
|
||||
rect[0] = new Rectangle(corners[1], corners[3], corners[5]);
|
||||
rect[1] = new Rectangle(corners[0], corners[2], corners[4]);
|
||||
rect[2] = new Rectangle(corners[0], corners[1], corners[2]);
|
||||
rect[3] = new Rectangle(corners[4], corners[5], corners[6]);
|
||||
rect[4] = new Rectangle(corners[2], corners[3], corners[6]);
|
||||
rect[5] = new Rectangle(corners[0], corners[1], corners[4]);
|
||||
|
||||
/* Now, need to walk through the min/max range to see which chunks are actually needed */
|
||||
ArrayList<DynmapChunk> chunks = new ArrayList<DynmapChunk>();
|
||||
Rectangle chunkrect = new Rectangle();
|
||||
int misscnt = 0;
|
||||
for(int x = min_chunk_x; x <= max_chunk_x; x++) {
|
||||
for(int z = min_chunk_z; z <= max_chunk_z; z++) {
|
||||
chunkrect.setSquare(x*16, z*16, 16);
|
||||
boolean hit = false;
|
||||
/* Check to see if square of chunk intersects any of our rectangle sides */
|
||||
for(int rctidx = 0; (!hit) && (rctidx < rect.length); rctidx++) {
|
||||
if(chunkrect.testRectangleIntesectsRectangle(rect[rctidx])) {
|
||||
hit = true;
|
||||
}
|
||||
}
|
||||
if(hit) {
|
||||
DynmapChunk chunk = new DynmapChunk(x, z);
|
||||
chunks.add(chunk);
|
||||
}
|
||||
else {
|
||||
misscnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean render(MapChunkCache cache, HDMapTile tile) {
|
||||
Color rslt = new Color();
|
||||
MapIterator mapiter = cache.getIterator(0, 0, 0);
|
||||
/* Build shader state object for each shader */
|
||||
HDShaderState[] shaderstate = MapManager.mapman.hdmapman.getShaderStateForTile(tile, cache, mapiter);
|
||||
int numshaders = shaderstate.length;
|
||||
if(numshaders == 0)
|
||||
return false;
|
||||
|
||||
/* Create buffered image for each */
|
||||
KzedBufferedImage im[] = new KzedBufferedImage[numshaders];
|
||||
KzedBufferedImage dayim[] = new KzedBufferedImage[numshaders];
|
||||
int[][] argb_buf = new int[numshaders][];
|
||||
int[][] day_argb_buf = new int[numshaders][];
|
||||
|
||||
for(int i = 0; i < numshaders; i++) {
|
||||
HDShader shader = shaderstate[i].getShader();
|
||||
HDLighting lighting = shaderstate[i].getLighting();
|
||||
if(shader.isEmittedLightLevelNeeded() || lighting.isEmittedLightLevelNeeded())
|
||||
need_emittedlightlevel = true;
|
||||
if(shader.isSkyLightLevelNeeded() || lighting.isSkyLightLevelNeeded())
|
||||
need_skylightlevel = true;
|
||||
im[i] = KzedMap.allocateBufferedImage(tileWidth, tileHeight);
|
||||
argb_buf[i] = im[i].argb_buf;
|
||||
if(lighting.isNightAndDayEnabled()) {
|
||||
dayim[i] = KzedMap.allocateBufferedImage(tileWidth, tileHeight);
|
||||
day_argb_buf[i] = dayim[i].argb_buf;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create perspective state object */
|
||||
OurPerspectiveState ps = new OurPerspectiveState();
|
||||
|
||||
ps.top = new Vector3D();
|
||||
ps.bottom = new Vector3D();
|
||||
double xbase = tile.tx * tileWidth;
|
||||
double ybase = tile.ty * tileHeight;
|
||||
boolean shaderdone[] = new boolean[numshaders];
|
||||
boolean rendered[] = new boolean[numshaders];
|
||||
for(int x = 0; x < tileWidth; x++) {
|
||||
ps.px = x;
|
||||
for(int y = 0; y < tileHeight; y++) {
|
||||
ps.top.x = ps.bottom.x = xbase + x + 0.5; /* Start at center of pixel at Y=127.5, bottom at Y=-0.5 */
|
||||
ps.top.y = ps.bottom.y = ybase + y + 0.5;
|
||||
ps.top.z = 127.5; ps.bottom.z = -0.5;
|
||||
map_to_world.transform(ps.top); /* Transform to world coordinates */
|
||||
map_to_world.transform(ps.bottom);
|
||||
ps.py = y;
|
||||
for(int i = 0; i < numshaders; i++) {
|
||||
shaderstate[i].reset(ps);
|
||||
}
|
||||
raytrace(cache, mapiter, ps, shaderstate, shaderdone);
|
||||
for(int i = 0; i < numshaders; i++) {
|
||||
if(shaderdone[i] == false) {
|
||||
shaderstate[i].rayFinished(ps);
|
||||
}
|
||||
else {
|
||||
shaderdone[i] = false;
|
||||
rendered[i] = true;
|
||||
}
|
||||
shaderstate[i].getRayColor(rslt, 0);
|
||||
argb_buf[i][(tileHeight-y-1)*tileWidth + x] = rslt.getARGB();
|
||||
if(day_argb_buf[i] != null) {
|
||||
shaderstate[i].getRayColor(rslt, 1);
|
||||
day_argb_buf[i][(tileHeight-y-1)*tileWidth + x] = rslt.getARGB();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean renderone = false;
|
||||
/* Test to see if we're unchanged from older tile */
|
||||
TileHashManager hashman = MapManager.mapman.hashman;
|
||||
for(int i = 0; i < numshaders; i++) {
|
||||
long crc = hashman.calculateTileHash(argb_buf[i]);
|
||||
boolean tile_update = false;
|
||||
String prefix = shaderstate[i].getMap().getPrefix();
|
||||
if(rendered[i]) {
|
||||
renderone = true;
|
||||
String fname = tile.getFilename(prefix);
|
||||
File f = new File(tile.getDynmapWorld().worldtilepath, fname);
|
||||
FileLockManager.getWriteLock(f);
|
||||
try {
|
||||
if((!f.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), prefix, tile.tx, tile.ty))) {
|
||||
/* Wrap buffer as buffered image */
|
||||
Debug.debug("saving image " + f.getPath());
|
||||
if(!f.getParentFile().exists())
|
||||
f.getParentFile().mkdirs();
|
||||
try {
|
||||
FileLockManager.imageIOWrite(im[i].buf_img, "png", f);
|
||||
} catch (IOException e) {
|
||||
Debug.error("Failed to save image: " + f.getPath(), e);
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Debug.error("Failed to save image (NullPointerException): " + f.getPath(), e);
|
||||
}
|
||||
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(fname));
|
||||
hashman.updateHashCode(tile.getKey(), prefix, tile.tx, tile.ty, crc);
|
||||
tile.getDynmapWorld().enqueueZoomOutUpdate(f);
|
||||
tile_update = true;
|
||||
}
|
||||
else {
|
||||
Debug.debug("skipping image " + f.getPath() + " - hash match");
|
||||
}
|
||||
} finally {
|
||||
FileLockManager.releaseWriteLock(f);
|
||||
KzedMap.freeBufferedImage(im[i]);
|
||||
}
|
||||
MapManager.mapman.updateStatistics(tile, prefix, true, tile_update, !rendered[i]);
|
||||
/* Handle day image, if needed */
|
||||
if(dayim[i] != null) {
|
||||
fname = tile.getDayFilename(prefix);
|
||||
f = new File(tile.getDynmapWorld().worldtilepath, fname);
|
||||
FileLockManager.getWriteLock(f);
|
||||
prefix = prefix+"_day";
|
||||
tile_update = false;
|
||||
try {
|
||||
if((!f.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), prefix, tile.tx, tile.ty))) {
|
||||
/* Wrap buffer as buffered image */
|
||||
Debug.debug("saving image " + f.getPath());
|
||||
if(!f.getParentFile().exists())
|
||||
f.getParentFile().mkdirs();
|
||||
try {
|
||||
FileLockManager.imageIOWrite(dayim[i].buf_img, "png", f);
|
||||
} catch (IOException e) {
|
||||
Debug.error("Failed to save image: " + f.getPath(), e);
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Debug.error("Failed to save image (NullPointerException): " + f.getPath(), e);
|
||||
}
|
||||
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(fname));
|
||||
hashman.updateHashCode(tile.getKey(), prefix, tile.tx, tile.ty, crc);
|
||||
tile.getDynmapWorld().enqueueZoomOutUpdate(f);
|
||||
tile_update = true;
|
||||
}
|
||||
else {
|
||||
Debug.debug("skipping image " + f.getPath() + " - hash match");
|
||||
}
|
||||
} finally {
|
||||
FileLockManager.releaseWriteLock(f);
|
||||
KzedMap.freeBufferedImage(dayim[i]);
|
||||
}
|
||||
MapManager.mapman.updateStatistics(tile, prefix, true, tile_update, !rendered[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return renderone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trace ray, based on "Voxel Tranversal along a 3D line"
|
||||
*/
|
||||
private void raytrace(MapChunkCache cache, MapIterator mapiter, OurPerspectiveState ps,
|
||||
HDShaderState[] shaderstate, boolean[] shaderdone) {
|
||||
Vector3D top = ps.top;
|
||||
Vector3D bottom = ps.bottom;
|
||||
/* Compute total delta on each axis */
|
||||
double dx = Math.abs(bottom.x - top.x);
|
||||
double dy = Math.abs(bottom.y - top.y);
|
||||
double dz = Math.abs(bottom.z - top.z);
|
||||
/* Initial block coord */
|
||||
int x = (int) (Math.floor(top.x));
|
||||
int y = (int) (Math.floor(top.y));
|
||||
int z = (int) (Math.floor(top.z));
|
||||
/* Compute parametric step (dt) per step on each axis */
|
||||
double dt_dx = 1.0 / dx;
|
||||
double dt_dy = 1.0 / dy;
|
||||
double dt_dz = 1.0 / dz;
|
||||
/* Initialize parametric value to 0 (and we're stepping towards 1) */
|
||||
double t = 0;
|
||||
/* Compute number of steps and increments for each */
|
||||
int n = 1;
|
||||
int x_inc, y_inc, z_inc;
|
||||
|
||||
double t_next_y, t_next_x, t_next_z;
|
||||
/* If perpendicular to X axis */
|
||||
if (dx == 0) {
|
||||
x_inc = 0;
|
||||
t_next_x = Double.MAX_VALUE;
|
||||
}
|
||||
/* If bottom is right of top */
|
||||
else if (bottom.x > top.x) {
|
||||
x_inc = 1;
|
||||
n += (int) (Math.floor(bottom.x)) - x;
|
||||
t_next_x = (Math.floor(top.x) + 1 - top.x) * dt_dx;
|
||||
}
|
||||
/* Top is right of bottom */
|
||||
else {
|
||||
x_inc = -1;
|
||||
n += x - (int) (Math.floor(bottom.x));
|
||||
t_next_x = (top.x - Math.floor(top.x)) * dt_dx;
|
||||
}
|
||||
/* If perpendicular to Y axis */
|
||||
if (dy == 0) {
|
||||
y_inc = 0;
|
||||
t_next_y = Double.MAX_VALUE;
|
||||
}
|
||||
/* If bottom is above top */
|
||||
else if (bottom.y > top.y) {
|
||||
y_inc = 1;
|
||||
n += (int) (Math.floor(bottom.y)) - y;
|
||||
t_next_y = (Math.floor(top.y) + 1 - top.y) * dt_dy;
|
||||
}
|
||||
/* If top is above bottom */
|
||||
else {
|
||||
y_inc = -1;
|
||||
n += y - (int) (Math.floor(bottom.y));
|
||||
t_next_y = (top.y - Math.floor(top.y)) * dt_dy;
|
||||
}
|
||||
/* If perpendicular to Z axis */
|
||||
if (dz == 0) {
|
||||
z_inc = 0;
|
||||
t_next_z = Double.MAX_VALUE;
|
||||
}
|
||||
/* If bottom right of top */
|
||||
else if (bottom.z > top.z) {
|
||||
z_inc = 1;
|
||||
n += (int) (Math.floor(bottom.z)) - z;
|
||||
t_next_z = (Math.floor(top.z) + 1 - top.z) * dt_dz;
|
||||
}
|
||||
/* If bottom left of top */
|
||||
else {
|
||||
z_inc = -1;
|
||||
n += z - (int) (Math.floor(bottom.z));
|
||||
t_next_z = (top.z - Math.floor(top.z)) * dt_dz;
|
||||
}
|
||||
/* Walk through scene */
|
||||
ps.laststep = BlockStep.Y_MINUS; /* Last step is down into map */
|
||||
mapiter.initialize(x, y, z);
|
||||
ps.skylightlevel = 15;
|
||||
ps.emittedlightlevel = 0;
|
||||
boolean nonairhit = false;
|
||||
for (; n > 0; --n) {
|
||||
ps.blocktypeid = mapiter.getBlockTypeID();
|
||||
if(nonairhit || (ps.blocktypeid != 0)) {
|
||||
ps.blockdata = mapiter.getBlockData();
|
||||
boolean done = true;
|
||||
for(int i = 0; i < shaderstate.length; i++) {
|
||||
if(!shaderdone[i])
|
||||
shaderdone[i] = shaderstate[i].processBlock(ps);
|
||||
done = done && shaderdone[i];
|
||||
}
|
||||
/* If all are done, we're out */
|
||||
if(done)
|
||||
return;
|
||||
nonairhit = true;
|
||||
}
|
||||
if(need_skylightlevel)
|
||||
ps.skylightlevel = mapiter.getBlockSkyLight();
|
||||
if(need_emittedlightlevel)
|
||||
ps.emittedlightlevel = mapiter.getBlockEmittedLight();
|
||||
/* If X step is next best */
|
||||
if((t_next_x <= t_next_y) && (t_next_x <= t_next_z)) {
|
||||
x += x_inc;
|
||||
t = t_next_x;
|
||||
t_next_x += dt_dx;
|
||||
if(x_inc > 0) {
|
||||
ps.laststep = BlockStep.X_PLUS;
|
||||
mapiter.incrementX();
|
||||
}
|
||||
else {
|
||||
ps.laststep = BlockStep.X_MINUS;
|
||||
mapiter.decrementX();
|
||||
}
|
||||
}
|
||||
/* If Y step is next best */
|
||||
else if((t_next_y <= t_next_x) && (t_next_y <= t_next_z)) {
|
||||
y += y_inc;
|
||||
t = t_next_y;
|
||||
t_next_y += dt_dy;
|
||||
if(y_inc > 0) {
|
||||
ps.laststep = BlockStep.Y_PLUS;
|
||||
mapiter.incrementY();
|
||||
if(mapiter.getY() > 127)
|
||||
return;
|
||||
}
|
||||
else {
|
||||
ps.laststep = BlockStep.Y_MINUS;
|
||||
mapiter.decrementY();
|
||||
if(mapiter.getY() < 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Else, Z step is next best */
|
||||
else {
|
||||
z += z_inc;
|
||||
t = t_next_z;
|
||||
t_next_z += dt_dz;
|
||||
if(z_inc > 0) {
|
||||
ps.laststep = BlockStep.Z_PLUS;
|
||||
mapiter.incrementZ();
|
||||
}
|
||||
else {
|
||||
ps.laststep = BlockStep.Z_MINUS;
|
||||
mapiter.decrementZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBiomeDataNeeded() {
|
||||
return need_biomedata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRawBiomeDataNeeded() {
|
||||
return need_rawbiomedata;
|
||||
}
|
||||
|
||||
public boolean isHightestBlockYDataNeeded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isBlockTypeDataNeeded() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public double getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addClientConfiguration(JSONObject mapObject) {
|
||||
s(mapObject, "perspective", name);
|
||||
s(mapObject, "azimuth", azimuth);
|
||||
s(mapObject, "inclination", inclination);
|
||||
s(mapObject, "scale", scale);
|
||||
s(mapObject, "worldtomap", world_to_map.toJSON());
|
||||
s(mapObject, "maptoworld", map_to_world.toJSON());
|
||||
}
|
||||
}
|
99
src/main/java/org/dynmap/hdmap/ShadowHDLighting.java
Normal file
99
src/main/java/org/dynmap/hdmap/ShadowHDLighting.java
Normal file
@ -0,0 +1,99 @@
|
||||
package org.dynmap.hdmap;
|
||||
|
||||
import static org.dynmap.JSONUtils.s;
|
||||
|
||||
import org.dynmap.Color;
|
||||
import org.dynmap.ConfigurationNode;
|
||||
import org.dynmap.Log;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class ShadowHDLighting extends DefaultHDLighting {
|
||||
|
||||
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 */
|
||||
|
||||
public ShadowHDLighting(ConfigurationNode configuration) {
|
||||
super(configuration);
|
||||
double shadowweight = configuration.getDouble("shadowstrength", 0.0);
|
||||
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;
|
||||
}
|
||||
}
|
||||
int v = configuration.getInteger("ambientlight", -1);
|
||||
if((v >= 0) && (v < 15)) {
|
||||
lightscale = new int[16];
|
||||
for(int i = 0; i < 16; i++) {
|
||||
if(i < (15-v))
|
||||
lightscale[i] = 0;
|
||||
else
|
||||
lightscale[i] = i - (15-v);
|
||||
}
|
||||
}
|
||||
night_and_day = configuration.getBoolean("night-and-day", false);
|
||||
if(night_and_day) {
|
||||
if(lightscale == null) {
|
||||
Log.severe("night-and-day in lighting '" + getName() + "' requires ambientlight<15");
|
||||
night_and_day = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply lighting to given pixel colors (1 outcolor if normal, 2 if night/day) */
|
||||
public void applyLighting(HDPerspectiveState ps, HDShaderState ss, Color incolor, Color[] outcolor) {
|
||||
int lightlevel = 15, lightlevel_day = 15;
|
||||
/* If processing for shadows, use sky light level as base lighting */
|
||||
if(shadowscale != null) {
|
||||
lightlevel = lightlevel_day = ps.getSkyLightLevel();
|
||||
}
|
||||
/* If ambient light, adjust base lighting for it */
|
||||
if(lightscale != null)
|
||||
lightlevel = lightscale[lightlevel];
|
||||
/* If we're below max, see if emitted light helps */
|
||||
if((lightlevel < 15) || (lightlevel_day < 15)) {
|
||||
int emitted = ps.getEmittedLightLevel();
|
||||
lightlevel = Math.max(emitted, lightlevel);
|
||||
lightlevel_day = Math.max(emitted, lightlevel_day);
|
||||
}
|
||||
/* Figure out our color, with lighting if needed */
|
||||
outcolor[0].setColor(incolor);
|
||||
if(lightlevel < 15) {
|
||||
shadowColor(outcolor[0], lightlevel);
|
||||
}
|
||||
if(outcolor.length > 1) {
|
||||
if(lightlevel_day == lightlevel) {
|
||||
outcolor[1].setColor(outcolor[0]);
|
||||
}
|
||||
else {
|
||||
outcolor[1].setColor(incolor);
|
||||
if(lightlevel_day < 15) {
|
||||
shadowColor(outcolor[1], lightlevel_day);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final void shadowColor(Color c, int lightlevel) {
|
||||
int scale = shadowscale[lightlevel];
|
||||
if(scale < 256)
|
||||
c.setRGBA((c.getRed() * scale) >> 8, (c.getGreen() * scale) >> 8,
|
||||
(c.getBlue() * scale) >> 8, c.getAlpha());
|
||||
}
|
||||
|
||||
/* Test if night/day is enabled for this renderer */
|
||||
public boolean isNightAndDayEnabled() { return night_and_day; }
|
||||
|
||||
/* Test if sky light level needed */
|
||||
public boolean isSkyLightLevelNeeded() { return (shadowscale != null); }
|
||||
|
||||
/* Test if emitted light level needed */
|
||||
public boolean isEmittedLightLevelNeeded() { return (shadowscale != null) || (lightscale != null); }
|
||||
|
||||
}
|
@ -16,6 +16,7 @@ import org.dynmap.Client;
|
||||
import org.dynmap.Color;
|
||||
import org.dynmap.ColorScheme;
|
||||
import org.dynmap.ConfigurationNode;
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.MapManager;
|
||||
import org.dynmap.TileHashManager;
|
||||
import org.dynmap.debug.Debug;
|
||||
@ -213,8 +214,7 @@ public class DefaultTileRenderer implements MapTileRenderer {
|
||||
}
|
||||
|
||||
/* Hand encoding and writing file off to MapManager */
|
||||
KzedZoomedMapTile zmtile = new KzedZoomedMapTile(tile.getDynmapWorld(),
|
||||
(KzedMap) tile.getMap(), tile);
|
||||
KzedZoomedMapTile zmtile = new KzedZoomedMapTile(tile.getDynmapWorld(), tile);
|
||||
File zoomFile = MapManager.mapman.getTileFile(zmtile);
|
||||
|
||||
doFileWrites(outputFile, tile, im, im_day, zmtile, zoomFile, zim, zim_day, !isempty);
|
||||
@ -587,7 +587,7 @@ public class DefaultTileRenderer implements MapTileRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildClientConfiguration(JSONObject worldObject) {
|
||||
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld world, KzedMap map) {
|
||||
ConfigurationNode c = configuration;
|
||||
JSONObject o = new JSONObject();
|
||||
s(o, "type", "KzedMapType");
|
||||
@ -599,6 +599,7 @@ public class DefaultTileRenderer implements MapTileRenderer {
|
||||
s(o, "nightandday", c.getBoolean("night-and-day", false));
|
||||
s(o, "backgroundday", c.getString("backgroundday"));
|
||||
s(o, "backgroundnight", c.getString("backgroundnight"));
|
||||
s(o, "bigmap", map.isBigWorldMap(world));
|
||||
a(worldObject, "maps", o);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import org.dynmap.Log;
|
||||
import org.dynmap.MapManager;
|
||||
import org.dynmap.MapTile;
|
||||
import org.dynmap.MapType;
|
||||
import org.dynmap.MapType.MapStep;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
import org.json.simple.JSONObject;
|
||||
import java.awt.image.DataBufferInt;
|
||||
@ -46,6 +47,7 @@ public class KzedMap extends MapType {
|
||||
public static final int anchorz = 0;
|
||||
|
||||
MapTileRenderer[] renderers;
|
||||
private boolean isbigmap;
|
||||
|
||||
/* BufferedImage with direct access to its ARGB-formatted data buffer */
|
||||
public static class KzedBufferedImage {
|
||||
@ -67,6 +69,7 @@ public class KzedMap extends MapType {
|
||||
this.renderers = new MapTileRenderer[renderers.size()];
|
||||
renderers.toArray(this.renderers);
|
||||
Log.verboseinfo("Loaded " + renderers.size() + " renderers for map '" + getClass().toString() + "'.");
|
||||
isbigmap = configuration.getBoolean("isbigmap", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -139,10 +142,6 @@ public class KzedMap extends MapType {
|
||||
}
|
||||
}
|
||||
|
||||
public void invalidateTile(MapTile tile) {
|
||||
onTileInvalidated.trigger(tile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if point x,z is inside rectangle with corner at r0x,r0z and with
|
||||
* size vectors s1x,s1z and s2x,s2z
|
||||
@ -335,8 +334,9 @@ public class KzedMap extends MapType {
|
||||
}
|
||||
return s;
|
||||
}
|
||||
/* Return negative to flag negative X walk */
|
||||
public int baseZoomFileStepSize() { return -zTileWidth; }
|
||||
public int baseZoomFileStepSize() { return zTileWidth; }
|
||||
|
||||
public MapStep zoomFileMapStep() { return MapStep.X_MINUS_Y_PLUS; }
|
||||
|
||||
private static final int[] stepseq = { 0, 2, 1, 3 };
|
||||
|
||||
@ -344,14 +344,20 @@ public class KzedMap extends MapType {
|
||||
/* How many bits of coordinate are shifted off to make big world directory name */
|
||||
public int getBigWorldShift() { return 12; }
|
||||
|
||||
/* Returns true if big world file structure is in effect for this map */
|
||||
@Override
|
||||
public boolean isBigWorldMap(DynmapWorld w) {
|
||||
return w.bigworld || isbigmap;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "KzedMap";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildClientConfiguration(JSONObject worldObject) {
|
||||
public void buildClientConfiguration(JSONObject worldObject, DynmapWorld world) {
|
||||
for(MapTileRenderer renderer : renderers) {
|
||||
renderer.buildClientConfiguration(worldObject);
|
||||
renderer.buildClientConfiguration(worldObject, world, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,14 @@
|
||||
package org.dynmap.kzedmap;
|
||||
|
||||
import org.dynmap.DynmapChunk;
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.MapManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import org.dynmap.MapTile;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
|
||||
public class KzedMapTile extends MapTile {
|
||||
public KzedMap map;
|
||||
@ -15,7 +21,7 @@ public class KzedMapTile extends MapTile {
|
||||
public File file = null;
|
||||
|
||||
public KzedMapTile(DynmapWorld world, KzedMap map, MapTileRenderer renderer, int px, int py) {
|
||||
super(world, map);
|
||||
super(world);
|
||||
this.map = map;
|
||||
this.renderer = renderer;
|
||||
this.px = px;
|
||||
@ -25,7 +31,7 @@ public class KzedMapTile extends MapTile {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
if(fname == null) {
|
||||
if(world.bigworld)
|
||||
if(map.isBigWorldMap(world))
|
||||
fname = renderer.getName() + "/" + (px >> 12) + '_' + (py >> 12) + '/' + px + "_" + py + ".png";
|
||||
else
|
||||
fname = renderer.getName() + "_" + px + "_" + py + ".png";
|
||||
@ -36,7 +42,7 @@ public class KzedMapTile extends MapTile {
|
||||
@Override
|
||||
public String getDayFilename() {
|
||||
if(fname_day == null) {
|
||||
if(world.bigworld)
|
||||
if(map.isBigWorldMap(world))
|
||||
fname_day = renderer.getName() + "_day/" + (px >> 12) + '_' + (py >> 12) + '/' + px + "_" + py + ".png";
|
||||
else
|
||||
fname_day = renderer.getName() + "_day_" + px + "_" + py + ".png";
|
||||
@ -68,4 +74,16 @@ public class KzedMapTile extends MapTile {
|
||||
public String toString() {
|
||||
return getWorld().getName() + ":" + getFilename();
|
||||
}
|
||||
|
||||
public boolean render(MapChunkCache cache) {
|
||||
return map.render(cache, this, MapManager.mapman.getTileFile(this));
|
||||
}
|
||||
|
||||
public List<DynmapChunk> getRequiredChunks() {
|
||||
return map.getRequiredChunks(this);
|
||||
}
|
||||
|
||||
public MapTile[] getAdjecentTiles() {
|
||||
return map.getAdjecentTiles(this);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
package org.dynmap.kzedmap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.dynmap.DynmapChunk;
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.MapTile;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
|
||||
public class KzedZoomedMapTile extends MapTile {
|
||||
private String fname;
|
||||
@ -33,8 +37,8 @@ public class KzedZoomedMapTile extends MapTile {
|
||||
|
||||
public KzedMapTile originalTile;
|
||||
|
||||
public KzedZoomedMapTile(DynmapWorld world, KzedMap map, KzedMapTile original) {
|
||||
super(world, map);
|
||||
public KzedZoomedMapTile(DynmapWorld world, KzedMapTile original) {
|
||||
super(world);
|
||||
this.originalTile = original;
|
||||
}
|
||||
|
||||
@ -79,4 +83,19 @@ public class KzedZoomedMapTile extends MapTile {
|
||||
return getWorld().getName() + ".z" + originalTile.renderer.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean render(MapChunkCache cache) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DynmapChunk> getRequiredChunks() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapTile[] getAdjecentTiles() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package org.dynmap.kzedmap;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.dynmap.DynmapWorld;
|
||||
import org.dynmap.utils.MapChunkCache;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
@ -11,7 +12,7 @@ public interface MapTileRenderer {
|
||||
|
||||
boolean render(MapChunkCache cache, KzedMapTile tile, File outputFile);
|
||||
|
||||
void buildClientConfiguration(JSONObject worldObject);
|
||||
void buildClientConfiguration(JSONObject worldObject, DynmapWorld w, KzedMap map);
|
||||
|
||||
boolean isBiomeDataNeeded();
|
||||
boolean isRawBiomeDataNeeded();
|
||||
|
@ -136,9 +136,15 @@ public class LegacyMapChunkCache implements MapChunkCache {
|
||||
public final void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
public final int getX() {
|
||||
return x;
|
||||
}
|
||||
public final int getY() {
|
||||
return y;
|
||||
}
|
||||
public final int getZ() {
|
||||
return z;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,8 +81,16 @@ public interface MapIterator {
|
||||
* @param y
|
||||
*/
|
||||
void setY(int y);
|
||||
/**
|
||||
* Get X coordinate
|
||||
*/
|
||||
int getX();
|
||||
/**
|
||||
* Get Y coordinate
|
||||
*/
|
||||
int getY();
|
||||
/**
|
||||
* Get Z coordinate
|
||||
*/
|
||||
int getZ();
|
||||
}
|
||||
|
139
src/main/java/org/dynmap/utils/Matrix3D.java
Normal file
139
src/main/java/org/dynmap/utils/Matrix3D.java
Normal file
@ -0,0 +1,139 @@
|
||||
package org.dynmap.utils;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
|
||||
/**
|
||||
* Basic 3D matrix math class - prevent dependency on Java 3D for this
|
||||
*/
|
||||
public class Matrix3D {
|
||||
private double m11, m12, m13, m21, m22, m23, m31, m32, m33;
|
||||
/**
|
||||
* Construct identity matrix
|
||||
*/
|
||||
public Matrix3D() {
|
||||
m11 = m22 = m33 = 1.0;
|
||||
m12 = m13 = m21 = m23 = m31 = m32 = 0.0;
|
||||
}
|
||||
/**
|
||||
* Construct matrix with given parms
|
||||
*
|
||||
* @param m11 - first cell of first row
|
||||
* @param m12 - second cell of first row
|
||||
* @param m13 - third cell of first row
|
||||
* @param m21 - first cell of second row
|
||||
* @param m22 - second cell of second row
|
||||
* @param m23 - third cell of second row
|
||||
* @param m31 - first cell of third row
|
||||
* @param m32 - second cell of third row
|
||||
* @param m33 - third cell of third row
|
||||
*/
|
||||
public Matrix3D(double m11, double m12, double m13, double m21, double m22, double m23, double m31, double m32, double m33) {
|
||||
this.m11 = m11; this.m12 = m12; this.m13 = m13;
|
||||
this.m21 = m21; this.m22 = m22; this.m23 = m23;
|
||||
this.m31 = m31; this.m32 = m32; this.m33 = m33;
|
||||
}
|
||||
/**
|
||||
* Multiply matrix by another matrix (this = mat * this), and store result in self
|
||||
* @param mat
|
||||
*/
|
||||
public void multiply(Matrix3D mat) {
|
||||
double new_m11 = mat.m11*m11 + mat.m12*m21 + mat.m13*m31;
|
||||
double new_m12 = mat.m11*m12 + mat.m12*m22 + mat.m13*m32;
|
||||
double new_m13 = mat.m11*m13 + mat.m12*m23 + mat.m13*m33;
|
||||
double new_m21 = mat.m21*m11 + mat.m22*m21 + mat.m23*m31;
|
||||
double new_m22 = mat.m21*m12 + mat.m22*m22 + mat.m23*m32;
|
||||
double new_m23 = mat.m21*m13 + mat.m22*m23 + mat.m23*m33;
|
||||
double new_m31 = mat.m31*m11 + mat.m32*m21 + mat.m33*m31;
|
||||
double new_m32 = mat.m31*m12 + mat.m32*m22 + mat.m33*m32;
|
||||
double new_m33 = mat.m31*m13 + mat.m32*m23 + mat.m33*m33;
|
||||
m11 = new_m11; m12 = new_m12; m13 = new_m13;
|
||||
m21 = new_m21; m22 = new_m22; m23 = new_m23;
|
||||
m31 = new_m31; m32 = new_m32; m33 = new_m33;
|
||||
}
|
||||
/**
|
||||
* Scale each coordinate by given values
|
||||
*
|
||||
* @param s1
|
||||
* @param s2
|
||||
* @param s3
|
||||
*/
|
||||
public void scale(double s1, double s2, double s3) {
|
||||
Matrix3D scalemat = new Matrix3D(s1, 0, 0, 0, s2, 0, 0, 0, s3);
|
||||
multiply(scalemat);
|
||||
}
|
||||
/**
|
||||
* Rotate XY clockwise around +Z axis
|
||||
* @param rot_deg - degrees of rotation
|
||||
*/
|
||||
public void rotateXY(double rot_deg) {
|
||||
double rot_rad = Math.toRadians(rot_deg);
|
||||
double sin_rot = Math.sin(rot_rad);
|
||||
double cos_rot = Math.cos(rot_rad);
|
||||
Matrix3D rotmat = new Matrix3D(cos_rot, sin_rot, 0, -sin_rot, cos_rot, 0, 0, 0, 1);
|
||||
multiply(rotmat);
|
||||
}
|
||||
/**
|
||||
* Rotate YZ clockwise around +X axis
|
||||
* @param rot_deg - degrees of rotation
|
||||
*/
|
||||
public void rotateYZ(double rot_deg) {
|
||||
double rot_rad = Math.toRadians(rot_deg);
|
||||
double sin_rot = Math.sin(rot_rad);
|
||||
double cos_rot = Math.cos(rot_rad);
|
||||
Matrix3D rotmat = new Matrix3D(1, 0, 0, 0, cos_rot, sin_rot, 0, -sin_rot, cos_rot);
|
||||
multiply(rotmat);
|
||||
}
|
||||
/**
|
||||
* Shear along Z axis by factor of X and Y
|
||||
*/
|
||||
public void shearZ(double x_fact, double y_fact) {
|
||||
Matrix3D shearmat = new Matrix3D(1, 0, 0, 0, 1, 0, x_fact, y_fact, 1);
|
||||
multiply(shearmat);
|
||||
}
|
||||
/**
|
||||
* Transform a given vector using the matrix
|
||||
*/
|
||||
public final void transform(double[] v) {
|
||||
double v1 = m11*v[0] + m12*v[1] + m13*v[2];
|
||||
double v2 = m21*v[0] + m22*v[1] + m23*v[2];
|
||||
double v3 = m31*v[0] + m32*v[1] + m33*v[2];
|
||||
v[0] = v1; v[1] = v2; v[2] = v3;
|
||||
}
|
||||
/**
|
||||
* Transform a given vector using the matrix
|
||||
*/
|
||||
public final void transform(Vector3D v) {
|
||||
double v1 = m11*v.x + m12*v.y + m13*v.z;
|
||||
double v2 = m21*v.x + m22*v.y + m23*v.z;
|
||||
double v3 = m31*v.x + m32*v.y + m33*v.z;
|
||||
v.x = v1; v.y = v2; v.z = v3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a given vector using the matrix - put result in provided output vector
|
||||
*/
|
||||
public final void transform(Vector3D v, Vector3D outv) {
|
||||
outv.x = m11*v.x + m12*v.y + m13*v.z;
|
||||
outv.y = m21*v.x + m22*v.y + m23*v.z;
|
||||
outv.z = m31*v.x + m32*v.y + m33*v.z;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "[ [" + m11 + " " + m12 + " " + m13 + "] [" + m21 + " " + m22 + " " + m23 + "] [" + m31 + " " + m32 + " " + m33 + "] ]";
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public JSONArray toJSON() {
|
||||
JSONArray array = new JSONArray();
|
||||
array.add(m11);
|
||||
array.add(m12);
|
||||
array.add(m13);
|
||||
array.add(m21);
|
||||
array.add(m22);
|
||||
array.add(m23);
|
||||
array.add(m31);
|
||||
array.add(m32);
|
||||
array.add(m33);
|
||||
return array;
|
||||
}
|
||||
}
|
@ -136,9 +136,15 @@ public class NewMapChunkCache implements MapChunkCache {
|
||||
public final void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
public final int getX() {
|
||||
return x;
|
||||
}
|
||||
public final int getY() {
|
||||
return y;
|
||||
}
|
||||
public final int getZ() {
|
||||
return z;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
16
src/main/java/org/dynmap/utils/Vector3D.java
Normal file
16
src/main/java/org/dynmap/utils/Vector3D.java
Normal file
@ -0,0 +1,16 @@
|
||||
package org.dynmap.utils;
|
||||
import org.bukkit.Location;
|
||||
/**
|
||||
* Simple vector class
|
||||
*/
|
||||
public class Vector3D {
|
||||
public double x, y, z;
|
||||
|
||||
public Vector3D() { x = y = z = 0.0; }
|
||||
|
||||
public void setFromLocation(Location l) { x = l.getX(); y = l.getY(); z = l.getZ(); }
|
||||
|
||||
public String toString() {
|
||||
return "{ " + x + ", " + y + ", " + z + " }";
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@
|
||||
<script type="text/javascript" src="js/custommarker.js"></script>
|
||||
<script type="text/javascript" src="js/minecraft.js"></script>
|
||||
<script type="text/javascript" src="js/map.js"></script>
|
||||
<script type="text/javascript" src="js/hdmap.js"></script>
|
||||
<script type="text/javascript" src="js/kzedmaps.js"></script>
|
||||
<script type="text/javascript" src="js/flatmap.js"></script>
|
||||
<script type="text/javascript" src="config.js"></script>
|
||||
|
@ -33,7 +33,7 @@ FlatMapType.prototype = $.extend(new DynMapType(), {
|
||||
if(zoom < extrazoom) {
|
||||
var scale = 1 << (extrazoom-zoom);
|
||||
var zprefix = "zzzzzzzzzzzz".substring(0, extrazoom-zoom);
|
||||
if(this.dynmap.world.bigworld)
|
||||
if(this.dynmap.map.mapTypes[this.dynmap.map.mapTypeId].bigmap)
|
||||
tileName = this.prefix + dnprefix + '_128/' + ((scale*coord.x) >> 5) + '_' + ((scale*coord.y) >> 5) +
|
||||
'/' + zprefix + "_" + (scale*coord.x) + '_' + (scale*coord.y) + '.png';
|
||||
else
|
||||
@ -41,7 +41,7 @@ FlatMapType.prototype = $.extend(new DynMapType(), {
|
||||
imgSize = 128;
|
||||
}
|
||||
else {
|
||||
if(this.dynmap.world.bigworld)
|
||||
if(this.dynmap.map.mapTypes[this.dynmap.map.mapTypeId].bigmap)
|
||||
tileName = this.prefix + dnprefix + '_128/' + (coord.x >> 5) + '_' + (coord.y >> 5) +
|
||||
'/' + coord.x + '_' + coord.y + '.png';
|
||||
else
|
||||
|
89
web/js/hdmap.js
Normal file
89
web/js/hdmap.js
Normal file
@ -0,0 +1,89 @@
|
||||
function HDProjection() {}
|
||||
HDProjection.prototype = {
|
||||
extrazoom: 0,
|
||||
worldtomap: null,
|
||||
fromLatLngToPoint: function(latLng) {
|
||||
return new google.maps.Point(latLng.lng()*config.tileWidth, latLng.lat()*config.tileHeight);
|
||||
},
|
||||
fromPointToLatLng: function(point) {
|
||||
return new google.maps.LatLng( point.y/config.tileHeight, point.x/config.tileWidth);
|
||||
},
|
||||
fromWorldToLatLng: function(x, y, z) {
|
||||
var wtp = this.worldtomap;
|
||||
var xx = x*wtp[0] + y*wtp[1] + z*wtp[2];
|
||||
var yy = x*wtp[3] + y*wtp[4] + z*wtp[5];
|
||||
|
||||
return new google.maps.LatLng(-yy / config.tileHeight / (1 << this.extrazoom), xx / config.tileWidth / (1 << this.extrazoom));
|
||||
}
|
||||
};
|
||||
|
||||
function HDMapType(configuration) {
|
||||
$.extend(this, configuration); }
|
||||
HDMapType.prototype = $.extend(new DynMapType(), {
|
||||
constructor: HDMapType,
|
||||
projection: new HDProjection(),
|
||||
tileSize: new google.maps.Size(128.0, 128.0),
|
||||
minZoom: 0,
|
||||
maxZoom: 2,
|
||||
prefix: null,
|
||||
getTile: function(coord, zoom, doc) {
|
||||
var tileSize = 128;
|
||||
var imgSize;
|
||||
var tileName;
|
||||
|
||||
var dnprefix = '';
|
||||
var map = this.dynmap.map.mapTypes[this.dynmap.map.mapTypeId];
|
||||
if(map.nightandday && this.dynmap.serverday)
|
||||
dnprefix = '_day';
|
||||
|
||||
var extrazoom = map.mapzoomout;
|
||||
if(zoom < extrazoom) {
|
||||
var scale = 1 << (extrazoom-zoom);
|
||||
var zprefix = "zzzzzzzzzzzzzzzzzzzzzz".substring(0, extrazoom-zoom);
|
||||
tileName = this.prefix + dnprefix + '/' + ((scale*coord.x) >> 5) + '_' + ((-scale*coord.y) >> 5) +
|
||||
'/' + zprefix + "_" + (scale*coord.x) + '_' + (-scale*coord.y) + '.png';
|
||||
imgSize = 128;
|
||||
}
|
||||
else {
|
||||
tileName = this.prefix + dnprefix + '/' + (coord.x >> 5) + '_' + ((-coord.y) >> 5) +
|
||||
'/' + coord.x + '_' + (-coord.y) + '.png';
|
||||
imgSize = Math.pow(2, 7+zoom-extrazoom);
|
||||
}
|
||||
var tile = $('<div/>')
|
||||
.addClass('tile')
|
||||
.css({
|
||||
width: tileSize + 'px',
|
||||
height: tileSize + 'px'
|
||||
});
|
||||
var img = $('<img/>')
|
||||
.attr('src', this.dynmap.getTileUrl(tileName))
|
||||
.error(function() { img.hide(); })
|
||||
.bind('load', function() { img.show(); })
|
||||
.css({
|
||||
width: imgSize +'px',
|
||||
height: imgSize + 'px',
|
||||
borderStyle: 'none'
|
||||
})
|
||||
.hide()
|
||||
.appendTo(tile);
|
||||
this.dynmap.registerTile(this, tileName, img);
|
||||
//this.dynmap.unregisterTile(this, tileName);
|
||||
return tile.get(0);
|
||||
},
|
||||
updateTileSize: function(zoom) {
|
||||
var size;
|
||||
var extrazoom = this.mapzoomout;
|
||||
this.projection.extrazoom = extrazoom;
|
||||
this.projection.worldtomap = this.worldtomap;
|
||||
this.maxZoom = 2 + extrazoom;
|
||||
if (zoom <= extrazoom) {
|
||||
size = 128;
|
||||
}
|
||||
else {
|
||||
size = Math.pow(2, 7+zoom-extrazoom);
|
||||
}
|
||||
this.tileSize = new google.maps.Size(size, size);
|
||||
}
|
||||
});
|
||||
|
||||
maptypes.HDMapType = function(configuration) { return new HDMapType(configuration); };
|
@ -55,7 +55,7 @@ KzedMapType.prototype = $.extend(new DynMapType(), {
|
||||
tileSize = 128;
|
||||
imgSize = tileSize;
|
||||
var tilescale = 2 << (extrazoom-zoom);
|
||||
if (this.dynmap.world.bigworld) {
|
||||
if (this.dynmap.map.mapTypes[this.dynmap.map.mapTypeId].bigmap) {
|
||||
if(zoom < extrazoom) zpre = zpre + '_';
|
||||
tileName = 'z' + this.prefix + dnprefix + '/' + ((-coord.x * tileSize*tilescale)>>12) +
|
||||
'_' + ((coord.y * tileSize*tilescale) >> 12) + '/' + zpre +
|
||||
@ -69,7 +69,7 @@ KzedMapType.prototype = $.extend(new DynMapType(), {
|
||||
tileSize = 128;
|
||||
|
||||
imgSize = Math.pow(2, 6+zoom-extrazoom);
|
||||
if(this.dynmap.world.bigworld) {
|
||||
if(this.dynmap.map.mapTypes[this.dynmap.map.mapTypeId].bigmap) {
|
||||
tileName = this.prefix + dnprefix + '/' + ((-coord.x*tileSize) >> 12) + '_' +
|
||||
((coord.y*tileSize)>>12) + '/' +
|
||||
(-coord.x*tileSize) + '_' + (coord.y*tileSize) + '.png';
|
||||
|
Loading…
Reference in New Issue
Block a user