diff --git a/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java b/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java index e1ceb19d..b0a75dd5 100644 --- a/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java +++ b/DynmapCore/src/main/java/org/dynmap/common/chunk/GenericMapChunkCache.java @@ -425,24 +425,7 @@ public abstract class GenericMapChunkCache extends MapChunkCache { @Override public final DynmapBlockState getBlockTypeAt(BlockStep s) { - if (s == BlockStep.Y_MINUS) { - if (y > ymin) { - return snap.getBlockType(bx, y - 1, bz); - } - } else if (s == BlockStep.Y_PLUS) { - if (y < (worldheight - 1)) { - return snap.getBlockType(bx, y + 1, bz); - } - } else { - BlockStep ls = laststep; - stepPosition(s); - DynmapBlockState tid = snap.getBlockType(bx, y, bz); - unstepPosition(); - laststep = ls; - return tid; - } - - return DynmapBlockState.AIR; + return getBlockTypeAt(s.xoff, s.yoff, s.zoff); } @Override @@ -483,14 +466,14 @@ public abstract class GenericMapChunkCache extends MapChunkCache { @Override public final DynmapBlockState getBlockTypeAt(int xoff, int yoff, int zoff) { - int xx = this.x + xoff; - int yy = this.y + yoff; - int zz = this.z + zoff; - int idx = ((xx >> 4) - x_min) + (((zz >> 4) - z_min) * x_dim); - try { - return snaparray[idx].getBlockType(xx & 0xF, yy, zz & 0xF); - } catch (Exception x) { + int nx = x + xoff; + int ny = y + yoff; + int nz = z + zoff; + int nchunkindex = ((nx >> 4) - x_min) + (((nz >> 4) - z_min) * x_dim); + if ((nchunkindex >= snapcnt) || (nchunkindex < 0)) { return DynmapBlockState.AIR; + } else { + return snaparray[nchunkindex].getBlockType(nx & 0xF, ny, nz & 0xF); } } diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/renderer/FluidStateRenderer.java b/DynmapCore/src/main/java/org/dynmap/hdmap/renderer/FluidStateRenderer.java index f9be4103..df795642 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/renderer/FluidStateRenderer.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/renderer/FluidStateRenderer.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.BitSet; import java.util.Map; -import org.dynmap.Log; import org.dynmap.renderer.CustomRenderer; import org.dynmap.renderer.DynmapBlockState; import org.dynmap.renderer.MapDataContext; @@ -22,25 +21,44 @@ public class FluidStateRenderer extends CustomRenderer { private static final int[] still_patches = { PATCH_STILL, PATCH_STILL, PATCH_FLOWING, PATCH_FLOWING, PATCH_FLOWING, PATCH_FLOWING }; - private static final int[] flow_patches = { PATCH_STILL, PATCH_FLOWING, PATCH_FLOWING, PATCH_FLOWING, PATCH_FLOWING, PATCH_FLOWING }; + private static boolean didIinit = false; private static RenderPatch bottom = null; // Common bottom patch - private static DynIntHashMap meshcache = new DynIntHashMap(); + private static DynIntHashMap meshcache = null; - @Override - public boolean initializeRenderer(RenderPatchFactory rpf, String blkname, BitSet blockdatamask, Map custparm) { - if(!super.initializeRenderer(rpf, blkname, blockdatamask, custparm)) - return false; + private static DynIntHashMap fullculledcache = null; + + private static final void init(RenderPatchFactory rpf) { ArrayList list = new ArrayList(); // Create meshes for flat topped blocks + meshcache = new DynIntHashMap(); for (int i = 0; i < 10; i++) { list.clear(); CustomRenderer.addBox(rpf, list, 0.0, 1.0, 0.0, 1.0 - (i / 9.0), 0.0, 1.0, still_patches); putCachedModel(9 - i, 9 - i, 9 - i, 9 - i, list.toArray(new RenderPatch[list.size()])); } - if (bottom == null) { - bottom = rpf.getPatch(0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, SideVisible.TOP, PATCH_STILL); + bottom = rpf.getPatch(0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, SideVisible.TOP, PATCH_STILL); + // For full height, build culled cache - eliminate surfaces adjacent to other fluid blocks + fullculledcache = new DynIntHashMap(); + RenderPatch[] fullblkmodel = getCachedModel(9, 9, 9, 9); + for (int i = 0; i < 64; i++) { + list.clear(); + for (int f = 0; f < 6; f++) { + if ((i & (1 << f)) != 0) { // Index by face list order: see which we need to keep (bit N=1 means keep face N patch) + list.add(fullblkmodel[f]); + } + } + fullculledcache.put(i, list.toArray(new RenderPatch[list.size()])); + } + } + @Override + public boolean initializeRenderer(RenderPatchFactory rpf, String blkname, BitSet blockdatamask, Map custparm) { + if(!super.initializeRenderer(rpf, blkname, blockdatamask, custparm)) + return false; + if (!didIinit) { + init(rpf); + didIinit = true; } return true; } @@ -50,7 +68,7 @@ public class FluidStateRenderer extends CustomRenderer { return 2; } - private DynmapBlockState getFluidState(MapDataContext ctx, int dx, int dy, int dz) { + private static final DynmapBlockState getFluidState(MapDataContext ctx, int dx, int dy, int dz) { DynmapBlockState bs; if ((dx == 0) && (dy == 0) && (dz == 0)) { bs = ctx.getBlockType(); @@ -63,7 +81,7 @@ public class FluidStateRenderer extends CustomRenderer { } // Height of air, in ninths - private int getAirHeight(DynmapBlockState bs) { + private static final int getAirHeight(DynmapBlockState bs) { int idx = bs.stateIndex; return (idx > 7) ? 1 : (idx + 1); } @@ -81,15 +99,55 @@ public class FluidStateRenderer extends CustomRenderer { private static void putCachedModel(int h_1_1, int h_n1_1, int h_1_n1, int h_n1_n1, RenderPatch[] model) { meshcache.put(getIntKey(h_1_1, h_n1_1, h_1_n1, h_n1_n1), model); } - + + // Get culled full model + private static final RenderPatch[] getFullCulledModel(MapDataContext ctx, DynmapBlockState bs_0_0_0, DynmapBlockState bs_0_1_0) { + DynmapBlockState bs_n1_0_0 = getFluidState(ctx, -1, 0, 0); + DynmapBlockState bs_1_0_0 = getFluidState(ctx, 1, 0, 0); + DynmapBlockState bs_0_0_n1 = getFluidState(ctx, 0, 0, -1); + DynmapBlockState bs_0_0_1 = getFluidState(ctx, 0, 0, 1); + return getFullCulledModel(ctx, bs_0_0_0, bs_0_1_0, bs_n1_0_0, bs_1_0_0, bs_0_0_n1, bs_0_0_1); + } + // Get culled full model + private static final RenderPatch[] getFullCulledModel(MapDataContext ctx, DynmapBlockState bs_0_0_0, + DynmapBlockState bs_0_1_0, DynmapBlockState bs_n1_0_0, DynmapBlockState bs_1_0_0, + DynmapBlockState bs_0_0_n1, DynmapBlockState bs_0_0_1) { + int idx = 0; + // Check bottom - keep if not match + if (!bs_0_0_0.matchingBaseState(getFluidState(ctx, 0, -1, 0))) { + idx += 1; + } + // Check top - keep if not match + if (!bs_0_0_0.matchingBaseState(bs_0_1_0)) { + idx += 2; + } + // Check minX side - keep if not match + if (!bs_0_0_0.matchingBaseState(bs_n1_0_0)) { + idx += 4; + } + // Check maxX side - keep if not match + if (!bs_0_0_0.matchingBaseState(bs_1_0_0)) { + idx += 8; + } + // Check minZ side - keep if not match + if (!bs_0_0_0.matchingBaseState(bs_0_0_n1)) { + idx += 16; + } + // Check maxZ side - keep if not match + if (!bs_0_0_0.matchingBaseState(bs_0_0_1)) { + idx += 32; + } + return (RenderPatch[]) fullculledcache.get(idx); + } + + // Check if full height corner due to upper block states + private static final boolean isUpperCornerHeightFull(DynmapBlockState b0, DynmapBlockState u0, DynmapBlockState u1, DynmapBlockState u2, DynmapBlockState u3) { + // If any above blocks are match, return full height + return (b0.matchingBaseState(u0) || b0.matchingBaseState(u1) || b0.matchingBaseState(u2) || b0.matchingBaseState(u3)); + } // Return height in ninths (round to nearest - 0-9) - private int getCornerHeight(DynmapBlockState b0, DynmapBlockState b1, DynmapBlockState b2, DynmapBlockState b3, - DynmapBlockState u0, DynmapBlockState u1, DynmapBlockState u2, DynmapBlockState u3) { - // If any above blocks are match, return full height - if (b0.matchingBaseState(u0) || b0.matchingBaseState(u1) || b0.matchingBaseState(u2) || b0.matchingBaseState(u3)) { - return 9; - } + private static final int getCornerHeight(DynmapBlockState b0, DynmapBlockState b1, DynmapBlockState b2, DynmapBlockState b3) { int accum = 0; int cnt = 0; // Check each of 4 neighbors @@ -154,12 +212,12 @@ public class FluidStateRenderer extends CustomRenderer { @Override - public RenderPatch[] getRenderPatchList(MapDataContext ctx) { + public final RenderPatch[] getRenderPatchList(MapDataContext ctx) { DynmapBlockState bs_0_0_0 = getFluidState(ctx, 0, 0, 0); // Get own state // Check above block - if matching fluid, block will be full DynmapBlockState bs_0_1_0 = getFluidState(ctx, 0, 1, 0); if (bs_0_1_0.matchingBaseState(bs_0_0_0)) { - return getCachedModel(9, 9, 9, 9); + return getFullCulledModel(ctx, bs_0_0_0, bs_0_1_0); } // Get other above blocks DynmapBlockState bs_0_1_1 = getFluidState(ctx, 0, 1, 1); @@ -170,7 +228,16 @@ public class FluidStateRenderer extends CustomRenderer { DynmapBlockState bs_n1_1_n1 = getFluidState(ctx, -1, 1, -1); DynmapBlockState bs_1_1_n1 = getFluidState(ctx, 1, 1, -1); DynmapBlockState bs_n1_1_1 = getFluidState(ctx, -1, 1, 1); - // Get other neighbors + // See if full height corner due to upper blocks + boolean isfull_1_1 = isUpperCornerHeightFull(bs_0_0_0, bs_0_1_0, bs_1_1_0, bs_0_1_1, bs_1_1_1); + boolean isfull_1_n1 = isUpperCornerHeightFull(bs_0_0_0, bs_0_1_0, bs_1_1_0, bs_0_1_n1, bs_1_1_n1); + boolean isfull_n1_1 = isUpperCornerHeightFull(bs_0_0_0, bs_0_1_0, bs_n1_1_0, bs_0_1_1, bs_n1_1_1); + boolean isfull_n1_n1 = isUpperCornerHeightFull(bs_0_0_0, bs_0_1_0, bs_n1_1_0, bs_0_1_n1, bs_n1_1_n1); + // If full height + if (isfull_1_1 && isfull_1_n1 && isfull_n1_1 && isfull_n1_n1) { + return getFullCulledModel(ctx, bs_0_0_0, bs_0_1_0); + } + // Get other neighbors to figure out corner heights DynmapBlockState bs_0_0_1 = getFluidState(ctx, 0, 0, 1); DynmapBlockState bs_1_0_0 = getFluidState(ctx, 1, 0, 0); DynmapBlockState bs_1_0_1 = getFluidState(ctx, 1, 0, 1); @@ -180,10 +247,14 @@ public class FluidStateRenderer extends CustomRenderer { DynmapBlockState bs_1_0_n1 = getFluidState(ctx, 1, 0, -1); DynmapBlockState bs_n1_0_1 = getFluidState(ctx, -1, 0, 1); // Get each corner height - int bh_1_1 = getCornerHeight(bs_0_0_0, bs_0_0_1, bs_1_0_0, bs_1_0_1, bs_0_1_0, bs_1_1_0, bs_0_1_1, bs_1_1_1); - int bh_1_n1 = getCornerHeight(bs_0_0_0, bs_0_0_n1, bs_1_0_0, bs_1_0_n1, bs_0_1_0, bs_1_1_0, bs_0_1_n1, bs_1_1_n1); - int bh_n1_1 = getCornerHeight(bs_0_0_0, bs_0_0_1, bs_n1_0_0, bs_n1_0_1, bs_0_1_0, bs_n1_1_0, bs_0_1_1, bs_n1_1_1); - int bh_n1_n1 = getCornerHeight(bs_0_0_0, bs_0_0_n1, bs_n1_0_0, bs_n1_0_n1, bs_0_1_0, bs_n1_1_0, bs_0_1_n1, bs_n1_1_n1); + int bh_1_1 = isfull_1_1 ? 9 : getCornerHeight(bs_0_0_0, bs_0_0_1, bs_1_0_0, bs_1_0_1); + int bh_1_n1 = isfull_1_n1 ? 9 : getCornerHeight(bs_0_0_0, bs_0_0_n1, bs_1_0_0, bs_1_0_n1); + int bh_n1_1 = isfull_n1_1 ? 9 : getCornerHeight(bs_0_0_0, bs_0_0_1, bs_n1_0_0, bs_n1_0_1); + int bh_n1_n1 = isfull_n1_n1 ? 9 : getCornerHeight(bs_0_0_0, bs_0_0_n1, bs_n1_0_0, bs_n1_0_n1); + // If full height + if ((bh_1_1 == 9) && (bh_1_n1 == 9) && (bh_n1_1 == 9) && (bh_n1_n1 == 9)) { + return getFullCulledModel(ctx, bs_0_0_0, bs_0_1_0, bs_n1_0_0, bs_1_0_0, bs_0_0_n1, bs_0_0_1); + } // Do cached lookup of model RenderPatch[] mod = getCachedModel(bh_1_1, bh_n1_1, bh_1_n1, bh_n1_n1); // If not found, create model @@ -226,13 +297,13 @@ public class FluidStateRenderer extends CustomRenderer { return mod; } - private void addSide(ArrayList list, RenderPatchFactory rpf, double x0, double z0, double x1, double z1, int h0, int h1) { + private static final void addSide(ArrayList list, RenderPatchFactory rpf, double x0, double z0, double x1, double z1, int h0, int h1) { if ((h0 == 0) && (h1 == 0)) return; list.add(rpf.getPatch(x0, 0, z0, x1, 0, z1, x0, 1, z0, 0, 1, 0, 0, (double) h0 / 9.0, (double) h1 / 9.0, SideVisible.TOP, PATCH_FLOWING)); } - private void addTop(ArrayList list, RenderPatchFactory rpf, double x0, double z0, double x1, double z1, int h0, int h1, int h2, int h3) { + private static final void addTop(ArrayList list, RenderPatchFactory rpf, double x0, double z0, double x1, double z1, int h0, int h1, int h2, int h3) { int h0_upper = h1 + h2 - h3; if (x0 == x1) { // edge is Z+/- if (h0_upper == h0) { // If single surface