diff --git a/src/main/java/mod/chiselsandbits/chiseledblock/data/VoxelBlob.java b/src/main/java/mod/chiselsandbits/chiseledblock/data/VoxelBlob.java index 674a1294..43796a5b 100644 --- a/src/main/java/mod/chiselsandbits/chiseledblock/data/VoxelBlob.java +++ b/src/main/java/mod/chiselsandbits/chiseledblock/data/VoxelBlob.java @@ -7,7 +7,10 @@ import java.nio.ShortBuffer; import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; +import java.util.EnumMap; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -17,9 +20,20 @@ import java.util.zip.GZIPOutputStream; import java.util.zip.InflaterInputStream; -import gnu.trove.TCollections; -import gnu.trove.map.TIntObjectMap; -import gnu.trove.map.hash.TIntObjectHashMap; +import net.minecraft.block.Block; +import net.minecraft.block.BlockLog.EnumAxis; +import net.minecraft.block.state.IBlockState; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumFacing.Axis; +import net.minecraft.util.EnumFacing.AxisDirection; +import net.minecraft.util.math.BlockPos; + +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + import io.netty.buffer.Unpooled; import mod.chiselsandbits.chiseledblock.BlockBitInfo; import mod.chiselsandbits.chiseledblock.serialization.BitStream; @@ -35,45 +49,79 @@ import mod.chiselsandbits.helpers.LocalStrings; import mod.chiselsandbits.helpers.ModUtil; import mod.chiselsandbits.items.ItemChiseledBit; -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.BlockRenderLayer; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumFacing.Axis; -import net.minecraft.util.EnumFacing.AxisDirection; -import net.minecraft.util.math.BlockPos; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; public final class VoxelBlob implements IVoxelSrc { - // generated filtering data as needed. - private static final TIntObjectMap fluidFilterState = TCollections.synchronizedMap( new TIntObjectHashMap() ); - private static final TIntObjectMap layerFilterStateSolid = TCollections.synchronizedMap( new TIntObjectHashMap() ); - private static final TIntObjectMap layerFilterStateCutout = TCollections.synchronizedMap( new TIntObjectHashMap() ); - private static final TIntObjectMap layerFilterStateCutoutMipped = TCollections.synchronizedMap( new TIntObjectHashMap() ); - private static final TIntObjectMap layerFilterStateTransparent = TCollections.synchronizedMap( new TIntObjectHashMap() ); + private static final BitSet fluidFilterState; + private static final Map layerFilters; + + static { + fluidFilterState = new BitSet(256); + + if (FMLCommonHandler.instance().getSide() == Side.CLIENT) { + layerFilters = new EnumMap(BlockRenderLayer.class); + } else { + layerFilters = null; + } - static - { clearCache(); } - public static void clearCache() - { + public static synchronized void clearCache() { fluidFilterState.clear(); - layerFilterStateSolid.clear(); - layerFilterStateCutout.clear(); - layerFilterStateCutoutMipped.clear(); - layerFilterStateTransparent.clear(); - fluidFilterState.put( 0, false ); - layerFilterStateSolid.put( 0, false ); - layerFilterStateCutout.put( 0, false ); - layerFilterStateCutoutMipped.put( 0, false ); - layerFilterStateTransparent.put( 0, false ); + for (Iterator it = Block.REGISTRY.iterator(); it.hasNext(); ) { + Block block = it.next(); + int blockId = Block.REGISTRY.getIDForObject(block); + + if (BlockBitInfo.getFluidFromBlock(block) != null) { + fluidFilterState.set(blockId); + } + } + + if (FMLCommonHandler.instance().getSide() == Side.CLIENT) { + updateCacheClient(); + } + } + + private static void updateCacheClient() { + layerFilters.clear(); + + Map layerFilters = VoxelBlob.layerFilters; + BlockRenderLayer[] layers = BlockRenderLayer.values(); + + for (BlockRenderLayer layer : layers) { + layerFilters.put(layer, new BitSet(4096)); + } + + for (Iterator it = Block.REGISTRY.iterator(); it.hasNext(); ) { + Block block = it.next(); + int blockId = Block.REGISTRY.getIDForObject(block); + int validMetas = 0; + + for (IBlockState state : block.getBlockState().getValidStates()) { + int meta = block.getMetaFromState(state); + if (meta == -1) continue; + + validMetas |= 1 << meta; + } + + while (validMetas != 0) { + int meta = Integer.numberOfTrailingZeros(validMetas); + validMetas &= ~(1 << meta); + + int id = blockId | meta << 12; + IBlockState state = Block.getStateById(id); + if (state == null) throw new IllegalStateException(); // reverse mapping is broken + + for (BlockRenderLayer layer : layers) { + if (block.canRenderInLayer(state, layer)) { + layerFilters.get(layer).set(id); + } + } + } + } } static final int SHORT_BYTES = Short.SIZE / 8; @@ -797,19 +845,11 @@ public boolean filterFluids( for ( int x = 0; x < array_size; x++ ) { final int ref = values[x]; + if (ref == 0) continue; - Boolean state = fluidFilterState.get( ref ); - if ( state == null ) - { - fluidFilterState.put( ref, state = isFluid( ref ) ); - } - - if ( state != wantsFluids ) - { + if (fluidFilterState.get(ref & 0xfff) != wantsFluids) { values[x] = 0; - } - else if ( ref != 0 ) - { + } else { hasValues = true; } } @@ -820,25 +860,17 @@ else if ( ref != 0 ) public boolean filter( final BlockRenderLayer layer ) { - final TIntObjectMap layerFilterState = getStateLayer( layer ); + BitSet layerFilterState = layerFilters.get(layer); boolean hasValues = false; for ( int x = 0; x < array_size; x++ ) { final int ref = values[x]; + if (ref == 0) continue; - Boolean state = layerFilterState.get( ref ); - if ( state == null ) - { - layerFilterState.put( ref, state = inLayer( layer, ref ) ); - } - - if ( state == false ) - { + if (!layerFilterState.get(ref)) { values[x] = 0; - } - else - { + } else { hasValues = true; } } @@ -846,38 +878,6 @@ public boolean filter( return hasValues; } - private TIntObjectMap getStateLayer( - final BlockRenderLayer layer ) - { - switch ( layer ) - { - case CUTOUT: - return layerFilterStateCutout; - case CUTOUT_MIPPED: - return layerFilterStateCutoutMipped; - case SOLID: - return layerFilterStateSolid; - case TRANSLUCENT: - return layerFilterStateTransparent; - } - throw new RuntimeException( "Invalid Layer" ); - } - - private Boolean isFluid( - final int ref ) - { - final IBlockState state = Block.getStateById( ref ); - return BlockBitInfo.getFluidFromBlock( state.getBlock() ) != null; - } - - private Boolean inLayer( - final BlockRenderLayer layer, - final int ref ) - { - final IBlockState state = Block.getStateById( ref ); - return state.getBlock().canRenderInLayer( state, layer ); - } - public static int VERSION_COMPACT = 0; public static int VERSION_CROSSWORLD_LEGACY = 1; // stored meta. public static int VERSION_CROSSWORLD = 2; diff --git a/src/main/java/mod/chiselsandbits/client/culling/MCCullTest.java b/src/main/java/mod/chiselsandbits/client/culling/MCCullTest.java index a6111359..af9d81f2 100644 --- a/src/main/java/mod/chiselsandbits/client/culling/MCCullTest.java +++ b/src/main/java/mod/chiselsandbits/client/culling/MCCullTest.java @@ -12,7 +12,7 @@ /** * Determine Culling using Block's Native Check. - * + * * hardcode vanilla stained glass because that looks horrible. */ public class MCCullTest implements ICullTest, IBlockAccess @@ -21,6 +21,7 @@ public class MCCullTest implements ICullTest, IBlockAccess private IBlockState a; private IBlockState b; + @SuppressWarnings("deprecation") @Override public boolean isVisible( final int mySpot, @@ -31,8 +32,10 @@ public boolean isVisible( return false; } - a = net.minecraft.block.Block.getStateById( mySpot ); - b = net.minecraft.block.Block.getStateById( secondSpot ); + a = net.minecraft.block.Block.BLOCK_STATE_IDS.getByValue( mySpot ); + if (a == null) a = Blocks.AIR.getDefaultState(); + b = net.minecraft.block.Block.BLOCK_STATE_IDS.getByValue( secondSpot ); + if (b == null) b = Blocks.AIR.getDefaultState(); if ( a.getBlock() == Blocks.STAINED_GLASS && a.getBlock() == b.getBlock() ) { diff --git a/src/main/java/mod/chiselsandbits/render/chiseledblock/ChiseledBlockBaked.java b/src/main/java/mod/chiselsandbits/render/chiseledblock/ChiseledBlockBaked.java index 8f5d274c..30f6d293 100644 --- a/src/main/java/mod/chiselsandbits/render/chiseledblock/ChiseledBlockBaked.java +++ b/src/main/java/mod/chiselsandbits/render/chiseledblock/ChiseledBlockBaked.java @@ -5,17 +5,6 @@ import java.util.Collections; import java.util.List; -import org.lwjgl.util.vector.Vector3f; - -import mod.chiselsandbits.chiseledblock.data.VoxelBlob; -import mod.chiselsandbits.chiseledblock.data.VoxelBlob.VisibleFace; -import mod.chiselsandbits.chiseledblock.data.VoxelBlobStateReference; -import mod.chiselsandbits.client.culling.ICullTest; -import mod.chiselsandbits.core.ChiselsAndBits; -import mod.chiselsandbits.core.ClientSide; -import mod.chiselsandbits.render.BaseBakedBlockModel; -import mod.chiselsandbits.render.helpers.ModelQuadLayer; -import mod.chiselsandbits.render.helpers.ModelUtil; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; @@ -32,6 +21,17 @@ import net.minecraft.util.EnumFacing; import net.minecraft.util.math.Vec3i; +import mod.chiselsandbits.chiseledblock.data.VoxelBlob; +import mod.chiselsandbits.chiseledblock.data.VoxelBlob.VisibleFace; +import mod.chiselsandbits.chiseledblock.data.VoxelBlobStateReference; +import mod.chiselsandbits.client.culling.ICullTest; +import mod.chiselsandbits.core.ChiselsAndBits; +import mod.chiselsandbits.core.ClientSide; +import mod.chiselsandbits.render.BaseBakedBlockModel; +import mod.chiselsandbits.render.helpers.ModelQuadLayer; +import mod.chiselsandbits.render.helpers.ModelUtil; +import org.lwjgl.util.vector.Vector3f; + public class ChiseledBlockBaked extends BaseBakedBlockModel { public static final float PIXELS_PER_BLOCK = 16.0f; @@ -270,8 +270,8 @@ private void generateFaces( // keep integers up until the last moment... ( note I tested // snapping the floats after this stage, it made no // difference. ) - offsetVec( to, region.max, myFace, 1 ); - offsetVec( from, region.min, myFace, -1 ); + offsetVec( to, region.getMaxX(), region.getMaxY(), region.getMaxZ(), myFace, 1 ); + offsetVec( from, region.getMinX(), region.getMinY(), region.getMinZ(), myFace, -1 ); final ModelQuadLayer[] mpc = ModelUtil.getCachedFace( region.blockStateID, weight, myFace, myLayer.layer ); for ( final ModelQuadLayer pc : mpc ) @@ -582,9 +582,13 @@ private FaceRegion getRegion( if ( visFace.visibleFace ) { final Vec3i off = myFace.getDirectionVec(); - final Vec3i center = new Vec3i( x * 2 + 1 + off.getX(), y * 2 + 1 + off.getY(), z * 2 + 1 + off.getZ() ); - return new FaceRegion( myFace, center, visFace.state, visFace.isEdge ); + return new FaceRegion( myFace, + x * 2 + 1 + off.getX(), + y * 2 + 1 + off.getY(), + z * 2 + 1 + off.getZ(), + visFace.state, + visFace.isEdge ); } return null; @@ -695,7 +699,7 @@ float v( static private void offsetVec( final int[] result, - final Vec3i to, + final int toX, final int toY, final int toZ, final EnumFacing f, final int d ) { @@ -710,37 +714,37 @@ static private void offsetVec( switch ( f ) { - case DOWN: - leftX = 1; - upZ = 1; - break; - case EAST: - leftZ = 1; - upY = 1; - break; - case NORTH: - leftX = 1; - upY = 1; - break; - case SOUTH: - leftX = 1; - upY = 1; - break; - case UP: - leftX = 1; - upZ = 1; - break; - case WEST: - leftZ = 1; - upY = 1; - break; - default: - break; + case DOWN: + leftX = 1; + upZ = 1; + break; + case EAST: + leftZ = 1; + upY = 1; + break; + case NORTH: + leftX = 1; + upY = 1; + break; + case SOUTH: + leftX = 1; + upY = 1; + break; + case UP: + leftX = 1; + upZ = 1; + break; + case WEST: + leftZ = 1; + upY = 1; + break; + default: + break; } - result[0] = ( to.getX() + leftX * d + upX * d ) / 2; - result[1] = ( to.getY() + leftY * d + upY * d ) / 2; - result[2] = ( to.getZ() + leftZ * d + upZ * d ) / 2; + result[0] = ( toX + leftX * d + upX * d ) / 2; + result[1] = ( toY + leftY * d + upY * d ) / 2; + result[2] = ( toZ + leftZ * d + upZ * d ) / 2; } @Override diff --git a/src/main/java/mod/chiselsandbits/render/chiseledblock/FaceRegion.java b/src/main/java/mod/chiselsandbits/render/chiseledblock/FaceRegion.java index 7f753d3b..8e6be50e 100644 --- a/src/main/java/mod/chiselsandbits/render/chiseledblock/FaceRegion.java +++ b/src/main/java/mod/chiselsandbits/render/chiseledblock/FaceRegion.java @@ -1,28 +1,60 @@ package mod.chiselsandbits.render.chiseledblock; import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.Vec3i; class FaceRegion { public FaceRegion( final EnumFacing myFace, - final Vec3i center, + final int centerX, final int centerY, final int centerZ, final int blockStateID, final boolean isEdgeFace ) { face = myFace; this.blockStateID = blockStateID; isEdge = isEdgeFace; - min = center; - max = new Vec3i( center.getX(), center.getY(), center.getZ() ); + minX = centerX; + minY = centerY; + minZ = centerZ; + maxX = centerX; + maxY = centerY; + maxZ = centerZ; } final public EnumFacing face; final int blockStateID; final boolean isEdge; - public Vec3i min, max; + private int minX; + private int minY; + private int minZ; + private int maxX; + private int maxY; + private int maxZ; + + public int getMinX() { + return minX; + } + + public int getMinY() { + return minY; + } + + public int getMinZ() { + return minZ; + } + + public int getMaxX() { + return maxX; + } + + public int getMaxY() { + return maxY; + } + + public int getMaxZ() { + return maxZ; + } public boolean extend( final FaceRegion currentFace ) @@ -34,62 +66,74 @@ public boolean extend( switch ( face ) { - case DOWN: - case UP: + case DOWN: + case UP: + { + final boolean a = maxX == currentFace.minX - 2 && maxZ == currentFace.maxZ && minZ == currentFace.minZ; + final boolean b = minX == currentFace.maxX + 2 && maxZ == currentFace.maxZ && minZ == currentFace.minZ; + final boolean c = maxZ == currentFace.minZ - 2 && maxX == currentFace.maxX && minX == currentFace.minX; + final boolean d = minZ == currentFace.maxZ + 2 && maxX == currentFace.maxX && minX == currentFace.minX; + + if ( a || b || c || d ) { - final boolean a = max.getX() == currentFace.min.getX() - 2 && max.getZ() == currentFace.max.getZ() && min.getZ() == currentFace.min.getZ(); - final boolean b = min.getX() == currentFace.max.getX() + 2 && max.getZ() == currentFace.max.getZ() && min.getZ() == currentFace.min.getZ(); - final boolean c = max.getZ() == currentFace.min.getZ() - 2 && max.getX() == currentFace.max.getX() && min.getX() == currentFace.min.getX(); - final boolean d = min.getZ() == currentFace.max.getZ() + 2 && max.getX() == currentFace.max.getX() && min.getX() == currentFace.min.getX(); - - if ( a || b || c || d ) - { - min = new Vec3i( Math.min( currentFace.min.getX(), min.getX() ), Math.min( currentFace.min.getY(), min.getY() ), Math.min( currentFace.min.getZ(), min.getZ() ) ); - max = new Vec3i( Math.max( currentFace.max.getX(), max.getX() ), Math.max( currentFace.max.getY(), max.getY() ), Math.max( currentFace.max.getZ(), max.getZ() ) ); - return true; - } - - return false; + minX = Math.min(currentFace.minX, minX); + minY = Math.min(currentFace.minY, minY); + minZ = Math.min(currentFace.minZ, minZ); + maxX = Math.max(currentFace.maxX, maxX); + maxY = Math.max(currentFace.maxY, maxY); + maxZ = Math.max(currentFace.maxZ, maxZ); + return true; } - case WEST: - case EAST: + return false; + } + + case WEST: + case EAST: + { + final boolean a = maxY == currentFace.minY - 2 && maxZ == currentFace.maxZ && minZ == currentFace.minZ; + final boolean b = minY == currentFace.maxY + 2 && maxZ == currentFace.maxZ && minZ == currentFace.minZ; + final boolean c = maxZ == currentFace.minZ - 2 && maxY == currentFace.maxY && minY == currentFace.minY; + final boolean d = minZ == currentFace.maxZ + 2 && maxY == currentFace.maxY && minY == currentFace.minY; + + if ( a || b || c || d ) { - final boolean a = max.getY() == currentFace.min.getY() - 2 && max.getZ() == currentFace.max.getZ() && min.getZ() == currentFace.min.getZ(); - final boolean b = min.getY() == currentFace.max.getY() + 2 && max.getZ() == currentFace.max.getZ() && min.getZ() == currentFace.min.getZ(); - final boolean c = max.getZ() == currentFace.min.getZ() - 2 && max.getY() == currentFace.max.getY() && min.getY() == currentFace.min.getY(); - final boolean d = min.getZ() == currentFace.max.getZ() + 2 && max.getY() == currentFace.max.getY() && min.getY() == currentFace.min.getY(); - - if ( a || b || c || d ) - { - min = new Vec3i( Math.min( currentFace.min.getX(), min.getX() ), Math.min( currentFace.min.getY(), min.getY() ), Math.min( currentFace.min.getZ(), min.getZ() ) ); - max = new Vec3i( Math.max( currentFace.max.getX(), max.getX() ), Math.max( currentFace.max.getY(), max.getY() ), Math.max( currentFace.max.getZ(), max.getZ() ) ); - return true; - } - - return false; + minX = Math.min(currentFace.minX, minX); + minY = Math.min(currentFace.minY, minY); + minZ = Math.min(currentFace.minZ, minZ); + maxX = Math.max(currentFace.maxX, maxX); + maxY = Math.max(currentFace.maxY, maxY); + maxZ = Math.max(currentFace.maxZ, maxZ); + return true; } - case NORTH: - case SOUTH: + return false; + } + + case NORTH: + case SOUTH: + { + final boolean a = maxY == currentFace.minY - 2 && maxX == currentFace.maxX && minX == currentFace.minX; + final boolean b = minY == currentFace.maxY + 2 && maxX == currentFace.maxX && minX == currentFace.minX; + final boolean c = maxX == currentFace.minX - 2 && maxY == currentFace.maxY && minY == currentFace.minY; + final boolean d = minX == currentFace.maxX + 2 && maxY == currentFace.maxY && minY == currentFace.minY; + + if ( a || b || c || d ) { - final boolean a = max.getY() == currentFace.min.getY() - 2 && max.getX() == currentFace.max.getX() && min.getX() == currentFace.min.getX(); - final boolean b = min.getY() == currentFace.max.getY() + 2 && max.getX() == currentFace.max.getX() && min.getX() == currentFace.min.getX(); - final boolean c = max.getX() == currentFace.min.getX() - 2 && max.getY() == currentFace.max.getY() && min.getY() == currentFace.min.getY(); - final boolean d = min.getX() == currentFace.max.getX() + 2 && max.getY() == currentFace.max.getY() && min.getY() == currentFace.min.getY(); - - if ( a || b || c || d ) - { - min = new Vec3i( Math.min( currentFace.min.getX(), min.getX() ), Math.min( currentFace.min.getY(), min.getY() ), Math.min( currentFace.min.getZ(), min.getZ() ) ); - max = new Vec3i( Math.max( currentFace.max.getX(), max.getX() ), Math.max( currentFace.max.getY(), max.getY() ), Math.max( currentFace.max.getZ(), max.getZ() ) ); - return true; - } - - return false; + minX = Math.min(currentFace.minX, minX); + minY = Math.min(currentFace.minY, minY); + minZ = Math.min(currentFace.minZ, minZ); + maxX = Math.max(currentFace.maxX, maxX); + maxY = Math.max(currentFace.maxY, maxY); + maxZ = Math.max(currentFace.maxZ, maxZ); + return true; } - default: - return false; + return false; + } + + default: + return false; } } } \ No newline at end of file