diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/CaveHDShader.java b/DynmapCore/src/main/java/org/dynmap/hdmap/CaveHDShader.java index f64f08f3..1963c342 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/CaveHDShader.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/CaveHDShader.java @@ -251,6 +251,9 @@ public class CaveHDShader implements HDShader { public int[] getLightingTable() { return lightingTable; } + @Override + public void setLastBlockState(DynmapBlockState new_lastbs) { + } } /** diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/CustomBlockModel.java b/DynmapCore/src/main/java/org/dynmap/hdmap/CustomBlockModel.java index dd82d8a8..b7a2fbc9 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/CustomBlockModel.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/CustomBlockModel.java @@ -12,18 +12,18 @@ import org.dynmap.renderer.RenderPatch; public class CustomBlockModel extends HDBlockModel { public CustomRenderer render; - public CustomBlockModel(String blockname, BitSet databits, String classname, Map classparm, String blockset) { - super(blockname, databits, blockset); + public CustomBlockModel(DynmapBlockState bstate, BitSet databits, String classname, Map classparm, String blockset) { + super(bstate, databits, blockset); try { Class cls = Class.forName(classname); /* Get class */ render = (CustomRenderer) cls.newInstance(); - if(render.initializeRenderer(HDBlockModels.pdf, blockname, databits, classparm) == false) { + if(render.initializeRenderer(HDBlockModels.pdf, bstate.blockName, databits, classparm) == false) { Log.severe("Error loading custom renderer - " + classname); render = null; } else { if(render.getTileEntityFieldsNeeded() != null) { - DynmapBlockState bbs = DynmapBlockState.getBaseStateByName(blockname); + DynmapBlockState bbs = bstate.baseState; for(int i = 0; i < bbs.getStateCount(); i++) { if (databits.isEmpty() || databits.get(i)) { DynmapBlockState bs = bbs.getState(i); diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/DefaultHDShader.java b/DynmapCore/src/main/java/org/dynmap/hdmap/DefaultHDShader.java index eeacf96b..e3a9b11d 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/DefaultHDShader.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/DefaultHDShader.java @@ -245,6 +245,9 @@ public class DefaultHDShader implements HDShader { public int[] getLightingTable() { return lightingTable; } + @Override + public void setLastBlockState(DynmapBlockState new_lastbs) { + } } private class OurBiomeShaderState extends OurShaderState { diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockModel.java b/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockModel.java index 7c4b545a..ac14820c 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockModel.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockModel.java @@ -8,13 +8,13 @@ public abstract class HDBlockModel { private String blockset; /** * Block definition - positions correspond to Bukkit coordinates (+X is south, +Y is up, +Z is west) - * @param blockname - block name + * @param bstate - block state * @param databits - bitmap of block data bits matching this model (bit N is set if data=N would match) * @param blockset - ID of block definition set */ - protected HDBlockModel(String blockname, BitSet databits, String blockset) { + protected HDBlockModel(DynmapBlockState bstate, BitSet databits, String blockset) { this.blockset = blockset; - DynmapBlockState bblk = DynmapBlockState.getBaseStateByName(blockname); + DynmapBlockState bblk = bstate.baseState; if (bblk.isNotAir()) { for (int i = 0; i < bblk.getStateCount(); i++) { if (databits.isEmpty() || databits.get(i)) { diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockModels.java b/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockModels.java index 058a5c65..33a0db10 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockModels.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockModels.java @@ -43,7 +43,7 @@ public class HDBlockModels { private static HashSet loadedmods = new HashSet(); private static HashMap scaled_models_by_scale = new HashMap(); - public static final int getMaxPatchCount() { return max_patches; } + public static final int getMaxPatchCount() { return max_patches; } public static final PatchDefinitionFactory getPatchDefinitionFactory() { return pdf; } /* Reset model if defined by different block set */ @@ -390,7 +390,7 @@ public class HDBlockModels { for(String bname : blknames) { DynmapBlockState bblk = DynmapBlockState.getBaseStateByName(bname); if (bblk.isNotAir()) { - modlist.add(new HDBlockVolumetricModel(bblk.blockName, databits, scale, new long[0], blockset)); + modlist.add(new HDBlockVolumetricModel(bblk, databits, scale, new long[0], blockset)); cnt++; } else { @@ -740,7 +740,7 @@ public class HDBlockModels { for(String nm : blknames) { DynmapBlockState bs = DynmapBlockState.getBaseStateByName(nm); if (bs.isNotAir()) { - pmodlist.add(new HDBlockPatchModel(bs.blockName, databits, patcharray, blockset)); + pmodlist.add(new HDBlockPatchModel(bs, databits, patcharray, blockset)); cnt++; } else { @@ -804,7 +804,7 @@ public class HDBlockModels { for(String nm : blknames) { DynmapBlockState bs = DynmapBlockState.getBaseStateByName(nm); if (bs.isNotAir()) { - pmodlist.add(new HDBlockPatchModel(bs.blockName, databits, patcharray, blockset)); + pmodlist.add(new HDBlockPatchModel(bs, databits, patcharray, blockset)); cnt++; } else { @@ -852,7 +852,7 @@ public class HDBlockModels { for (String nm : blknames) { DynmapBlockState bs = DynmapBlockState.getBaseStateByName(nm); if (bs.isNotAir()) { - CustomBlockModel cbm = new CustomBlockModel(bs.blockName, databits, cls, custargs, blockset); + CustomBlockModel cbm = new CustomBlockModel(bs, databits, cls, custargs, blockset); if(cbm.render == null) { Log.severe("Custom block model failed to initialize = line " + rdr.getLineNumber() + " of " + fname); } diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockPatchModel.java b/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockPatchModel.java index 000244b6..d68c6cbf 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockPatchModel.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockPatchModel.java @@ -2,6 +2,7 @@ package org.dynmap.hdmap; import java.util.BitSet; +import org.dynmap.renderer.DynmapBlockState; import org.dynmap.utils.PatchDefinition; public class HDBlockPatchModel extends HDBlockModel { @@ -11,13 +12,13 @@ public class HDBlockPatchModel extends HDBlockModel { /** * Block definition - positions correspond to Bukkit coordinates (+X is south, +Y is up, +Z is west) * (for patch models) - * @param blockname - block name + * @param bs - block state * @param databits - bitmap of block data bits matching this model (bit N is set if data=N would match) * @param patches - list of patches (surfaces composing model) * @param blockset - ID of set of blocks defining model */ - public HDBlockPatchModel(String blockname, BitSet databits, PatchDefinition[] patches, String blockset) { - super(blockname, databits, blockset); + public HDBlockPatchModel(DynmapBlockState bs, BitSet databits, PatchDefinition[] patches, String blockset) { + super(bs, databits, blockset); this.patches = patches; int max = 0; for(int i = 0; i < patches.length; i++) { diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockVolumetricModel.java b/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockVolumetricModel.java index c23e1c72..90ee4245 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockVolumetricModel.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/HDBlockVolumetricModel.java @@ -3,6 +3,8 @@ package org.dynmap.hdmap; import java.util.BitSet; import java.util.HashMap; +import org.dynmap.renderer.DynmapBlockState; + public class HDBlockVolumetricModel extends HDBlockModel { /* Volumetric model specific attributes */ private long blockflags[]; @@ -11,15 +13,15 @@ public class HDBlockVolumetricModel extends HDBlockModel { /** * Block definition - positions correspond to Bukkit coordinates (+X is south, +Y is up, +Z is west) * (for volumetric models) - * @param blockname - block name + * @param bs - block state * @param databits - bitmap of block data bits matching this model (bit N is set if data=N would match) * @param nativeres - native subblocks per edge of cube (up to 64) * @param blockflags - array of native^2 long integers representing volume of block (bit X of element (nativeres*Y+Z) is set if that subblock is filled) * if array is short, other elements area are assumed to be zero (fills from bottom of block up) * @param blockset - ID of set of blocks defining model */ - public HDBlockVolumetricModel(String blockname, BitSet databits, int nativeres, long[] blockflags, String blockset) { - super(blockname, databits, blockset); + public HDBlockVolumetricModel(DynmapBlockState bs, BitSet databits, int nativeres, long[] blockflags, String blockset) { + super(bs, databits, blockset); this.nativeres = nativeres; this.blockflags = new long[nativeres * nativeres]; diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/HDPerspectiveState.java b/DynmapCore/src/main/java/org/dynmap/hdmap/HDPerspectiveState.java index 00519e0e..a8f55270 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/HDPerspectiveState.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/HDPerspectiveState.java @@ -63,6 +63,10 @@ public interface HDPerspectiveState { * @return coordinates of ray */ int[] getSubblockCoord(); + /** + * Check if point is on face + */ + boolean isOnFace(); /** * Get map iterator * @return iterator diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/HDShaderState.java b/DynmapCore/src/main/java/org/dynmap/hdmap/HDShaderState.java index e797f5de..d41ea868 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/HDShaderState.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/HDShaderState.java @@ -1,6 +1,7 @@ package org.dynmap.hdmap; import org.dynmap.Color; +import org.dynmap.renderer.DynmapBlockState; import org.dynmap.utils.DynLongHashMap; /** @@ -59,4 +60,8 @@ public interface HDShaderState { * @return array of lighting values */ int[] getLightingTable(); + /** + * Update last block state (called before moving to next block) + */ + void setLastBlockState(DynmapBlockState new_lastbs); } diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/InhabitedHDShader.java b/DynmapCore/src/main/java/org/dynmap/hdmap/InhabitedHDShader.java index d6a6639a..79b09827 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/InhabitedHDShader.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/InhabitedHDShader.java @@ -210,6 +210,9 @@ public class InhabitedHDShader implements HDShader { public int[] getLightingTable() { return lightingTable; } + @Override + public void setLastBlockState(DynmapBlockState new_lastbs) { + } } /** diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java b/DynmapCore/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java index 3cbe1fc0..6574e9a9 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java @@ -80,6 +80,7 @@ public class IsoHDPerspective implements HDPerspective { private static final BlockStep [] semi_steps = { BlockStep.Y_PLUS, BlockStep.X_MINUS, BlockStep.X_PLUS, BlockStep.Z_MINUS, BlockStep.Z_PLUS }; private DynmapBlockState full_water = null; + private RenderPatch full_water_patch = null; private class OurPerspectiveState implements HDPerspectiveState { DynmapBlockState blocktype = DynmapBlockState.AIR; @@ -122,11 +123,12 @@ public class IsoHDPerspective implements HDPerspective { Vector3D v0 = new Vector3D(); Vector3D vS = new Vector3D(); Vector3D d_cross_uv = new Vector3D(); - double patch_t[] = new double[HDBlockModels.getMaxPatchCount()]; - double patch_u[] = new double[HDBlockModels.getMaxPatchCount()]; - double patch_v[] = new double[HDBlockModels.getMaxPatchCount()]; - BlockStep patch_step[] = new BlockStep[HDBlockModels.getMaxPatchCount()]; - int patch_id[] = new int[HDBlockModels.getMaxPatchCount()]; + // Double max patch count to be safe for patches + water patches + double patch_t[] = new double[2*HDBlockModels.getMaxPatchCount()]; + double patch_u[] = new double[2*HDBlockModels.getMaxPatchCount()]; + double patch_v[] = new double[2*HDBlockModels.getMaxPatchCount()]; + BlockStep patch_step[] = new BlockStep[2*HDBlockModels.getMaxPatchCount()]; + int patch_id[] = new int[2*HDBlockModels.getMaxPatchCount()]; int cur_patch = -1; double cur_patch_u; double cur_patch_v; @@ -142,6 +144,7 @@ public class IsoHDPerspective implements HDPerspective { /* Cache for custom model patch lists */ private final DynLongHashMap custom_meshes; + private final DynLongHashMap custom_fluid_meshes; public OurPerspectiveState(MapIterator mi, boolean isnether, int scaled) { mapiter = mi; @@ -154,6 +157,7 @@ public class IsoHDPerspective implements HDPerspective { for(int i = 0; i < llcache.length; i++) llcache[i] = new LightLevels(); custom_meshes = new DynLongHashMap(); + custom_fluid_meshes = new DynLongHashMap(); modscale = basemodscale << scaled; scalemodels = HDBlockModels.getModelsForScale(basemodscale << scaled); } @@ -394,83 +398,112 @@ public class IsoHDPerspective implements HDPerspective { nonairhit = true; firststep = false; } + // Set current block as last block for any incomplete shaders + for(int i = 0; i < shaderstate.length; i++) { + if(!shaderdone[i]) + // Update with current block as last block + shaderstate[i].setLastBlockState(blocktype); + } return false; } - private final boolean handlePatches(RenderPatch[] patches, HDShaderState[] shaderstate, boolean[] shaderdone) { + private final int handlePatch(PatchDefinition pd, int hitcnt) { + /* Compute origin of patch */ + v0.x = (double)x + pd.x0; + v0.y = (double)y + pd.y0; + v0.z = (double)z + pd.z0; + /* Compute cross product of direction and V vector */ + d_cross_uv.set(direction); + d_cross_uv.crossProduct(pd.v); + /* Compute determinant - inner product of this with U */ + double det = pd.u.innerProduct(d_cross_uv); + /* If parallel to surface, no intercept */ + switch(pd.sidevis) { + case TOP: + if (det < 0.000001) { + return hitcnt; + } + break; + case BOTTOM: + if (det > -0.000001) { + return hitcnt; + } + break; + case BOTH: + case FLIP: + if((det > -0.000001) && (det < 0.000001)) { + return hitcnt; + } + break; + } + double inv_det = 1.0 / det; /* Calculate inverse determinant */ + /* Compute distance from patch to ray origin */ + vS.set(top); + vS.subtract(v0); + /* Compute u - slope times inner product of offset and cross product */ + double u = inv_det * vS.innerProduct(d_cross_uv); + if((u <= pd.umin) || (u >= pd.umax)) { + return hitcnt; + } + /* Compute cross product of offset and U */ + vS.crossProduct(pd.u); + /* Compute V using slope times inner product of direction and cross product */ + double v = inv_det * direction.innerProduct(vS); + if((v <= pd.vmin) || (v >= pd.vmax) || ((u + v) >= pd.uplusvmax)) { + return hitcnt; + } + /* Compute parametric value of intercept */ + double t = inv_det * pd.v.innerProduct(vS); + if (t > 0.000001) { /* We've got a hit */ + patch_t[hitcnt] = t; + patch_u[hitcnt] = u; + patch_v[hitcnt] = v; + patch_id[hitcnt] = pd.textureindex; + if(det > 0) { + patch_step[hitcnt] = pd.step.opposite(); + } + else { + if (pd.sidevis == SideVisible.FLIP) { + patch_u[hitcnt] = 1 - u; + } + patch_step[hitcnt] = pd.step; + } + hitcnt++; + } + return hitcnt; + } + + private final boolean handlePatches(RenderPatch[] patches, HDShaderState[] shaderstate, boolean[] shaderdone, RenderPatch[] fluidpatches) { int hitcnt = 0; + int water_hit = Integer.MAX_VALUE; // hit index of first water hit /* Loop through patches : compute intercept values for each */ for(int i = 0; i < patches.length; i++) { - PatchDefinition pd = (PatchDefinition)patches[i]; - /* Compute origin of patch */ - v0.x = (double)x + pd.x0; - v0.y = (double)y + pd.y0; - v0.z = (double)z + pd.z0; - /* Compute cross product of direction and V vector */ - d_cross_uv.set(direction); - d_cross_uv.crossProduct(pd.v); - /* Compute determinant - inner product of this with U */ - double det = pd.u.innerProduct(d_cross_uv); - /* If parallel to surface, no intercept */ - switch(pd.sidevis) { - case TOP: - if (det < 0.000001) { - continue; - } - break; - case BOTTOM: - if (det > -0.000001) { - continue; - } - break; - case BOTH: - case FLIP: - if((det > -0.000001) && (det < 0.000001)) { - continue; - } - break; + hitcnt = handlePatch((PatchDefinition)patches[i], hitcnt); + } + if ((fluidpatches != null) && (fluidpatches.length > 0)) { + if (full_water == null) { + full_water = DynmapBlockState.getBaseStateByName(DynmapBlockState.WATER_BLOCK); } - double inv_det = 1.0 / det; /* Calculate inverse determinant */ - /* Compute distance from patch to ray origin */ - vS.set(top); - vS.subtract(v0); - /* Compute u - slope times inner product of offset and cross product */ - double u = inv_det * vS.innerProduct(d_cross_uv); - if((u <= pd.umin) || (u >= pd.umax)) { - continue; + int prev_hitcnt = hitcnt; + for(int i = 0; i < fluidpatches.length; i++) { + hitcnt = handlePatch((PatchDefinition)fluidpatches[i], hitcnt); } - /* Compute cross product of offset and U */ - vS.crossProduct(pd.u); - /* Compute V using slope times inner product of direction and cross product */ - double v = inv_det * direction.innerProduct(vS); - if((v <= pd.vmin) || (v >= pd.vmax) || ((u + v) >= pd.uplusvmax)) { - continue; - } - /* Compute parametric value of intercept */ - double t = inv_det * pd.v.innerProduct(vS); - if (t > 0.000001) { /* We've got a hit */ - patch_t[hitcnt] = t; - patch_u[hitcnt] = u; - patch_v[hitcnt] = v; - patch_id[hitcnt] = pd.textureindex; - if(det > 0) { - patch_step[hitcnt] = pd.step.opposite(); - } - else { - if (pd.sidevis == SideVisible.FLIP) { - patch_u[hitcnt] = 1 - u; - } - patch_step[hitcnt] = pd.step; - } - hitcnt++; + if (prev_hitcnt < hitcnt) { // At least one water hit? + water_hit = prev_hitcnt; // Remember index } } /* If no hits, we're done */ if(hitcnt == 0) { + // Set current block as last block for any incomplete shaders + for(int i = 0; i < shaderstate.length; i++) { + if(!shaderdone[i]) + // Update with current block as last block + shaderstate[i].setLastBlockState(blocktype); + } return false; } BlockStep old_laststep = laststep; /* Save last step */ - + DynmapBlockState cur_bt = blocktype; for(int i = 0; i < hitcnt; i++) { /* Find closest hit (lowest parametric value) */ double best_t = Double.MAX_VALUE; @@ -486,6 +519,10 @@ public class IsoHDPerspective implements HDPerspective { cur_patch_v = patch_v[best_patch]; laststep = patch_step[best_patch]; cur_patch_t = best_t; + // If the water patch, switch to water state and patch index + if (best_patch >= water_hit) { + blocktype = full_water; + } /* Process the shaders */ boolean done = true; for(int j = 0; j < shaderstate.length; j++) { @@ -493,6 +530,10 @@ public class IsoHDPerspective implements HDPerspective { shaderdone[j] = shaderstate[j].processBlock(this); done = done && shaderdone[j]; } + // If water, restore block type + if (best_patch >= water_hit) { + blocktype = cur_bt; + } cur_patch = -1; /* If all are done, we're out */ if(done) { @@ -504,10 +545,41 @@ public class IsoHDPerspective implements HDPerspective { patch_t[best_patch] = Double.MAX_VALUE; } laststep = old_laststep; - + + // Set current block as last block for any incomplete shaders + for(int i = 0; i < shaderstate.length; i++) { + if(!shaderdone[i]) + // Update with current block as last block + shaderstate[i].setLastBlockState(blocktype); + } + return false; } - + + private RenderPatch[] getPatches(DynmapBlockState bt, boolean isFluid) { + RenderPatch[] patches = scalemodels.getPatchModel(bt); + /* If no patches, see if custom model */ + if (patches == null) { + CustomBlockModel cbm = scalemodels.getCustomBlockModel(bt); + if (cbm != null) { /* If found, see if cached already */ + if (isFluid) { + patches = this.getCustomFluidMesh(); + if (patches == null) { + patches = cbm.getMeshForBlock(mapiter); + this.setCustomFluidMesh(patches); + } + } + else { + patches = this.getCustomMesh(); + if (patches == null) { + patches = cbm.getMeshForBlock(mapiter); + this.setCustomMesh(patches); + } + } + } + } + return patches; + } /** * Process visit of ray to block */ @@ -520,45 +592,17 @@ public class IsoHDPerspective implements HDPerspective { } } else if(nonairhit || blocktype.isNotAir()) { - // If waterlogged, start by rendering as if full water block - if (blocktype.isWaterlogged()) { - boolean done = true; - DynmapBlockState saved_type = blocktype; - if (full_water == null) { - full_water = DynmapBlockState.getBaseStateByName(DynmapBlockState.WATER_BLOCK); - } - blocktype = full_water; // Switch to water state - subalpha = -1; - for (int i = 0; i < shaderstate.length; i++) { - if(!shaderdone[i]) { - shaderdone[i] = shaderstate[i].processBlock(this); - } - done = done && shaderdone[i]; - } - // Restore block type - blocktype = saved_type; - /* If all are done, we're out */ - if (done) { - return true; - } - nonairhit = true; - } short[] model; - RenderPatch[] patches = scalemodels.getPatchModel(blocktype); - /* If no patches, see if custom model */ - if (patches == null) { - CustomBlockModel cbm = scalemodels.getCustomBlockModel(blocktype); - if (cbm != null) { /* If found, see if cached already */ - patches = this.getCustomMesh(); - if (patches == null) { - patches = cbm.getMeshForBlock(mapiter); - this.setCustomMesh(patches); - } - } - } + RenderPatch[] patches = getPatches(blocktype, false); /* Look up to see if block is modelled */ if(patches != null) { - return handlePatches(patches, shaderstate, shaderdone); + RenderPatch[] fluidpatches = null; + // If so, check for waterlogged + DynmapBlockState fluidstate = blocktype.getLiquidState(); + if (fluidstate != null) { + fluidpatches = getPatches(fluidstate, true); + } + return handlePatches(patches, shaderstate, shaderdone, fluidpatches); } else if ((model = scalemodels.getScaledModel(blocktype)) != null) { return handleSubModel(model, shaderstate, shaderdone); @@ -569,6 +613,8 @@ public class IsoHDPerspective implements HDPerspective { for(int i = 0; i < shaderstate.length; i++) { if(!shaderdone[i]) { shaderdone[i] = shaderstate[i].processBlock(this); + // Update with current block as last block + shaderstate[i].setLastBlockState(blocktype); } done = done && shaderdone[i]; } @@ -825,6 +871,27 @@ public class IsoHDPerspective implements HDPerspective { return subblock_xyz; } + // Is the hit on a cullable face? + public final boolean isOnFace() { + double tt; + if(cur_patch >= 0) { /* If patch hit */ + tt = cur_patch_t; + } + else if(subalpha < 0) { + tt = t + 0.0000001; + } + else { // Full blocks always on face + return true; + } + double xx = top.x + tt * direction.x; + double yy = top.y + tt * direction.y; + double zz = top.z + tt * direction.z; + double xoff = xx - fastFloor(xx); + double yoff = yy - fastFloor(yy); + double zoff = zz - fastFloor(zz); + return ((xoff < 0.0001) || (xoff > 0.9999) || (yoff < 0.0001) || (yoff > 0.9999) || (zoff < 0.0001) || (zoff > 0.9999)); + } + /** * Get current texture index */ @@ -870,6 +937,20 @@ public class IsoHDPerspective implements HDPerspective { long key = this.mapiter.getBlockKey(); /* Get key for current block */ custom_meshes.put(key, mesh); } + /** + * Get custom fluid mesh for block, if defined (null if not) + */ + public final RenderPatch[] getCustomFluidMesh() { + long key = this.mapiter.getBlockKey(); /* Get key for current block */ + return (RenderPatch[])custom_fluid_meshes.get(key); + } + /** + * Save custom mesh for block + */ + public final void setCustomFluidMesh(RenderPatch[] mesh) { + long key = this.mapiter.getBlockKey(); /* Get key for current block */ + custom_fluid_meshes.put(key, mesh); + } } public IsoHDPerspective(DynmapCore core, ConfigurationNode configuration) { diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/TexturePack.java b/DynmapCore/src/main/java/org/dynmap/hdmap/TexturePack.java index 9344f71c..fdc42cab 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/TexturePack.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/TexturePack.java @@ -2652,6 +2652,7 @@ public class TexturePack { } } } + /** * Read color for given subblock coordinate, with given block id and data and face */ @@ -2664,6 +2665,7 @@ public class TexturePack { boolean hasblockcoloring = ss.do_biome_shading && this.blockColoring.hasBlkStateValue(blk); // Test if we have no texture modifications boolean simplemap = (textid < COLORMOD_MULT_INTERNAL) && (!hasblockcoloring); + int[] xyz = null; if (simplemap) { /* If simple mapping */ int[] texture = getTileARGB(textid); @@ -2671,7 +2673,7 @@ public class TexturePack { int u = 0, v = 0; /* If not patch, compute U and V */ if(patchid < 0) { - int[] xyz = ps.getSubblockCoord(); + xyz = ps.getSubblockCoord(); switch(laststep) { case X_MINUS: /* South face: U = East (Z-), V = Down (Y-) */ @@ -2729,7 +2731,7 @@ public class TexturePack { /* If clear-inside op, get out early */ if((textop == COLORMOD_CLEARINSIDE) || (textop == COLORMOD_MULTTONED_CLEARINSIDE)) { /* Check if previous block is same block type as we are: surface is transparent if it is */ - if (blk.matchingBaseState(lastblocktype) || (blk.isWater() && lastblocktype.isWaterlogged())) { + if ((blk.matchingBaseState(lastblocktype) || (blk.isWater() && lastblocktype.isWaterlogged())) && ps.isOnFace()) { rslt.setTransparent(); return; } @@ -2747,8 +2749,7 @@ public class TexturePack { int u = 0, v = 0, tmp; if(patchid < 0) { - int[] xyz = ps.getSubblockCoord(); - + if (xyz == null) xyz = ps.getSubblockCoord(); switch(laststep) { case X_MINUS: /* South face: U = East (Z-), V = Down (Y-) */ u = native_scale-xyz[2]-1; v = native_scale-xyz[1]-1; diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/TexturePackHDShader.java b/DynmapCore/src/main/java/org/dynmap/hdmap/TexturePackHDShader.java index 330258ea..8a27a9ab 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/TexturePackHDShader.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/TexturePackHDShader.java @@ -172,7 +172,7 @@ public class TexturePackHDShader implements HDShader { public void reset(HDPerspectiveState ps) { for(int i = 0; i < color.length; i++) color[i].setTransparent(); - lastblk = DynmapBlockState.AIR; + setLastBlockState(DynmapBlockState.AIR); } /** @@ -184,13 +184,13 @@ public class TexturePackHDShader implements HDShader { if ((hiddenids != null) && hiddenids.get(blocktype.globalStateIndex)) { blocktype = DynmapBlockState.AIR; } - DynmapBlockState lastblocktype = lastblk; - lastblk = blocktype; if (blocktype.isAir()) { return false; } + DynmapBlockState lastblocktype = lastblk; + /* Get color from textures */ if (scaledtp != null) { scaledtp.readColor(ps, mapiter, c, blocktype, lastblocktype, ShaderState.this); @@ -314,6 +314,10 @@ public class TexturePackHDShader implements HDShader { public int[] getLightingTable() { return lightingTable; } + @Override + public void setLastBlockState(DynmapBlockState new_lastbs) { + lastblk = new_lastbs; + } } /** diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/TopoHDShader.java b/DynmapCore/src/main/java/org/dynmap/hdmap/TopoHDShader.java index a08b78fc..d91700ae 100644 --- a/DynmapCore/src/main/java/org/dynmap/hdmap/TopoHDShader.java +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/TopoHDShader.java @@ -318,6 +318,9 @@ public class TopoHDShader implements HDShader { public int[] getLightingTable() { return lightingTable; } + @Override + public void setLastBlockState(DynmapBlockState new_lastbs) { + } } /** diff --git a/DynmapCore/src/main/java/org/dynmap/hdmap/renderer/FluidStateRenderer.java b/DynmapCore/src/main/java/org/dynmap/hdmap/renderer/FluidStateRenderer.java new file mode 100644 index 00000000..3e707234 --- /dev/null +++ b/DynmapCore/src/main/java/org/dynmap/hdmap/renderer/FluidStateRenderer.java @@ -0,0 +1,58 @@ +package org.dynmap.hdmap.renderer; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Map; + +import org.dynmap.renderer.CustomRenderer; +import org.dynmap.renderer.DynmapBlockState; +import org.dynmap.renderer.MapDataContext; +import org.dynmap.renderer.RenderPatch; +import org.dynmap.renderer.RenderPatchFactory; + +/** + * Renderer for vanilla fluids - will attempt to emulate vanilla rendering behavior, but still WIP + */ +public class FluidStateRenderer extends CustomRenderer { + private RenderPatch[][] flat_meshes = new RenderPatch[8][]; // Meshes for each level from 0 (full) to 7 (most empty), no surface incline + private RenderPatch[] full_mesh; + + private static final int PATCH_STILL = 0; + private static final int PATCH_FLOWING = 1; + + private static final int[] still_patches = { PATCH_STILL, PATCH_STILL, PATCH_FLOWING, PATCH_FLOWING, PATCH_FLOWING, PATCH_FLOWING }; + + @Override + public boolean initializeRenderer(RenderPatchFactory rpf, String blkname, BitSet blockdatamask, Map custparm) { + if(!super.initializeRenderer(rpf, blkname, blockdatamask, custparm)) + return false; + ArrayList list = new ArrayList(); + // Create meshes for flat topped blocks + for (int i = 0; i < 8; i++) { + list.clear(); + CustomRenderer.addBox(rpf, list, 0.0, 1.0, 0.0, 0.875 - (0.12 * i), 0.0, 1.0, still_patches); + flat_meshes[i] = list.toArray(new RenderPatch[list.size()]); + } + list.clear(); + CustomRenderer.addBox(rpf, list, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, still_patches); + full_mesh = list.toArray(new RenderPatch[list.size()]); + + return true; + } + + @Override + public int getMaximumTextureCount() { + return 2; + } + + @Override + public RenderPatch[] getRenderPatchList(MapDataContext ctx) { + int idx = ctx.getBlockType().stateIndex; + if ((idx == 0) || (idx >= 8)) { + DynmapBlockState up = ctx.getBlockTypeAt(0, 1, 0); + if (up.isWater() || up.isWaterlogged()) + return full_mesh; + } + return (idx < 8) ? flat_meshes[idx] : flat_meshes[0]; + } +} diff --git a/DynmapCore/src/main/resources/models_0.txt b/DynmapCore/src/main/resources/models_0.txt index 1f208312..94a9ea4a 100644 --- a/DynmapCore/src/main/resources/models_0.txt +++ b/DynmapCore/src/main/resources/models_0.txt @@ -763,27 +763,9 @@ layer:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ---------------- # Lily pad patchblock:id=waterlily,data=*,patch0=HorizY001ZTop -# Water (1 down) -# Lava (1 down) -boxblock:id=flowing_water,id=water,id=flowing_lava,id=lava,data=1,ymax=0.875 -# Water (2 down) -# Lava (2 down) -boxblock:id=flowing_water,id=water,id=flowing_lava,id=lava,data=2,ymax=0.75 -# Water (3 down) -# Lava (3 down) -boxblock:id=flowing_water,id=water,id=flowing_lava,id=lava,data=3,ymax=0.625 -# Water (4 down) -# Lava (4 down) -boxblock:id=flowing_water,id=water,id=flowing_lava,id=lava,data=4,ymax=0.5 -# Water (5 down) -# Lava (5 down) -boxblock:id=flowing_water,id=water,id=flowing_lava,id=lava,data=5,ymax=0.375 -# Water (6 down) -# Lava (6 down) -boxblock:id=flowing_water,id=water,id=flowing_lava,id=lava,data=6,ymax=0.25 -# Water (7 down) -# Lava (7 down) -boxblock:id=flowing_water,id=water,id=flowing_lava,id=lava,data=7,ymax=0.125 +# Water +# Lava +customblock:id=flowing_water,id=water,id=flowing_lava,id=lava,class=org.dynmap.hdmap.renderer.FluidStateRenderer # Enchantment Table boxblock:id=enchanting_table,data=*,ymax=0.75 diff --git a/DynmapCore/src/main/resources/models_1.txt b/DynmapCore/src/main/resources/models_1.txt index 978ae4dc..770d7d94 100644 --- a/DynmapCore/src/main/resources/models_1.txt +++ b/DynmapCore/src/main/resources/models_1.txt @@ -804,27 +804,9 @@ layer:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ---------------- # Lily pad patchblock:id=lily_pad,patch0=HorizY001ZTop -# Water (1 down) -# Lava (1 down) -boxblock:id=water,id=lava,data=1,ymax=0.875 -# Water (2 down) -# Lava (2 down) -boxblock:id=water,id=lava,data=2,ymax=0.75 -# Water (3 down) -# Lava (3 down) -boxblock:id=water,id=lava,data=3,ymax=0.625 -# Water (4 down) -# Lava (4 down) -boxblock:id=water,id=lava,data=4,ymax=0.5 -# Water (5 down) -# Lava (5 down) -boxblock:id=water,id=lava,data=5,ymax=0.375 -# Water (6 down) -# Lava (6 down) -boxblock:id=water,id=lava,data=6,ymax=0.25 -# Water (7 down) -# Lava (7 down) -boxblock:id=water,id=lava,data=7,ymax=0.125 +# Water +customblock:id=water,id=lava,class=org.dynmap.hdmap.renderer.FluidStateRenderer + # Enchantment Table boxblock:id=enchanting_table,ymax=0.75 diff --git a/DynmapCore/src/main/resources/texture_0.txt b/DynmapCore/src/main/resources/texture_0.txt index f6d69824..9f7f34bf 100644 --- a/DynmapCore/src/main/resources/texture_0.txt +++ b/DynmapCore/src/main/resources/texture_0.txt @@ -390,14 +390,11 @@ block:id=sapling,data=3,data=11,patch0-1=0:sapling_jungle,transparency=TRANSPARE # Bedrock block:id=bedrock,allfaces=0:bedrock,stdrot=true # Water -block:id=flowing_water,allfaces=12000:water_flow,stdrot=true,transparency=SEMITRANSPARENT # Stationary water -block:id=water,data=0,data=8,data=9,data=10,data=11,data=12,data=13,data=14,data=15,topbottom=12000:water_still,allsides=12000:water_flow,stdrot=true,transparency=SEMITRANSPARENT -block:id=water,data=1,data=2,data=3,data=4,data=5,data=6,data=7,allfaces=12000:water_flow,stdrot=true,transparency=SEMITRANSPARENT +block:id=water,id=flowing_water,patch0=12000:water_still,patch1=12000:water_flow,transparency=SEMITRANSPARENT # Lava -block:id=flowing_lava,allfaces=0:lava_flow,stdrot=true,transparency=SEMITRANSPARENT # Stationary Lava -block:id=lava,allfaces=0:lava_still,stdrot=true,transparency=SEMITRANSPARENT +block:id=lava,id=flowing_lava,patch0=0:lava_still,patch1=0:lava_flow,transparency=SEMITRANSPARENT # Sand block:id=sand,allfaces=0:sand,stdrot=true [1.7.0-]block:id=sand,data=1,allfaces=0:red_sand,stdrot=true diff --git a/DynmapCore/src/main/resources/texture_1.txt b/DynmapCore/src/main/resources/texture_1.txt index de26d1e6..dd4ad715 100644 --- a/DynmapCore/src/main/resources/texture_1.txt +++ b/DynmapCore/src/main/resources/texture_1.txt @@ -133,10 +133,7 @@ texture:id=birch_sapling texture:id=jungle_sapling texture:id=bedrock texture:id=water_still,material=WATER -#TODO: fix when I figure out 1.13 biome shading logic -#texturefile:id=water_still,filename=assets/minecraft/textures/blocks/water_still.png,xcount=1,ycount=1 texture:id=water_flow,material=WATER -#texturefile:id=water_flow,filename=assets/minecraft/textures/blocks/water_flow.png,xcount=1,ycount=1 texture:id=lava_still texture:id=lava_flow texture:id=sand @@ -599,9 +596,11 @@ block:id=dark_oak_sapling,data=1,patch0-1=0:dark_oak_sapling,transparency=TRANSP # Bedrock block:id=bedrock,allfaces=0:bedrock,stdrot=true # Water -block:id=water,topbottom=12000:water_still,allsides=12000:water_flow,stdrot=true,transparency=SEMITRANSPARENT +#block:id=water,topbottom=12000:water_still,allsides=12000:water_flow,stdrot=true,transparency=SEMITRANSPARENT +block:id=water,patch0=12000:water_still,patch1=12000:water_flow,transparency=SEMITRANSPARENT # Lava -block:id=lava,allfaces=0:lava_still,stdrot=true,transparency=SEMITRANSPARENT +#block:id=lava,allfaces=0:lava_still,stdrot=true,transparency=SEMITRANSPARENT +block:id=lava,patch0=0:lava_still,patch1=0:lava_flow,transparency=SEMITRANSPARENT # Sand block:id=sand,allfaces=0:sand,stdrot=true # Red Sand diff --git a/DynmapCoreAPI/src/main/java/org/dynmap/renderer/DynmapBlockState.java b/DynmapCoreAPI/src/main/java/org/dynmap/renderer/DynmapBlockState.java index a1029a7d..6f947a36 100644 --- a/DynmapCoreAPI/src/main/java/org/dynmap/renderer/DynmapBlockState.java +++ b/DynmapCoreAPI/src/main/java/org/dynmap/renderer/DynmapBlockState.java @@ -76,6 +76,8 @@ public class DynmapBlockState { // Well known base blocks - air public static final DynmapBlockState AIR = new DynmapBlockState(null, 0, AIR_BLOCK, ""); + private static DynmapBlockState still_water = null; + /** * Constructor for block state * @param base - base block state (null if first/only state for block) @@ -126,6 +128,10 @@ public class DynmapBlockState { matchflags |= (blockName.equals(SNOW_BLOCK) || blockName.equals(SNOW_LAYER_BLOCK)) ? MATCH_SNOW : 0; matchflags |= blockName.equals(GRASS_BLOCK) ? MATCH_GRASS : 0; matchflags |= log_blocks.contains(blockName) ? MATCH_LOG : 0; + // If water block, set singleton + if (this.blockName.equals(WATER_BLOCK) && (this == this.baseState)) { + still_water = this; + } } /** * Get state for same base block with given index @@ -310,6 +316,15 @@ public class DynmapBlockState { public boolean matchingBaseState(DynmapBlockState blk) { return this.baseState == blk.baseState; } + /** + * Get liquid state (null if not waterlogged or otherwise immmersed) + */ + public DynmapBlockState getLiquidState() { + if (isWaterlogged()) { + return still_water; + } + return null; + } /** * To printable string */