Tinker with performance on some base data classes
This commit is contained in:
parent
5a30ab0d3f
commit
c6fb0be7e7
8 changed files with 172 additions and 119 deletions
|
|
@ -38,12 +38,13 @@ public class Color {
|
||||||
val = TRANSPARENT;
|
val = TRANSPARENT;
|
||||||
}
|
}
|
||||||
public final void setGrayscale() {
|
public final void setGrayscale() {
|
||||||
int alpha = (val >> 24) & 0xFF;
|
int alpha = val & 0xFF000000;
|
||||||
int red = (val >> 16) & 0xFF;
|
int num = (((val >> 16) & 0xFF) * 76)
|
||||||
int green = (val >> 8) & 0xFF;
|
+ (((val >> 8) & 0xFF) * 151)
|
||||||
int blue = val & 0xFF;
|
+ (( val & 0xFF) * 28);
|
||||||
int gray = ((red * 76) + (green * 151) + (blue * 28)) / 255;
|
// weights sum to 255, so num ∈ [0, 65025]; fast /255 via shift
|
||||||
setRGBA(gray, gray, gray, alpha);
|
int gray = (num + (num >> 8) + 1) >> 8;
|
||||||
|
val = alpha | (gray << 16) | (gray << 8) | gray;
|
||||||
}
|
}
|
||||||
public final void setColor(Color c) {
|
public final void setColor(Color c) {
|
||||||
val = c.val;
|
val = c.val;
|
||||||
|
|
@ -85,11 +86,10 @@ public class Color {
|
||||||
* @param argb - ARGB to blend
|
* @param argb - ARGB to blend
|
||||||
*/
|
*/
|
||||||
public final void blendColor(int argb) {
|
public final void blendColor(int argb) {
|
||||||
int nval = (((((val >> 24) & 0xFF) * ((argb >> 24) & 0xFF)) / 255) << 24);
|
val = (mulDiv255(val >>> 24, argb >>> 24 ) << 24)
|
||||||
nval = nval | (((((val >> 16) & 0xFF) * ((argb >> 16) & 0xFF)) / 255) << 16);
|
| (mulDiv255((val >> 16) & 0xFF, (argb >> 16) & 0xFF) << 16)
|
||||||
nval = nval | (((((val >> 8) & 0xFF) * ((argb >> 8) & 0xFF)) / 255) << 8);
|
| (mulDiv255((val >> 8) & 0xFF, (argb >> 8) & 0xFF) << 8)
|
||||||
nval = nval | (((val & 0xFF) * (argb & 0xFF)) / 255);
|
| mulDiv255( val & 0xFF, argb & 0xFF);
|
||||||
val = nval;
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Scale each color component, based on the corresponding component
|
* Scale each color component, based on the corresponding component
|
||||||
|
|
@ -98,10 +98,30 @@ public class Color {
|
||||||
* @return blended color
|
* @return blended color
|
||||||
*/
|
*/
|
||||||
public static final int blendColor(int argb0, int argb1) {
|
public static final int blendColor(int argb0, int argb1) {
|
||||||
int nval = (((((argb0 >> 24) & 0xFF) * ((argb1 >> 24) & 0xFF)) / 255) << 24);
|
return (mulDiv255(argb0 >>> 24, argb1 >>> 24 ) << 24)
|
||||||
nval = nval | (((((argb0 >> 16) & 0xFF) * ((argb1 >> 16) & 0xFF)) / 255) << 16);
|
| (mulDiv255((argb0 >> 16) & 0xFF, (argb1 >> 16) & 0xFF) << 16)
|
||||||
nval = nval | (((((argb0 >> 8) & 0xFF) * ((argb1 >> 8) & 0xFF)) / 255) << 8);
|
| (mulDiv255((argb0 >> 8) & 0xFF, (argb1 >> 8) & 0xFF) << 8)
|
||||||
nval = nval | (((argb0 & 0xFF) * (argb1 & 0xFF)) / 255);
|
| mulDiv255( argb0 & 0xFF, argb1 & 0xFF);
|
||||||
return nval;
|
}
|
||||||
|
/**
|
||||||
|
* Scale the RGB channels by scale/256, leaving alpha unchanged.
|
||||||
|
* Equivalent to setRGBA(getRed()*scale>>8, getGreen()*scale>>8, getBlue()*scale>>8, getAlpha())
|
||||||
|
* but avoids redundant unpack/repack of the alpha channel.
|
||||||
|
* @param scale - scale factor 0..256 (256 = full brightness)
|
||||||
|
*/
|
||||||
|
public final void scaleRGB(int scale) {
|
||||||
|
val = (val & 0xFF000000)
|
||||||
|
| ((((val >> 16) & 0xFF) * scale >> 8) << 16)
|
||||||
|
| ((((val >> 8) & 0xFF) * scale >> 8) << 8)
|
||||||
|
| ((val & 0xFF) * scale >> 8);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Fast multiply-then-divide-by-255 for two values a, b each in [0, 255].
|
||||||
|
* Returns floor(a*b/255), equivalent to the standard integer division but
|
||||||
|
* computed with shifts only: (x + (x >> 8) + 1) >> 8 where x = a * b.
|
||||||
|
*/
|
||||||
|
private static int mulDiv255(int a, int b) {
|
||||||
|
int x = a * b;
|
||||||
|
return (x + (x >> 8) + 1) >> 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package org.dynmap.common;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
@ -11,7 +12,9 @@ import org.dynmap.hdmap.HDBlockModels;
|
||||||
public class BiomeMap {
|
public class BiomeMap {
|
||||||
public static final int NO_INDEX = -2;
|
public static final int NO_INDEX = -2;
|
||||||
private static BiomeMap[] biome_by_index = new BiomeMap[256];
|
private static BiomeMap[] biome_by_index = new BiomeMap[256];
|
||||||
private static Map<String, BiomeMap> biome_by_rl = new HashMap<String, BiomeMap>();
|
private static Map<String, BiomeMap> biome_by_rl = new HashMap<String, BiomeMap>(256);
|
||||||
|
// Tracks registered IDs for O(1) uniqueness checks during initialization
|
||||||
|
private static final HashSet<String> biome_ids = new HashSet<String>(256);
|
||||||
public static final BiomeMap NULL = new BiomeMap(-1, "NULL", 0.5, 0.5, 0xFFFFFF, 0, 0, null);
|
public static final BiomeMap NULL = new BiomeMap(-1, "NULL", 0.5, 0.5, 0xFFFFFF, 0, 0, null);
|
||||||
|
|
||||||
public static final BiomeMap OCEAN = new BiomeMap(0, "OCEAN", "minecraft:ocean");
|
public static final BiomeMap OCEAN = new BiomeMap(0, "OCEAN", "minecraft:ocean");
|
||||||
|
|
@ -145,12 +148,17 @@ public class BiomeMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isUniqueID(String id) {
|
private static boolean isUniqueID(String id) {
|
||||||
for(int i = 0; i < biome_by_index.length; i++) {
|
return !biome_ids.contains(id);
|
||||||
if(biome_by_index[i] == null) continue;
|
}
|
||||||
if(biome_by_index[i].id.equals(id))
|
|
||||||
return false;
|
/**
|
||||||
}
|
* Encodes a grass/foliage color multiplier for efficient hot-path dispatch:
|
||||||
return true;
|
* == 0 → 0 (passthrough: return raw value unchanged)
|
||||||
|
* 0 < val ≤ 0xFFFFFF → positive (blend: average with raw)
|
||||||
|
* val > 0xFFFFFF → -(val & 0xFFFFFF) (negative sentinel: fixed override color)
|
||||||
|
*/
|
||||||
|
private static int encodeColorMult(int val) {
|
||||||
|
return (val > 0xFFFFFF) ? -(val & 0xFFFFFF) : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void resizeIfNeeded(int idx) {
|
private static void resizeIfNeeded(int idx) {
|
||||||
|
|
@ -171,8 +179,8 @@ public class BiomeMap {
|
||||||
setTemperature(tmp);
|
setTemperature(tmp);
|
||||||
setRainfall(rain);
|
setRainfall(rain);
|
||||||
this.watercolormult = waterColorMultiplier;
|
this.watercolormult = waterColorMultiplier;
|
||||||
this.grassmult = grassmult;
|
this.grassmult = encodeColorMult(grassmult);
|
||||||
this.foliagemult = foliagemult;
|
this.foliagemult = encodeColorMult(foliagemult);
|
||||||
// Handle null biome
|
// Handle null biome
|
||||||
if (id == null) { id = "biome_" + idx; }
|
if (id == null) { id = "biome_" + idx; }
|
||||||
id = id.toUpperCase().replace(' ', '_');
|
id = id.toUpperCase().replace(' ', '_');
|
||||||
|
|
@ -180,6 +188,7 @@ public class BiomeMap {
|
||||||
id = id + "_" + idx;
|
id = id + "_" + idx;
|
||||||
}
|
}
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
biome_ids.add(this.id);
|
||||||
// If index is NO_INDEX, find one after the well known ones
|
// If index is NO_INDEX, find one after the well known ones
|
||||||
if (idx == NO_INDEX) {
|
if (idx == NO_INDEX) {
|
||||||
idx = LAST_WELL_KNOWN;
|
idx = LAST_WELL_KNOWN;
|
||||||
|
|
@ -235,21 +244,15 @@ public class BiomeMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final int getModifiedGrassMultiplier(int rawgrassmult) {
|
public final int getModifiedGrassMultiplier(int rawgrassmult) {
|
||||||
if(grassmult == 0)
|
if (grassmult == 0) return rawgrassmult; // common case: no override
|
||||||
return rawgrassmult;
|
if (grassmult < 0) return -grassmult; // fixed color (pre-masked at set-time)
|
||||||
else if(grassmult > 0xFFFFFF)
|
return ((rawgrassmult & 0xfefefe) + grassmult) >> 1; // blend
|
||||||
return grassmult & 0xFFFFFF;
|
|
||||||
else
|
|
||||||
return ((rawgrassmult & 0xfefefe) + grassmult) / 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final int getModifiedFoliageMultiplier(int rawfoliagemult) {
|
public final int getModifiedFoliageMultiplier(int rawfoliagemult) {
|
||||||
if(foliagemult == 0)
|
if (foliagemult == 0) return rawfoliagemult; // common case: no override
|
||||||
return rawfoliagemult;
|
if (foliagemult < 0) return -foliagemult; // fixed color (pre-masked at set-time)
|
||||||
else if(foliagemult > 0xFFFFFF)
|
return ((rawfoliagemult & 0xfefefe) + foliagemult) >> 1; // blend
|
||||||
return foliagemult & 0xFFFFFF;
|
|
||||||
else
|
|
||||||
return ((rawfoliagemult & 0xfefefe) + foliagemult) / 2;
|
|
||||||
}
|
}
|
||||||
public final int getWaterColorMult() {
|
public final int getWaterColorMult() {
|
||||||
return watercolormult;
|
return watercolormult;
|
||||||
|
|
@ -278,10 +281,10 @@ public class BiomeMap {
|
||||||
this.watercolormult = watercolormult;
|
this.watercolormult = watercolormult;
|
||||||
}
|
}
|
||||||
public void setGrassColorMultiplier(int grassmult) {
|
public void setGrassColorMultiplier(int grassmult) {
|
||||||
this.grassmult = grassmult;
|
this.grassmult = encodeColorMult(grassmult);
|
||||||
}
|
}
|
||||||
public void setFoliageColorMultiplier(int foliagemult) {
|
public void setFoliageColorMultiplier(int foliagemult) {
|
||||||
this.foliagemult = foliagemult;
|
this.foliagemult = encodeColorMult(foliagemult);
|
||||||
}
|
}
|
||||||
public void setTemperature(double tmp) {
|
public void setTemperature(double tmp) {
|
||||||
if(tmp < 0.0) tmp = 0.0;
|
if(tmp < 0.0) tmp = 0.0;
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ public class GenericChunk {
|
||||||
// Get section for given block Y coord
|
// Get section for given block Y coord
|
||||||
public final GenericChunkSection getSection(int y) {
|
public final GenericChunkSection getSection(int y) {
|
||||||
int idx = (y >> 4) - this.cy_min;
|
int idx = (y >> 4) - this.cy_min;
|
||||||
if ((idx < 0) || (idx >= sectionCnt)) {
|
if ((idx < 0) || (idx >= sections.length)) {
|
||||||
return GenericChunkSection.EMPTY;
|
return GenericChunkSection.EMPTY;
|
||||||
}
|
}
|
||||||
return this.sections[idx];
|
return this.sections[idx];
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import java.lang.ref.Reference;
|
||||||
import java.lang.ref.ReferenceQueue;
|
import java.lang.ref.ReferenceQueue;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.lang.ref.SoftReference;
|
import java.lang.ref.SoftReference;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -23,22 +24,26 @@ public class GenericChunkCache {
|
||||||
private long cache_attempts;
|
private long cache_attempts;
|
||||||
private long cache_success;
|
private long cache_success;
|
||||||
private boolean softref;
|
private boolean softref;
|
||||||
|
// World name -> small integer ID, used to build long cache keys without String concatenation.
|
||||||
|
// Accessed only while holding snapcachelock.
|
||||||
|
private final HashMap<String, Integer> worldIds = new HashMap<String, Integer>();
|
||||||
|
private int nextWorldId = 0;
|
||||||
|
|
||||||
private static class CacheRec {
|
private static class CacheRec {
|
||||||
Reference<ChunkCacheRec> ref;
|
Reference<ChunkCacheRec> ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class CacheHashMap extends LinkedHashMap<String, CacheRec> {
|
public class CacheHashMap extends LinkedHashMap<Long, CacheRec> {
|
||||||
private int limit;
|
private int limit;
|
||||||
private IdentityHashMap<Reference<ChunkCacheRec>, String> reverselookup;
|
private IdentityHashMap<Reference<ChunkCacheRec>, Long> reverselookup;
|
||||||
|
|
||||||
public CacheHashMap(int lim) {
|
public CacheHashMap(int lim) {
|
||||||
super(16, (float)0.75, true);
|
super(16, (float)0.75, true);
|
||||||
limit = lim;
|
limit = lim;
|
||||||
reverselookup = new IdentityHashMap<Reference<ChunkCacheRec>, String>();
|
reverselookup = new IdentityHashMap<Reference<ChunkCacheRec>, Long>();
|
||||||
}
|
}
|
||||||
protected boolean removeEldestEntry(Map.Entry<String, CacheRec> last) {
|
protected boolean removeEldestEntry(Map.Entry<Long, CacheRec> last) {
|
||||||
boolean remove = (size() >= limit);
|
boolean remove = (size() >= limit);
|
||||||
if(remove && (last != null) && (last.getValue() != null)) {
|
if(remove && (last != null) && (last.getValue() != null)) {
|
||||||
reverselookup.remove(last.getValue().ref);
|
reverselookup.remove(last.getValue().ref);
|
||||||
|
|
@ -56,15 +61,26 @@ public class GenericChunkCache {
|
||||||
refqueue = new ReferenceQueue<ChunkCacheRec>();
|
refqueue = new ReferenceQueue<ChunkCacheRec>();
|
||||||
this.softref = softref;
|
this.softref = softref;
|
||||||
}
|
}
|
||||||
private String getKey(String w, int cx, int cz) {
|
/**
|
||||||
return w + ":" + cx + ":" + cz;
|
* Encode world name + chunk coords as a single long key.
|
||||||
|
* Worlds are assigned small integer IDs (10 bits) on first use.
|
||||||
|
* cx and cz are each encoded in 27 bits (signed, supports ±8M chunks / ±128M blocks).
|
||||||
|
* Must be called while holding snapcachelock.
|
||||||
|
*/
|
||||||
|
private long getKey(String w, int cx, int cz) {
|
||||||
|
Integer wid = worldIds.get(w);
|
||||||
|
if (wid == null) {
|
||||||
|
wid = nextWorldId++;
|
||||||
|
worldIds.put(w, wid);
|
||||||
|
}
|
||||||
|
return ((long)(wid & 0x3FF) << 54) | ((long)(cx & 0x7FFFFFF) << 27) | (long)(cz & 0x7FFFFFF);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Invalidate cached snapshot, if in cache
|
* Invalidate cached snapshot, if in cache
|
||||||
*/
|
*/
|
||||||
public void invalidateSnapshot(String w, int x, int y, int z) {
|
public void invalidateSnapshot(String w, int x, int y, int z) {
|
||||||
String key = getKey(w, x>>4, z>>4);
|
|
||||||
synchronized(snapcachelock) {
|
synchronized(snapcachelock) {
|
||||||
|
long key = getKey(w, x>>4, z>>4);
|
||||||
CacheRec rec = (snapcache != null) ? snapcache.remove(key) : null;
|
CacheRec rec = (snapcache != null) ? snapcache.remove(key) : null;
|
||||||
if(rec != null) {
|
if(rec != null) {
|
||||||
snapcache.reverselookup.remove(rec.ref);
|
snapcache.reverselookup.remove(rec.ref);
|
||||||
|
|
@ -77,10 +93,10 @@ public class GenericChunkCache {
|
||||||
* Invalidate cached snapshot, if in cache
|
* Invalidate cached snapshot, if in cache
|
||||||
*/
|
*/
|
||||||
public void invalidateSnapshot(String w, int x0, int y0, int z0, int x1, int y1, int z1) {
|
public void invalidateSnapshot(String w, int x0, int y0, int z0, int x1, int y1, int z1) {
|
||||||
for(int xx = (x0>>4); xx <= (x1>>4); xx++) {
|
synchronized(snapcachelock) {
|
||||||
for(int zz = (z0>>4); zz <= (z1>>4); zz++) {
|
for(int xx = (x0>>4); xx <= (x1>>4); xx++) {
|
||||||
String key = getKey(w, xx, zz);
|
for(int zz = (z0>>4); zz <= (z1>>4); zz++) {
|
||||||
synchronized(snapcachelock) {
|
long key = getKey(w, xx, zz);
|
||||||
CacheRec rec = (snapcache != null) ? snapcache.remove(key) : null;
|
CacheRec rec = (snapcache != null) ? snapcache.remove(key) : null;
|
||||||
if(rec != null) {
|
if(rec != null) {
|
||||||
snapcache.reverselookup.remove(rec.ref);
|
snapcache.reverselookup.remove(rec.ref);
|
||||||
|
|
@ -95,11 +111,11 @@ public class GenericChunkCache {
|
||||||
* Look for chunk snapshot in cache
|
* Look for chunk snapshot in cache
|
||||||
*/
|
*/
|
||||||
public ChunkCacheRec getSnapshot(String w, int chunkx, int chunkz) {
|
public ChunkCacheRec getSnapshot(String w, int chunkx, int chunkz) {
|
||||||
String key = getKey(w, chunkx, chunkz);
|
|
||||||
processRefQueue();
|
processRefQueue();
|
||||||
ChunkCacheRec ss = null;
|
ChunkCacheRec ss = null;
|
||||||
CacheRec rec;
|
CacheRec rec;
|
||||||
synchronized(snapcachelock) {
|
synchronized(snapcachelock) {
|
||||||
|
long key = getKey(w, chunkx, chunkz);
|
||||||
rec = (snapcache != null) ? snapcache.get(key) : null;
|
rec = (snapcache != null) ? snapcache.get(key) : null;
|
||||||
if(rec != null) {
|
if(rec != null) {
|
||||||
ss = rec.ref.get();
|
ss = rec.ref.get();
|
||||||
|
|
@ -118,7 +134,6 @@ public class GenericChunkCache {
|
||||||
* Add chunk snapshot to cache
|
* Add chunk snapshot to cache
|
||||||
*/
|
*/
|
||||||
public void putSnapshot(String w, int chunkx, int chunkz, ChunkCacheRec ss) {
|
public void putSnapshot(String w, int chunkx, int chunkz, ChunkCacheRec ss) {
|
||||||
String key = getKey(w, chunkx, chunkz);
|
|
||||||
processRefQueue();
|
processRefQueue();
|
||||||
CacheRec rec = new CacheRec();
|
CacheRec rec = new CacheRec();
|
||||||
if (softref)
|
if (softref)
|
||||||
|
|
@ -126,6 +141,7 @@ public class GenericChunkCache {
|
||||||
else
|
else
|
||||||
rec.ref = new WeakReference<ChunkCacheRec>(ss, refqueue);
|
rec.ref = new WeakReference<ChunkCacheRec>(ss, refqueue);
|
||||||
synchronized(snapcachelock) {
|
synchronized(snapcachelock) {
|
||||||
|
long key = getKey(w, chunkx, chunkz);
|
||||||
CacheRec prevrec = (snapcache != null) ? snapcache.put(key, rec) : null;
|
CacheRec prevrec = (snapcache != null) ? snapcache.put(key, rec) : null;
|
||||||
if(prevrec != null) {
|
if(prevrec != null) {
|
||||||
snapcache.reverselookup.remove(prevrec.ref);
|
snapcache.reverselookup.remove(prevrec.ref);
|
||||||
|
|
@ -140,7 +156,7 @@ public class GenericChunkCache {
|
||||||
Reference<? extends ChunkCacheRec> ref;
|
Reference<? extends ChunkCacheRec> ref;
|
||||||
while((ref = refqueue.poll()) != null) {
|
while((ref = refqueue.poll()) != null) {
|
||||||
synchronized(snapcachelock) {
|
synchronized(snapcachelock) {
|
||||||
String k = (snapcache != null) ? snapcache.reverselookup.remove(ref) : null;
|
Long k = (snapcache != null) ? snapcache.reverselookup.remove(ref) : null;
|
||||||
if(k != null) {
|
if(k != null) {
|
||||||
snapcache.remove(k);
|
snapcache.remove(k);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ public class GenericChunkSection {
|
||||||
blocks = bs;
|
blocks = bs;
|
||||||
}
|
}
|
||||||
public final DynmapBlockState getBlock(int x, int y, int z) {
|
public final DynmapBlockState getBlock(int x, int y, int z) {
|
||||||
return blocks[(256 * (y & 0xF)) + (16 * (z & 0xF)) + (x & 0xF)];
|
return blocks[((y & 0xF) << 8) | ((z & 0xF) << 4) | (x & 0xF)];
|
||||||
}
|
}
|
||||||
public final DynmapBlockState getBlock(GenericChunkPos pos) {
|
public final DynmapBlockState getBlock(GenericChunkPos pos) {
|
||||||
return blocks[pos.soffset];
|
return blocks[pos.soffset];
|
||||||
|
|
@ -40,7 +40,7 @@ public class GenericChunkSection {
|
||||||
palette = pal;
|
palette = pal;
|
||||||
}
|
}
|
||||||
public final DynmapBlockState getBlock(int x, int y, int z) {
|
public final DynmapBlockState getBlock(int x, int y, int z) {
|
||||||
return palette[blocks[(256 * (y & 0xF)) + (16 * (z & 0xF)) + (x & 0xF)]];
|
return palette[blocks[((y & 0xF) << 8) | ((z & 0xF) << 4) | (x & 0xF)]];
|
||||||
}
|
}
|
||||||
public final DynmapBlockState getBlock(GenericChunkPos pos) {
|
public final DynmapBlockState getBlock(GenericChunkPos pos) {
|
||||||
return palette[blocks[pos.soffset]];
|
return palette[blocks[pos.soffset]];
|
||||||
|
|
@ -126,12 +126,12 @@ public class GenericChunkSection {
|
||||||
light = new long[256];
|
light = new long[256];
|
||||||
if (lig != null) {
|
if (lig != null) {
|
||||||
for (int off = 0; (off < lig.length) && (off < 2048); off++) {
|
for (int off = 0; (off < lig.length) && (off < 2048); off++) {
|
||||||
light[off >> 3] |= (0xFFL & (long)lig[off]) << (8 * (off & 0x7));
|
light[off >> 3] |= (0xFFL & (long)lig[off]) << ((off & 0x7) << 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public final int getLight(int x, int y, int z) {
|
public final int getLight(int x, int y, int z) {
|
||||||
return 0xF & (int)(light[(16 * (y & 0xF)) + (z & 0xF)] >> (4 * (x & 0xF)));
|
return 0xF & (int)(light[((y & 0xF) << 4) | (z & 0xF)] >> ((x & 0xF) << 2));
|
||||||
}
|
}
|
||||||
public final int getLight(GenericChunkPos pos) {
|
public final int getLight(GenericChunkPos pos) {
|
||||||
return 0xF & (int)(light[pos.soffset >> 4] >> (4 * pos.sx));
|
return 0xF & (int)(light[pos.soffset >> 4] >> (4 * pos.sx));
|
||||||
|
|
|
||||||
|
|
@ -154,9 +154,7 @@ public class ShadowHDLighting extends DefaultHDLighting {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(cscale < 256) {
|
if(cscale < 256) {
|
||||||
Color c = outcolor[0];
|
outcolor[0].scaleRGB(cscale);
|
||||||
c.setRGBA((c.getRed() * cscale) >> 8, (c.getGreen() * cscale) >> 8,
|
|
||||||
(c.getBlue() * cscale) >> 8, c.getAlpha());
|
|
||||||
}
|
}
|
||||||
if(outcolor.length > 1) {
|
if(outcolor.length > 1) {
|
||||||
ll0 = getLightLevel(skyemit0, false);
|
ll0 = getLightLevel(skyemit0, false);
|
||||||
|
|
@ -194,9 +192,7 @@ public class ShadowHDLighting extends DefaultHDLighting {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(cscale < 256) {
|
if(cscale < 256) {
|
||||||
Color c = outcolor[1];
|
outcolor[1].scaleRGB(cscale);
|
||||||
c.setRGBA((c.getRed() * cscale) >> 8, (c.getGreen() * cscale) >> 8,
|
|
||||||
(c.getBlue() * cscale) >> 8, c.getAlpha());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -269,8 +265,7 @@ public class ShadowHDLighting extends DefaultHDLighting {
|
||||||
private final void shadowColor(Color c, int lightlevel, int[] shadowscale) {
|
private final void shadowColor(Color c, int lightlevel, int[] shadowscale) {
|
||||||
int scale = shadowscale[lightlevel];
|
int scale = shadowscale[lightlevel];
|
||||||
if(scale < 256)
|
if(scale < 256)
|
||||||
c.setRGBA((c.getRed() * scale) >> 8, (c.getGreen() * scale) >> 8,
|
c.scaleRGB(scale);
|
||||||
(c.getBlue() * scale) >> 8, c.getAlpha());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,16 +97,21 @@ public class PatchDefinition implements RenderPatch {
|
||||||
*/
|
*/
|
||||||
PatchDefinition(PatchDefinition orig, double rotatex, double rotatey, double rotatez, Vector3D rotorigin, int textureindex) {
|
PatchDefinition(PatchDefinition orig, double rotatex, double rotatey, double rotatez, Vector3D rotorigin, int textureindex) {
|
||||||
if (rotorigin == null) rotorigin = offsetCenter;
|
if (rotorigin == null) rotorigin = offsetCenter;
|
||||||
|
/* Precompute trig once - reused for all three vector rotations */
|
||||||
|
double sinX = 0, cosX = 1, sinY = 0, cosY = 1, sinZ = 0, cosZ = 1;
|
||||||
|
if (rotatex != 0) { double r = Math.toRadians(rotatex); sinX = Math.sin(r); cosX = Math.cos(r); }
|
||||||
|
if (rotatey != 0) { double r = Math.toRadians(rotatey); sinY = Math.sin(r); cosY = Math.cos(r); }
|
||||||
|
if (rotatez != 0) { double r = Math.toRadians(rotatez); sinZ = Math.sin(r); cosZ = Math.cos(r); }
|
||||||
Vector3D vec = new Vector3D(orig.x0, orig.y0, orig.z0);
|
Vector3D vec = new Vector3D(orig.x0, orig.y0, orig.z0);
|
||||||
rotate(vec, rotatex, rotatey, rotatez, rotorigin); /* Rotate origin */
|
rotatePrecomputed(vec, sinX, cosX, sinY, cosY, sinZ, cosZ, rotorigin); /* Rotate origin */
|
||||||
x0 = vec.x; y0 = vec.y; z0 = vec.z;
|
x0 = vec.x; y0 = vec.y; z0 = vec.z;
|
||||||
/* Rotate U */
|
/* Rotate U */
|
||||||
vec.x = orig.xu; vec.y = orig.yu; vec.z = orig.zu;
|
vec.x = orig.xu; vec.y = orig.yu; vec.z = orig.zu;
|
||||||
rotate(vec, rotatex, rotatey, rotatez, rotorigin); /* Rotate origin */
|
rotatePrecomputed(vec, sinX, cosX, sinY, cosY, sinZ, cosZ, rotorigin);
|
||||||
xu = vec.x; yu = vec.y; zu = vec.z;
|
xu = vec.x; yu = vec.y; zu = vec.z;
|
||||||
/* Rotate V */
|
/* Rotate V */
|
||||||
vec.x = orig.xv; vec.y = orig.yv; vec.z = orig.zv;
|
vec.x = orig.xv; vec.y = orig.yv; vec.z = orig.zv;
|
||||||
rotate(vec, rotatex, rotatey, rotatez, rotorigin); /* Rotate origin */
|
rotatePrecomputed(vec, sinX, cosX, sinY, cosY, sinZ, cosZ, rotorigin);
|
||||||
xv = vec.x; yv = vec.y; zv = vec.z;
|
xv = vec.x; yv = vec.y; zv = vec.z;
|
||||||
umin = orig.umin; vmin = orig.vmin;
|
umin = orig.umin; vmin = orig.vmin;
|
||||||
umax = orig.umax; vmax = orig.vmax;
|
umax = orig.umax; vmax = orig.vmax;
|
||||||
|
|
@ -120,26 +125,30 @@ public class PatchDefinition implements RenderPatch {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void rotate(Vector3D vec, double xcnt, double ycnt, double zcnt, Vector3D origin) {
|
private static void rotatePrecomputed(Vector3D vec,
|
||||||
// If no rotation, skip
|
double sinX, double cosX, double sinY, double cosY, double sinZ, double cosZ,
|
||||||
if ((xcnt == 0) && (ycnt == 0) && (zcnt == 0)) return;
|
Vector3D origin) {
|
||||||
vec.subtract(origin); /* Shoft to center of block */
|
if (sinX == 0 && sinY == 0 && sinZ == 0) return;
|
||||||
|
vec.subtract(origin);
|
||||||
/* Do X rotation */
|
/* Do X rotation */
|
||||||
double rot = Math.toRadians(xcnt);
|
if (sinX != 0) {
|
||||||
double nval = vec.z * Math.sin(rot) + vec.y * Math.cos(rot);
|
double nval = vec.z * sinX + vec.y * cosX;
|
||||||
vec.z = vec.z * Math.cos(rot) - vec.y * Math.sin(rot);
|
vec.z = vec.z * cosX - vec.y * sinX;
|
||||||
vec.y = nval;
|
vec.y = nval;
|
||||||
|
}
|
||||||
/* Do Y rotation */
|
/* Do Y rotation */
|
||||||
rot = Math.toRadians(ycnt);
|
if (sinY != 0) {
|
||||||
nval = vec.x * Math.cos(rot) - vec.z * Math.sin(rot);
|
double nval = vec.x * cosY - vec.z * sinY;
|
||||||
vec.z = vec.x * Math.sin(rot) + vec.z * Math.cos(rot);
|
vec.z = vec.x * sinY + vec.z * cosY;
|
||||||
vec.x = nval;
|
vec.x = nval;
|
||||||
|
}
|
||||||
/* Do Z rotation */
|
/* Do Z rotation */
|
||||||
rot = Math.toRadians(zcnt);
|
if (sinZ != 0) {
|
||||||
nval = vec.y * Math.sin(rot) + vec.x * Math.cos(rot);
|
double nval = vec.y * sinZ + vec.x * cosZ;
|
||||||
vec.y = vec.y * Math.cos(rot) - vec.x * Math.sin(rot);
|
vec.y = vec.y * cosZ - vec.x * sinZ;
|
||||||
vec.x = nval;
|
vec.x = nval;
|
||||||
vec.add(origin); /* Shoft back to corner */
|
}
|
||||||
|
vec.add(origin);
|
||||||
}
|
}
|
||||||
public void update(double x0, double y0, double z0, double xu,
|
public void update(double x0, double y0, double z0, double xu,
|
||||||
double yu, double zu, double xv, double yv, double zv, double umin,
|
double yu, double zu, double xv, double yv, double zv, double umin,
|
||||||
|
|
@ -171,7 +180,7 @@ public class PatchDefinition implements RenderPatch {
|
||||||
/* Compute hash code */
|
/* Compute hash code */
|
||||||
hc = (int)((Double.doubleToLongBits(x0 + xu + xv) >> 32) ^
|
hc = (int)((Double.doubleToLongBits(x0 + xu + xv) >> 32) ^
|
||||||
(Double.doubleToLongBits(y0 + yu + yv) >> 34) ^
|
(Double.doubleToLongBits(y0 + yu + yv) >> 34) ^
|
||||||
(Double.doubleToLongBits(z0 + yu + yv) >> 36) ^
|
(Double.doubleToLongBits(z0 + zu + zv) >> 36) ^
|
||||||
(Double.doubleToLongBits(umin + umax + vmin + vmax + vmaxatumax) >> 38)) ^
|
(Double.doubleToLongBits(umin + umax + vmin + vmax + vmaxatumax) >> 38)) ^
|
||||||
(sidevis.ordinal() << 8) ^ textureindex;
|
(sidevis.ordinal() << 8) ^ textureindex;
|
||||||
/* Now compute normal of surface - U cross V */
|
/* Now compute normal of surface - U cross V */
|
||||||
|
|
@ -221,27 +230,27 @@ public class PatchDefinition implements RenderPatch {
|
||||||
}
|
}
|
||||||
public boolean validate() {
|
public boolean validate() {
|
||||||
boolean good = true;
|
boolean good = true;
|
||||||
// Compute visible corners to see if we're inside cube
|
// Compute visible corners to see if we're inside cube (u.x = xu-x0, v.x = xv-x0)
|
||||||
double xx0 = x0 + (xu - x0) * umin + (xv - x0) * vmin;
|
double xx0 = x0 + u.x * umin + v.x * vmin;
|
||||||
double xx1 = x0 + (xu - x0) * vmin + (xv - x0) * vmax;
|
double xx1 = x0 + u.x * vmin + v.x * vmax;
|
||||||
double xx2 = x0 + (xu - x0) * umax + (xv - x0) * vmin;
|
double xx2 = x0 + u.x * umax + v.x * vmin;
|
||||||
double xx3 = x0 + (xu - x0) * vmax + (xv - x0) * vmax;;
|
double xx3 = x0 + u.x * vmax + v.x * vmax;
|
||||||
if (outOfRange(xx0) || outOfRange(xx1) || outOfRange(xx2) || outOfRange(xx3)) {
|
if (outOfRange(xx0) || outOfRange(xx1) || outOfRange(xx2) || outOfRange(xx3)) {
|
||||||
Log.verboseinfo(String.format("Invalid visible range xu=[%f:%f], xv=[%f:%f]", xx0, xx2, xx1, xx3));
|
Log.verboseinfo(String.format("Invalid visible range xu=[%f:%f], xv=[%f:%f]", xx0, xx2, xx1, xx3));
|
||||||
good = false;
|
good = false;
|
||||||
}
|
}
|
||||||
double yy0 = y0 + (yu - y0) * umin + (yv - y0) * vmin;
|
double yy0 = y0 + u.y * umin + v.y * vmin;
|
||||||
double yy1 = y0 + (yu - y0) * vmin + (yv - y0) * vmax;
|
double yy1 = y0 + u.y * vmin + v.y * vmax;
|
||||||
double yy2 = y0 + (yu - y0) * umax + (yv - y0) * vmin;
|
double yy2 = y0 + u.y * umax + v.y * vmin;
|
||||||
double yy3 = y0 + (yu - y0) * vmax + (yv - y0) * vmax;;
|
double yy3 = y0 + u.y * vmax + v.y * vmax;
|
||||||
if (outOfRange(yy0) || outOfRange(yy1) || outOfRange(yy2) || outOfRange(yy3)) {
|
if (outOfRange(yy0) || outOfRange(yy1) || outOfRange(yy2) || outOfRange(yy3)) {
|
||||||
Log.verboseinfo(String.format("Invalid visible range yu=[%f:%f], yv=[%f:%f]", yy0, yy2, yy1, yy3));
|
Log.verboseinfo(String.format("Invalid visible range yu=[%f:%f], yv=[%f:%f]", yy0, yy2, yy1, yy3));
|
||||||
good = false;
|
good = false;
|
||||||
}
|
}
|
||||||
double zz0 = z0 + (zu - z0) * umin + (zv - z0) * vmin;
|
double zz0 = z0 + u.z * umin + v.z * vmin;
|
||||||
double zz1 = z0 + (zu - z0) * vmin + (zv - z0) * vmax;
|
double zz1 = z0 + u.z * vmin + v.z * vmax;
|
||||||
double zz2 = z0 + (zu - z0) * umax + (zv - z0) * vmin;
|
double zz2 = z0 + u.z * umax + v.z * vmin;
|
||||||
double zz3 = z0 + (zu - z0) * vmax + (zv - z0) * vmax;
|
double zz3 = z0 + u.z * vmax + v.z * vmax;
|
||||||
if (outOfRange(zz0) || outOfRange(zz1) || outOfRange(zz2) || outOfRange(zz3)) {
|
if (outOfRange(zz0) || outOfRange(zz1) || outOfRange(zz2) || outOfRange(zz3)) {
|
||||||
Log.verboseinfo(String.format("Invalid visible range zu=[%f:%f], zv=[%f:%f]", zz0, zz2, zz1, zz3));
|
Log.verboseinfo(String.format("Invalid visible range zu=[%f:%f], zv=[%f:%f]", zz0, zz2, zz1, zz3));
|
||||||
good = false;
|
good = false;
|
||||||
|
|
|
||||||
|
|
@ -306,11 +306,10 @@ public class DynmapBlockState {
|
||||||
*/
|
*/
|
||||||
public static final DynmapBlockState getStateByGlobalIndex(int gidx) {
|
public static final DynmapBlockState getStateByGlobalIndex(int gidx) {
|
||||||
if (blockArrayByIndex != null) {
|
if (blockArrayByIndex != null) {
|
||||||
try {
|
if (gidx >= 0 && gidx < blockArrayByIndex.length) {
|
||||||
return blockArrayByIndex[gidx];
|
return blockArrayByIndex[gidx];
|
||||||
} catch (ArrayIndexOutOfBoundsException aioob) {
|
|
||||||
return AIR;
|
|
||||||
}
|
}
|
||||||
|
return AIR;
|
||||||
}
|
}
|
||||||
DynmapBlockState bs = blocksByIndex.get(gidx);
|
DynmapBlockState bs = blocksByIndex.get(gidx);
|
||||||
return (bs != null) ? bs : AIR;
|
return (bs != null) ? bs : AIR;
|
||||||
|
|
@ -322,11 +321,10 @@ public class DynmapBlockState {
|
||||||
*/
|
*/
|
||||||
public static final DynmapBlockState getStateByLegacyBlockID(int legacyid) {
|
public static final DynmapBlockState getStateByLegacyBlockID(int legacyid) {
|
||||||
if (blockArrayByLegacyID != null) {
|
if (blockArrayByLegacyID != null) {
|
||||||
try {
|
if (legacyid >= 0 && legacyid < blockArrayByLegacyID.length) {
|
||||||
return blockArrayByLegacyID[legacyid];
|
return blockArrayByLegacyID[legacyid];
|
||||||
} catch (ArrayIndexOutOfBoundsException aioob) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return blocksByLegacyID.get(legacyid);
|
return blocksByLegacyID.get(legacyid);
|
||||||
}
|
}
|
||||||
|
|
@ -348,7 +346,9 @@ public class DynmapBlockState {
|
||||||
|
|
||||||
rslt = AIR; // Assume miss
|
rslt = AIR; // Assume miss
|
||||||
String[] statelist = statename.toLowerCase().split(",");
|
String[] statelist = statename.toLowerCase().split(",");
|
||||||
for (DynmapBlockState bb : blk.states) {
|
for (int sidx = 0; sidx <= blk.stateLastIdx; sidx++) {
|
||||||
|
DynmapBlockState bb = blk.states[sidx];
|
||||||
|
if (bb == AIR) continue; // Skip AIR fill slots
|
||||||
boolean match = true;
|
boolean match = true;
|
||||||
for (int i = 0; i < statelist.length; i++) {
|
for (int i = 0; i < statelist.length; i++) {
|
||||||
boolean valmatch = false;
|
boolean valmatch = false;
|
||||||
|
|
@ -546,10 +546,20 @@ public class DynmapBlockState {
|
||||||
* Test if matches attrib=value pair
|
* Test if matches attrib=value pair
|
||||||
*/
|
*/
|
||||||
public final boolean isStateMatch(String attrib, String value) {
|
public final boolean isStateMatch(String attrib, String value) {
|
||||||
String v = attrib + "=" + value;
|
int alen = attrib.length();
|
||||||
v = v.toLowerCase();
|
int vlen = value.length();
|
||||||
|
int total = alen + 1 + vlen;
|
||||||
|
outer:
|
||||||
for (String state : stateList) {
|
for (String state : stateList) {
|
||||||
if (state.equals(v)) return true;
|
if (state.length() != total) continue;
|
||||||
|
for (int i = 0; i < alen; i++) {
|
||||||
|
if (Character.toLowerCase(attrib.charAt(i)) != state.charAt(i)) continue outer;
|
||||||
|
}
|
||||||
|
if (state.charAt(alen) != '=') continue;
|
||||||
|
for (int i = 0; i < vlen; i++) {
|
||||||
|
if (Character.toLowerCase(value.charAt(i)) != state.charAt(alen + 1 + i)) continue outer;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue