pipes: improve render performance

This commit is contained in:
Player 2013-10-27 12:14:14 +01:00
parent bdf93e12ba
commit 36da365ccb
3 changed files with 85 additions and 145 deletions

View file

@ -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);

View file

@ -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) {

View file

@ -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;
}
}