package buildcraft.transport.render; import org.lwjgl.opengl.GL11; import gnu.trove.iterator.TIntIterator; import gnu.trove.set.hash.TIntHashSet; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.init.Blocks; import net.minecraft.util.IntHashMap; import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import buildcraft.core.CoreConstants; import buildcraft.core.lib.render.RenderEntityBlock; import buildcraft.core.lib.render.RenderUtils; import buildcraft.transport.Pipe; import buildcraft.transport.PipeTransportFluids; import buildcraft.transport.utils.FluidRenderData; public class PipeTransportFluidsRenderer extends PipeTransportRenderer<PipeTransportFluids> { private static final IntHashMap displayFluidLists = new IntHashMap(); private static final TIntHashSet displayFluidListsSet = new TIntHashSet(); private static final int LIQUID_STAGES = 40; private static final int[] angleY = {0, 0, 270, 90, 0, 180}; private static final int[] angleZ = {90, 270, 0, 0, 0, 0}; private class DisplayFluidList { public int[] sideHorizontal = new int[LIQUID_STAGES]; public int[] sideVertical = new int[LIQUID_STAGES]; public int[] centerHorizontal = new int[LIQUID_STAGES]; public int[] centerVertical = new int[LIQUID_STAGES]; } protected static void clear() { TIntIterator i = displayFluidListsSet.iterator(); while (i.hasNext()) { GL11.glDeleteLists(i.next(), 1); } displayFluidListsSet.clear(); displayFluidLists.clearMap(); } @Override public boolean useServerTileIfPresent() { return false; } private DisplayFluidList getDisplayFluidLists(int liquidId, int skylight, int blocklight, int flags, World world) { int finalBlockLight = Math.max(flags & 31, blocklight); int listId = (liquidId & 0x3FFFF) << 13 | (flags & 0xE0 | finalBlockLight) << 5 | (skylight & 31); if (displayFluidLists.containsItem(listId)) { return (DisplayFluidList) displayFluidLists.lookup(listId); } Fluid fluid = FluidRegistry.getFluid(liquidId); if (fluid == null) { return null; } DisplayFluidList d = new DisplayFluidList(); displayFluidLists.addKey(listId, d); displayFluidListsSet.add(listId); RenderEntityBlock.RenderInfo block = new RenderEntityBlock.RenderInfo(); if (fluid.getBlock() != null) { block.baseBlock = fluid.getBlock(); } else { block.baseBlock = Blocks.water; } block.texture = fluid.getStillIcon(); block.brightness = skylight << 16 | finalBlockLight; float size = CoreConstants.PIPE_MAX_POS - CoreConstants.PIPE_MIN_POS; // render size for (int s = 0; s < LIQUID_STAGES; ++s) { float ratio = (float) s / (float) LIQUID_STAGES; // SIDE HORIZONTAL d.sideHorizontal[s] = GLAllocation.generateDisplayLists(1); GL11.glNewList(d.sideHorizontal[s], GL11.GL_COMPILE); block.minX = 0.0F; block.minZ = CoreConstants.PIPE_MIN_POS + 0.01F; block.maxX = block.minX + size / 2F + 0.01F; block.maxZ = block.minZ + size - 0.02F; block.minY = CoreConstants.PIPE_MIN_POS + 0.01F; block.maxY = block.minY + (size - 0.02F) * ratio; RenderEntityBlock.INSTANCE.renderBlock(block); GL11.glEndList(); // SIDE VERTICAL d.sideVertical[s] = GLAllocation.generateDisplayLists(1); GL11.glNewList(d.sideVertical[s], GL11.GL_COMPILE); block.minY = CoreConstants.PIPE_MAX_POS - 0.01; block.maxY = 1; block.minX = 0.5 - (size / 2 - 0.01) * ratio; block.maxX = 0.5 + (size / 2 - 0.01) * ratio; block.minZ = 0.5 - (size / 2 - 0.01) * ratio; block.maxZ = 0.5 + (size / 2 - 0.01) * ratio; RenderEntityBlock.INSTANCE.renderBlock(block); GL11.glEndList(); // CENTER HORIZONTAL d.centerHorizontal[s] = GLAllocation.generateDisplayLists(1); GL11.glNewList(d.centerHorizontal[s], GL11.GL_COMPILE); block.minX = CoreConstants.PIPE_MIN_POS + 0.01; block.minZ = CoreConstants.PIPE_MIN_POS + 0.01; block.maxX = block.minX + size - 0.02; block.maxZ = block.minZ + size - 0.02; block.minY = CoreConstants.PIPE_MIN_POS + 0.01; block.maxY = block.minY + (size - 0.02F) * ratio; RenderEntityBlock.INSTANCE.renderBlock(block); GL11.glEndList(); // CENTER VERTICAL d.centerVertical[s] = GLAllocation.generateDisplayLists(1); GL11.glNewList(d.centerVertical[s], GL11.GL_COMPILE); block.minY = CoreConstants.PIPE_MIN_POS + 0.01; block.maxY = CoreConstants.PIPE_MAX_POS - 0.01; block.minX = 0.5 - (size / 2 - 0.02) * ratio; block.maxX = 0.5 + (size / 2 - 0.02) * ratio; block.minZ = 0.5 - (size / 2 - 0.02) * ratio; block.maxZ = 0.5 + (size / 2 - 0.02) * ratio; RenderEntityBlock.INSTANCE.renderBlock(block); GL11.glEndList(); } return d; } @Override public void render(Pipe<PipeTransportFluids> pipe, double x, double y, double z, float f) { PipeTransportFluids trans = pipe.transport; boolean needsRender = false; FluidRenderData renderData = trans.renderCache; for (int i = 0; i < 7; ++i) { if (renderData.amount[i] > 0) { needsRender = true; break; } } if (!needsRender) { return; } if (pipe.container == null) { return; } GL11.glPushMatrix(); GL11.glPushAttrib(GL11.GL_ENABLE_BIT); GL11.glEnable(GL11.GL_CULL_FACE); GL11.glDisable(GL11.GL_LIGHTING); GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GL11.glTranslatef((float) x, (float) y, (float) z); int skylight = pipe.container.getWorld().getSkyBlockTypeBrightness(EnumSkyBlock.Sky, pipe.container.x(), pipe.container.y(), pipe.container.z()); int blocklight = pipe.container.getWorld().getSkyBlockTypeBrightness(EnumSkyBlock.Block, pipe.container.x(), pipe.container.y(), pipe.container.z()); boolean sides = false, above = false; for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { int i = side.ordinal(); if (renderData.amount[i] <= 0) { continue; } if (!pipe.container.isPipeConnected(side)) { continue; } DisplayFluidList d = getDisplayFluidLists(renderData.fluidID, skylight, blocklight, renderData.flags, pipe.container.getWorldObj()); if (d == null) { continue; } int stage = (int) ((float) renderData.amount[i] / (float) (trans.getCapacity()) * (LIQUID_STAGES - 1)); GL11.glPushMatrix(); int list = 0; switch (ForgeDirection.VALID_DIRECTIONS[i]) { case UP: above = true; list = d.sideVertical[stage]; break; case DOWN: GL11.glTranslatef(0, -0.75F, 0); list = d.sideVertical[stage]; break; case EAST: case WEST: case SOUTH: case NORTH: sides = true; // Yes, this is kind of ugly, but was easier than transform the coordinates above. GL11.glTranslatef(0.5F, 0.0F, 0.5F); GL11.glRotatef(angleY[i], 0, 1, 0); GL11.glRotatef(angleZ[i], 0, 0, 1); GL11.glTranslatef(-0.5F, 0.0F, -0.5F); list = d.sideHorizontal[stage]; break; default: } bindTexture(TextureMap.locationBlocksTexture); RenderUtils.setGLColorFromInt(renderData.color); GL11.glCallList(list); GL11.glPopMatrix(); } if (renderData.amount[6] > 0) { DisplayFluidList d = getDisplayFluidLists(renderData.fluidID, skylight, blocklight, renderData.flags, pipe.container.getWorldObj()); if (d != null) { int stage = (int) ((float) renderData.amount[6] / (float) (trans.getCapacity()) * (LIQUID_STAGES - 1)); bindTexture(TextureMap.locationBlocksTexture); RenderUtils.setGLColorFromInt(renderData.color); if (above) { GL11.glCallList(d.centerVertical[stage]); } if (!above || sides) { GL11.glCallList(d.centerHorizontal[stage]); } } } GL11.glPopAttrib(); GL11.glPopMatrix(); } }