package micdoodle8.mods.galacticraft.core.client.render.tile;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
import micdoodle8.mods.galacticraft.api.transmission.tile.IBufferTransmitter;
import micdoodle8.mods.galacticraft.core.Constants;
import micdoodle8.mods.galacticraft.core.GCBlocks;
import micdoodle8.mods.galacticraft.core.fluid.FluidNetwork;
import micdoodle8.mods.galacticraft.core.tile.TileEntityFluidPipe;
import micdoodle8.mods.galacticraft.core.util.ClientUtil;
import micdoodle8.mods.galacticraft.core.util.OxygenUtil;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.IFlexibleBakedModel;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.fluids.Fluid;
import org.lwjgl.opengl.GL11;
import java.util.HashMap;
public class TileEntityFluidPipeRenderer extends TileEntitySpecialRenderer<TileEntityFluidPipe>
{
private static HashMap<Integer, HashMap<Fluid, Integer[]>> cache = new HashMap<>();
private static IFlexibleBakedModel[] pullConnectorModel = new IFlexibleBakedModel[6];
private final int stages = 100;
private void updateModels()
{
if (pullConnectorModel[0] == null)
{
try
{
for (EnumFacing facing : EnumFacing.VALUES)
{
// Get the first character of the direction name (n/e/s/w/u/d)
Character c = Character.toLowerCase(facing.getName().charAt(0));
IModel model = ModelLoaderRegistry.getModel(new ResourceLocation(Constants.ASSET_PREFIX, "block/fluid_pipe_pull_" + c));
Function<ResourceLocation, TextureAtlasSprite> spriteFunction = (ResourceLocation location) -> Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(location.toString());
pullConnectorModel[facing.ordinal()] = model.bake(model.getDefaultState(), DefaultVertexFormats.ITEM, spriteFunction);
}
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
@Override
public void renderTileEntityAt(TileEntityFluidPipe pipe, double x, double y, double z, float partialTicks, int destroyStage)
{
updateModels();
if (pipe.getBlockType() == GCBlocks.oxygenPipePull)
{
GL11.glPushMatrix();
GL11.glTranslatef((float) x, (float) y, (float) z);
RenderHelper.disableStandardItemLighting();
this.bindTexture(TextureMap.locationBlocksTexture);
if (Minecraft.isAmbientOcclusionEnabled())
{
GlStateManager.shadeModel(GL11.GL_SMOOTH);
}
else
{
GlStateManager.shadeModel(GL11.GL_FLAT);
}
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
TileEntity[] adj = OxygenUtil.getAdjacentFluidConnections(pipe);
for (EnumFacing facing : EnumFacing.VALUES)
{
TileEntity sideTile = adj[facing.ordinal()];
if (sideTile != null && !(sideTile instanceof IBufferTransmitter))
{
GL11.glPushMatrix();
ClientUtil.drawBakedModel(pullConnectorModel[facing.ordinal()]);
GL11.glPopMatrix();
}
}
GL11.glPopMatrix();
}
float scale;
if (pipe.hasNetwork())
{
FluidNetwork network = (FluidNetwork) pipe.getNetwork();
scale = network.fluidScale;
}
else
{
scale = pipe.buffer.getFluidAmount() / (float) pipe.buffer.getCapacity();
}
Fluid fluid;
if (pipe.hasNetwork())
{
FluidNetwork network = (FluidNetwork) pipe.getNetwork();
fluid = network.refFluid;
}
else
{
fluid = pipe.getBuffer() == null ? null : pipe.getBuffer().getFluid();
}
if (fluid == null)
{
return;
}
if (scale > 0.01)
{
this.bindTexture(TextureMap.locationBlocksTexture);
GL11.glPushMatrix();
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
GL11.glTranslatef((float) x, (float) y + 1.0F, (float) z + 1.0F);
GL11.glScalef(1.0F, -1.0F, -1.0F);
GL11.glTranslatef(0.5F, 0.5F, 0.5F);
GlStateManager.disableLighting();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
float opacity = 1.0F;
boolean gas = fluid.isGaseous();
if (gas)
{
opacity = scale;
}
GL11.glColor4f(1.0F, 1.0F, 1.0F, opacity);
TileEntity[] connections = OxygenUtil.getAdjacentFluidConnections(pipe);
for (EnumFacing side : EnumFacing.VALUES)
{
TileEntity sideTile = connections[side.ordinal()];
if (sideTile != null)
{
Integer[] displayLists = getListAndRender(side, fluid);
if (displayLists != null)
{
if (!gas)
{
Integer list = displayLists[Math.max(3, (int) (scale * (stages - 1)))];
GL11.glCallList(list);
}
else
{
Integer list = displayLists[stages - 1];
GL11.glCallList(list);
}
}
}
}
Integer[] displayLists = getListAndRender(null, fluid);
if (displayLists != null)
{
if (!gas)
{
Integer list = displayLists[Math.max(3, (int) (scale * (stages - 1)))];
GL11.glCallList(list);
}
else
{
Integer list = displayLists[stages - 1];
GL11.glCallList(list);
}
}
GlStateManager.enableLighting();
GlStateManager.disableBlend();
GL11.glPopMatrix();
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
}
}
private Integer[] getListAndRender(EnumFacing side, Fluid fluid)
{
if (fluid == null)
{
return null;
}
TextureAtlasSprite sprite = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(fluid.getStill().toString());
int sideIndex = side == null ? 6 : side.ordinal();
if (cache.containsKey(sideIndex) && cache.get(sideIndex).containsKey(fluid))
{
return cache.get(sideIndex).get(fluid);
}
float size = 0.09F;
float mid = 0.0F;
float minX;
float maxX;
float minY;
float maxY;
float minZ;
float maxZ;
Integer[] displayLists = new Integer[this.stages];
if (cache.containsKey(sideIndex))
{
cache.get(sideIndex).put(fluid, displayLists);
}
else
{
HashMap<Fluid, Integer[]> map = Maps.newHashMap();
map.put(fluid, displayLists);
cache.put(sideIndex, map);
}
for (int i = 0; i < stages; ++i)
{
displayLists[i] = GLAllocation.generateDisplayLists(1);
GL11.glNewList(displayLists[i], GL11.GL_COMPILE);
float level = (i / (float) stages);
switch (sideIndex)
{
case 0:
minX = mid - level * size;
maxX = mid + level * size;
minY = mid + size;
maxY = mid + 0.5F;
minZ = mid - level * size;
maxZ = mid + level * size;
break;
case 1:
minX = mid - level * size;
maxX = mid + level * size;
minY = mid - 0.5F;
maxY = mid - size;
minZ = mid - level * size;
maxZ = mid + level * size;
break;
case 2:
minX = mid - size;
maxX = mid + size;
maxY = mid + size;
minY = mid + size - level * size * 2.0F;
minZ = mid + size;
maxZ = mid + 0.5F;
break;
case 3:
minX = mid - size;
maxX = mid + size;
maxY = mid + size;
minY = mid + size - level * size * 2.0F;
minZ = mid - 0.5F;
maxZ = mid - size;
break;
case 4:
minX = mid - 0.5F;
maxX = mid - size;
maxY = mid + size;
minY = mid + size - level * size * 2.0F;
minZ = mid - size;
maxZ = mid + size;
break;
case 5:
minX = mid + size;
maxX = mid + 0.5F;
maxY = mid + size;
minY = mid + size - level * size * 2.0F;
minZ = mid - size;
maxZ = mid + size;
break;
default:
minX = mid - size;
maxX = mid + size;
maxY = mid + size;
minY = mid + size - level * size * 2.0F;
minZ = mid - size;
maxZ = mid + size;
break;
}
renderBox(minX, maxX, minY, maxY, minZ, maxZ, level, sprite);
GL11.glEndList();
}
return displayLists;
}
private void renderBox(float minX, float maxX, float minY, float maxY, float minZ, float maxZ, float level, TextureAtlasSprite sprite)
{
final double uMin = sprite.getMinU();
final double uMax = sprite.getMaxU();
final double vMin = sprite.getMinV();
final double vMax = sprite.getMaxV();
Tessellator tess = Tessellator.getInstance();
WorldRenderer worldRenderer = tess.getWorldRenderer();
double uDiff = (uMax - uMin);
double vDiff = (vMax - vMin);
double texMinX_U = uMin + (minX + 0.5F) * uDiff;
double texMaxX_U = uMin + (maxX + 0.5F) * uDiff;
double texMinZ_U = uMin + (minZ + 0.5F) * uDiff;
double texMaxZ_U = uMin + (maxZ + 0.5F) * uDiff;
double texMinX_V = vMin + (minX + 0.5F) * vDiff;
double texMaxX_V = vMin + (maxX + 0.5F) * vDiff;
double texMinY_V = vMin + (minY + 0.5F) * vDiff;
double texMaxY_V = vMin + (maxY + 0.5F) * vDiff;
// North
worldRenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
worldRenderer.pos(minX, minY, minZ).tex(texMinX_U, texMinY_V).endVertex();
worldRenderer.pos(minX, maxY, minZ).tex(texMinX_U, texMaxY_V).endVertex();
worldRenderer.pos(maxX, maxY, minZ).tex(texMaxX_U, texMaxY_V).endVertex();
worldRenderer.pos(maxX, minY, minZ).tex(texMaxX_U, texMinY_V).endVertex();
tess.draw();
// South
worldRenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
worldRenderer.pos(maxX, minY, maxZ).tex(texMaxX_U, texMinY_V).endVertex();
worldRenderer.pos(maxX, maxY, maxZ).tex(texMaxX_U, texMaxY_V).endVertex();
worldRenderer.pos(minX, maxY, maxZ).tex(texMinX_U, texMaxY_V).endVertex();
worldRenderer.pos(minX, minY, maxZ).tex(texMinX_U, texMinY_V).endVertex();
tess.draw();
// West
worldRenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
worldRenderer.pos(minX, maxY, minZ).tex(texMinZ_U, texMaxY_V).endVertex();
worldRenderer.pos(minX, minY, minZ).tex(texMinZ_U, texMinY_V).endVertex();
worldRenderer.pos(minX, minY, maxZ).tex(texMaxZ_U, texMinY_V).endVertex();
worldRenderer.pos(minX, maxY, maxZ).tex(texMaxZ_U, texMaxY_V).endVertex();
tess.draw();
// East
worldRenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
worldRenderer.pos(maxX, maxY, maxZ).tex(texMaxZ_U, texMaxY_V).endVertex();
worldRenderer.pos(maxX, minY, maxZ).tex(texMaxZ_U, texMinY_V).endVertex();
worldRenderer.pos(maxX, minY, minZ).tex(texMinZ_U, texMinY_V).endVertex();
worldRenderer.pos(maxX, maxY, minZ).tex(texMinZ_U, texMaxY_V).endVertex();
tess.draw();
worldRenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
worldRenderer.pos(maxX, minY, maxZ).tex(texMaxZ_U, texMaxX_V).endVertex();
worldRenderer.pos(minX, minY, maxZ).tex(texMaxZ_U, texMinX_V).endVertex();
worldRenderer.pos(minX, minY, minZ).tex(texMinZ_U, texMinX_V).endVertex();
worldRenderer.pos(maxX, minY, minZ).tex(texMinZ_U, texMaxX_V).endVertex();
tess.draw();
worldRenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
worldRenderer.pos(maxX, maxY, maxZ).tex(texMaxZ_U, texMaxX_V).endVertex();
worldRenderer.pos(maxX, maxY, minZ).tex(texMinZ_U, texMaxX_V).endVertex();
worldRenderer.pos(minX, maxY, minZ).tex(texMinZ_U, texMinX_V).endVertex();
worldRenderer.pos(minX, maxY, maxZ).tex(texMaxZ_U, texMinX_V).endVertex();
tess.draw();
}
}