pipes: improve render performance
This commit is contained in:
parent
bdf93e12ba
commit
36da365ccb
3 changed files with 85 additions and 145 deletions
|
@ -81,7 +81,7 @@ public class BlockGenericPipe extends BlockContainer {
|
|||
private static final ForgeDirection[] DIR_VALUES = ForgeDirection.values();
|
||||
private static Random rand = new Random();
|
||||
private boolean skippedFirstIconRegister;
|
||||
private boolean[] renderSide = new boolean[6];
|
||||
private int renderMask = 0;
|
||||
|
||||
/* Defined subprograms ************************************************* */
|
||||
public BlockGenericPipe(int i) {
|
||||
|
@ -114,34 +114,26 @@ public class BlockGenericPipe extends BlockContainer {
|
|||
return false;
|
||||
}
|
||||
|
||||
public void setRenderAxis(char axis) {
|
||||
Arrays.fill(renderSide, false);
|
||||
if (axis == 'x') {
|
||||
renderSide[4] = true;
|
||||
renderSide[5] = true;
|
||||
}
|
||||
if (axis == 'y') {
|
||||
renderSide[0] = true;
|
||||
renderSide[1] = true;
|
||||
}
|
||||
if (axis == 'z') {
|
||||
renderSide[2] = true;
|
||||
renderSide[3] = true;
|
||||
}
|
||||
public void setRenderMask(int mask) {
|
||||
renderMask = mask;
|
||||
}
|
||||
|
||||
public final void setRenderAllSides() {
|
||||
Arrays.fill(renderSide, true);
|
||||
renderMask = 0x3f;
|
||||
}
|
||||
|
||||
public void setRenderSide(ForgeDirection side, boolean render) {
|
||||
renderSide[side.ordinal()] = render;
|
||||
if (render) {
|
||||
renderMask |= 1 << side.ordinal();
|
||||
} else {
|
||||
renderMask &= ~(1 << side.ordinal());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean shouldSideBeRendered(IBlockAccess blockAccess, int x, int y, int z, int side) {
|
||||
return renderSide[side];
|
||||
return (renderMask & (1 << side)) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1100,27 +1092,27 @@ public class BlockGenericPipe extends BlockContainer {
|
|||
double pz = z + rand.nextDouble() * (block.getBlockBoundsMaxZ() - block.getBlockBoundsMinZ() - (b * 2.0F)) + b + block.getBlockBoundsMinZ();
|
||||
|
||||
if (sideHit == 0) {
|
||||
py = (double) y + block.getBlockBoundsMinY() - (double) b;
|
||||
py = y + block.getBlockBoundsMinY() - b;
|
||||
}
|
||||
|
||||
if (sideHit == 1) {
|
||||
py = (double) y + block.getBlockBoundsMaxY() + (double) b;
|
||||
py = y + block.getBlockBoundsMaxY() + b;
|
||||
}
|
||||
|
||||
if (sideHit == 2) {
|
||||
pz = (double) z + block.getBlockBoundsMinZ() - (double) b;
|
||||
pz = z + block.getBlockBoundsMinZ() - b;
|
||||
}
|
||||
|
||||
if (sideHit == 3) {
|
||||
pz = (double) z + block.getBlockBoundsMaxZ() + (double) b;
|
||||
pz = z + block.getBlockBoundsMaxZ() + b;
|
||||
}
|
||||
|
||||
if (sideHit == 4) {
|
||||
px = (double) x + block.getBlockBoundsMinX() - (double) b;
|
||||
px = x + block.getBlockBoundsMinX() - b;
|
||||
}
|
||||
|
||||
if (sideHit == 5) {
|
||||
px = (double) x + block.getBlockBoundsMaxX() + (double) b;
|
||||
px = x + block.getBlockBoundsMaxX() + b;
|
||||
}
|
||||
|
||||
EntityDiggingFX fx = new EntityDiggingFX(worldObj, px, py, pz, 0.0D, 0.0D, 0.0D, block, sideHit, worldObj.getBlockMetadata(x, y, z));
|
||||
|
@ -1156,9 +1148,9 @@ public class BlockGenericPipe extends BlockContainer {
|
|||
for (int i = 0; i < its; ++i) {
|
||||
for (int j = 0; j < its; ++j) {
|
||||
for (int k = 0; k < its; ++k) {
|
||||
double px = x + (i + 0.5D) / (double) its;
|
||||
double py = y + (j + 0.5D) / (double) its;
|
||||
double pz = z + (k + 0.5D) / (double) its;
|
||||
double px = x + (i + 0.5D) / its;
|
||||
double py = y + (j + 0.5D) / its;
|
||||
double pz = z + (k + 0.5D) / its;
|
||||
int random = rand.nextInt(6);
|
||||
EntityDiggingFX fx = new EntityDiggingFX(worldObj, px, py, pz, px - x - 0.5D, py - y - 0.5D, pz - z - 0.5D, BuildCraftTransport.genericPipeBlock, random, meta);
|
||||
fx.setParticleIcon(icon);
|
||||
|
|
|
@ -7,142 +7,82 @@ import buildcraft.transport.BlockGenericPipe;
|
|||
import buildcraft.transport.IPipeRenderState;
|
||||
import buildcraft.transport.PipeIconProvider;
|
||||
import buildcraft.transport.PipeRenderState;
|
||||
import buildcraft.transport.TransportConstants;
|
||||
import buildcraft.transport.TransportProxy;
|
||||
import buildcraft.core.utils.MatrixTranformations;
|
||||
|
||||
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.renderer.RenderBlocks;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Icon;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
import net.minecraftforge.common.ForgeDirection;
|
||||
|
||||
public class PipeRendererWorld implements ISimpleBlockRenderingHandler {
|
||||
|
||||
private void renderAllFaceExeptAxe(RenderBlocks renderblocks, BlockGenericPipe block, Icon icon, int x, int y, int z, char axe) {
|
||||
float minX = (float) renderblocks.renderMinX;
|
||||
float minY = (float) renderblocks.renderMinY;
|
||||
float minZ = (float) renderblocks.renderMinZ;
|
||||
float maxX = (float) renderblocks.renderMaxX;
|
||||
float maxY = (float) renderblocks.renderMaxY;
|
||||
float maxZ = (float) renderblocks.renderMaxZ;
|
||||
if (axe != 'x') {
|
||||
renderTwoWayXFace(renderblocks, block, icon, x, y, z, minY, minZ, maxY, maxZ, minX);
|
||||
renderTwoWayXFace(renderblocks, block, icon, x, y, z, minY, minZ, maxY, maxZ, maxX);
|
||||
}
|
||||
if (axe != 'y') {
|
||||
renderTwoWayYFace(renderblocks, block, icon, x, y, z, minX, minZ, maxX, maxZ, minY);
|
||||
renderTwoWayYFace(renderblocks, block, icon, x, y, z, minX, minZ, maxX, maxZ, maxY);
|
||||
}
|
||||
if (axe != 'z') {
|
||||
renderTwoWayZFace(renderblocks, block, icon, x, y, z, minX, minY, maxX, maxY, minZ);
|
||||
renderTwoWayZFace(renderblocks, block, icon, x, y, z, minX, minY, maxX, maxY, maxZ);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderTwoWayXFace(RenderBlocks renderblocks, BlockGenericPipe block, Icon icon, int xCoord, int yCoord, int zCoord, float minY, float minZ, float maxY, float maxZ, float x) {
|
||||
renderblocks.setRenderBounds(x, minY, minZ, x, maxY, maxZ);
|
||||
block.setRenderAxis('x');
|
||||
renderblocks.renderStandardBlock(block, xCoord, yCoord, zCoord);
|
||||
block.setRenderAxis('a');
|
||||
}
|
||||
|
||||
private void renderTwoWayYFace(RenderBlocks renderblocks, BlockGenericPipe block, Icon icon, int xCoord, int yCoord, int zCoord, float minX, float minZ, float maxX, float maxZ, float y) {
|
||||
renderblocks.setRenderBounds(minX, y, minZ, maxX, y, maxZ);
|
||||
block.setRenderAxis('y');
|
||||
renderblocks.renderStandardBlock(block, xCoord, yCoord, zCoord);
|
||||
block.setRenderAxis('a');
|
||||
}
|
||||
|
||||
private void renderTwoWayZFace(RenderBlocks renderblocks, BlockGenericPipe block, Icon icon, int xCoord, int yCoord, int zCoord, float minX, float minY, float maxX, float maxY, float z) {
|
||||
renderblocks.setRenderBounds(minX, minY, z, maxX, maxY, z);
|
||||
block.setRenderAxis('z');
|
||||
renderblocks.renderStandardBlock(block, xCoord, yCoord, zCoord);
|
||||
block.setRenderAxis('a');
|
||||
}
|
||||
|
||||
public void renderPipe(RenderBlocks renderblocks, IBlockAccess iblockaccess, BlockGenericPipe block, IPipeRenderState renderState, int x, int y, int z) {
|
||||
|
||||
float minSize = CoreConstants.PIPE_MIN_POS;
|
||||
float maxSize = CoreConstants.PIPE_MAX_POS;
|
||||
|
||||
PipeRenderState state = renderState.getRenderState();
|
||||
IIconProvider icons = renderState.getPipeIcons();
|
||||
if (icons == null)
|
||||
return;
|
||||
|
||||
boolean west = false;
|
||||
boolean east = false;
|
||||
boolean down = false;
|
||||
boolean up = false;
|
||||
boolean north = false;
|
||||
boolean south = false;
|
||||
int connectivity = state.pipeConnectionMatrix.getMask();
|
||||
float[] dim = new float[6];
|
||||
|
||||
if (state.pipeConnectionMatrix.isConnected(ForgeDirection.WEST)) {
|
||||
state.currentTexture = icons.getIcon(state.textureMatrix.getTextureIndex(ForgeDirection.WEST));
|
||||
renderblocks.setRenderBounds(0.0F, minSize, minSize, minSize, maxSize, maxSize);
|
||||
renderAllFaceExeptAxe(renderblocks, block, state.currentTexture, x, y, z, 'x');
|
||||
west = true;
|
||||
// render the unconnected pipe faces of the center block (if any)
|
||||
|
||||
if (connectivity != 0x3f) { // note: 0x3f = 0x111111 = all sides
|
||||
resetToCenterDimensions(dim);
|
||||
|
||||
state.currentTexture = icons.getIcon(state.textureMatrix.getTextureIndex(ForgeDirection.UNKNOWN));
|
||||
renderTwoWayBlock(renderblocks, block, x, y, z, dim, connectivity ^ 0x3f);
|
||||
}
|
||||
|
||||
if (state.pipeConnectionMatrix.isConnected(ForgeDirection.EAST)) {
|
||||
state.currentTexture = icons.getIcon(state.textureMatrix.getTextureIndex(ForgeDirection.EAST));
|
||||
renderblocks.setRenderBounds(maxSize, minSize, minSize, 1.0F, maxSize, maxSize);
|
||||
renderAllFaceExeptAxe(renderblocks, block, state.currentTexture, x, y, z, 'x');
|
||||
east = true;
|
||||
}
|
||||
// render the connecting pipe faces
|
||||
|
||||
if (state.pipeConnectionMatrix.isConnected(ForgeDirection.DOWN)) {
|
||||
state.currentTexture = icons.getIcon(state.textureMatrix.getTextureIndex(ForgeDirection.DOWN));
|
||||
renderblocks.setRenderBounds(minSize, 0.0F, minSize, maxSize, minSize, maxSize);
|
||||
renderAllFaceExeptAxe(renderblocks, block, state.currentTexture, x, y, z, 'y');
|
||||
down = true;
|
||||
}
|
||||
for (int dir = 0; dir < 6; dir++) {
|
||||
int mask = 1 << dir;
|
||||
if ((connectivity & mask) == 0) continue; // no connection towards dir
|
||||
|
||||
if (state.pipeConnectionMatrix.isConnected(ForgeDirection.UP)) {
|
||||
state.currentTexture = icons.getIcon(state.textureMatrix.getTextureIndex(ForgeDirection.UP));
|
||||
renderblocks.setRenderBounds(minSize, maxSize, minSize, maxSize, 1.0F, maxSize);
|
||||
renderAllFaceExeptAxe(renderblocks, block, state.currentTexture, x, y, z, 'y');
|
||||
up = true;
|
||||
}
|
||||
// center piece offsets
|
||||
resetToCenterDimensions(dim);
|
||||
|
||||
if (state.pipeConnectionMatrix.isConnected(ForgeDirection.NORTH)) {
|
||||
state.currentTexture = icons.getIcon(state.textureMatrix.getTextureIndex(ForgeDirection.NORTH));
|
||||
renderblocks.setRenderBounds(minSize, minSize, 0.0F, maxSize, maxSize, minSize);
|
||||
renderAllFaceExeptAxe(renderblocks, block, state.currentTexture, x, y, z, 'z');
|
||||
north = true;
|
||||
}
|
||||
// extend block towards dir as it's connected to there
|
||||
dim[dir / 2] = dir % 2 == 0 ? 0 : CoreConstants.PIPE_MAX_POS;
|
||||
dim[dir / 2 + 3] = dir % 2 == 0 ? CoreConstants.PIPE_MIN_POS : 1;
|
||||
|
||||
if (state.pipeConnectionMatrix.isConnected(ForgeDirection.SOUTH)) {
|
||||
state.currentTexture = icons.getIcon(state.textureMatrix.getTextureIndex(ForgeDirection.SOUTH));
|
||||
renderblocks.setRenderBounds(minSize, minSize, maxSize, maxSize, maxSize, 1.0F);
|
||||
renderAllFaceExeptAxe(renderblocks, block, state.currentTexture, x, y, z, 'z');
|
||||
south = true;
|
||||
}
|
||||
// the mask points to all faces perpendicular to dir, i.e. dirs 0+1 -> mask 111100, 1+2 -> 110011, 3+5 -> 001111
|
||||
int renderMask = (3 << (dir / 2 * 2)) ^ 0x3f;
|
||||
|
||||
state.currentTexture = icons.getIcon(state.textureMatrix.getTextureIndex(ForgeDirection.UNKNOWN));
|
||||
renderblocks.setRenderBounds(minSize, minSize, minSize, maxSize, maxSize, maxSize);
|
||||
if (!west)
|
||||
renderTwoWayXFace(renderblocks, block, state.currentTexture, x, y, z, minSize, minSize, maxSize, maxSize, minSize);
|
||||
if (!east)
|
||||
renderTwoWayXFace(renderblocks, block, state.currentTexture, x, y, z, minSize, minSize, maxSize, maxSize, maxSize);
|
||||
if (!down)
|
||||
renderTwoWayYFace(renderblocks, block, state.currentTexture, x, y, z, minSize, minSize, maxSize, maxSize, minSize);
|
||||
if (!up)
|
||||
renderTwoWayYFace(renderblocks, block, state.currentTexture, x, y, z, minSize, minSize, maxSize, maxSize, maxSize);
|
||||
if (!north)
|
||||
renderTwoWayZFace(renderblocks, block, state.currentTexture, x, y, z, minSize, minSize, maxSize, maxSize, minSize);
|
||||
if (!south)
|
||||
renderTwoWayZFace(renderblocks, block, state.currentTexture, x, y, z, minSize, minSize, maxSize, maxSize, maxSize);
|
||||
// render sub block
|
||||
state.currentTexture = icons.getIcon(state.textureMatrix.getTextureIndex(ForgeDirection.VALID_DIRECTIONS[dir]));
|
||||
|
||||
renderTwoWayBlock(renderblocks, block, x, y, z, dim, renderMask);
|
||||
}
|
||||
|
||||
renderblocks.setRenderBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
|
||||
|
||||
pipeFacadeRenderer(renderblocks, block, state, x, y, z);
|
||||
pipePlugRenderer(renderblocks, block, state, x, y, z);
|
||||
}
|
||||
|
||||
private void resetToCenterDimensions(float[] dim) {
|
||||
for (int i = 0; i < 3; i++) dim[i] = CoreConstants.PIPE_MIN_POS;
|
||||
for (int i = 3; i < 6; i++) dim[i] = CoreConstants.PIPE_MAX_POS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a block with normal and inverted vertex order so back face culling doesn't have any effect.
|
||||
*/
|
||||
private void renderTwoWayBlock(RenderBlocks renderblocks, BlockGenericPipe block, int x, int y, int z, float[] dim, int mask) {
|
||||
assert mask != 0;
|
||||
|
||||
block.setRenderMask(mask);
|
||||
renderblocks.setRenderBounds(dim[2], dim[0], dim[1], dim[5], dim[3], dim[4]);
|
||||
renderblocks.renderStandardBlock(block, x, y, z);
|
||||
block.setRenderMask((mask & 0x15) << 1 | (mask & 0x2a) >> 1); // pairwise swapped mask
|
||||
renderblocks.setRenderBounds(dim[5], dim[3], dim[4], dim[2], dim[0], dim[1]);
|
||||
renderblocks.renderStandardBlock(block, x, y, z);
|
||||
}
|
||||
|
||||
private void pipeFacadeRenderer(RenderBlocks renderblocks, BlockGenericPipe block, PipeRenderState state, int x, int y, int z) {
|
||||
|
|
|
@ -3,26 +3,34 @@ package buildcraft.transport.utils;
|
|||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.BitSet;
|
||||
import net.minecraftforge.common.ForgeDirection;
|
||||
|
||||
public class ConnectionMatrix {
|
||||
|
||||
private BitSet _connected = new BitSet(ForgeDirection.VALID_DIRECTIONS.length);
|
||||
private final BitSetCodec _bitSetCodec = new BitSetCodec();
|
||||
private int mask = 0;
|
||||
private boolean dirty = false;
|
||||
|
||||
public boolean isConnected(ForgeDirection direction) {
|
||||
return _connected.get(direction.ordinal());
|
||||
// test if the direction.ordinal()'th bit of mask is set
|
||||
return (mask & (1 << direction.ordinal())) != 0;
|
||||
}
|
||||
|
||||
public void setConnected(ForgeDirection direction, boolean value) {
|
||||
if (_connected.get(direction.ordinal()) != value) {
|
||||
_connected.set(direction.ordinal(), value);
|
||||
if (isConnected(direction) != value) {
|
||||
// invert the direction.ordinal()'th bit of mask
|
||||
mask ^= 1 << direction.ordinal();
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a mask representing the connectivity for all sides.
|
||||
*
|
||||
* @return mask in ForgeDirection order, least significant bit = first entry
|
||||
*/
|
||||
public int getMask() {
|
||||
return mask;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return dirty;
|
||||
}
|
||||
|
@ -32,14 +40,14 @@ public class ConnectionMatrix {
|
|||
}
|
||||
|
||||
public void writeData(DataOutputStream data) throws IOException {
|
||||
data.writeByte(_bitSetCodec.encode(_connected));
|
||||
data.writeByte(mask);
|
||||
}
|
||||
|
||||
public void readData(DataInputStream data) throws IOException {
|
||||
BitSet connection = new BitSet(ForgeDirection.VALID_DIRECTIONS.length);
|
||||
_bitSetCodec.decode(data.readByte(), connection);
|
||||
if (!_connected.equals(connection)) {
|
||||
_connected = connection;
|
||||
byte newMask = data.readByte();
|
||||
|
||||
if (newMask != mask) {
|
||||
mask = newMask;
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue