blob: 221d99dee3c29da3af560a03bb8f24267cad1049 [file] [log] [blame] [raw]
package mekanism.client.render;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import mekanism.api.EnumColor;
import mekanism.api.ObfuscatedNames;
import mekanism.api.gas.Gas;
import mekanism.api.gas.GasRegistry;
import mekanism.api.infuse.InfuseRegistry;
import mekanism.api.infuse.InfuseType;
import mekanism.api.transmitters.TransmissionType;
import mekanism.api.util.ReflectionUtils;
import mekanism.client.render.obj.TransmitterModel;
import mekanism.client.render.tileentity.RenderConfigurableMachine;
import mekanism.client.render.tileentity.RenderDynamicTank;
import mekanism.client.render.tileentity.RenderFluidTank;
import mekanism.client.render.tileentity.RenderThermalEvaporationController;
import mekanism.client.render.transmitter.RenderLogisticalTransporter;
import mekanism.client.render.transmitter.RenderMechanicalPipe;
import mekanism.common.base.IMetaItem;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ModelBakery;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.Timer;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.opengl.GL11;
@SideOnly(Side.CLIENT)
public class MekanismRenderer
{
public enum FluidType
{
STILL,
FLOWING;
}
public static TextureAtlasSprite[] colors = new TextureAtlasSprite[256];
public static TextureAtlasSprite energyIcon;
public static TextureAtlasSprite heatIcon;
public static TextureAtlasSprite laserIcon;
public static float GAS_RENDER_BASE = 0.2F;
public static Map<TransmissionType, TextureAtlasSprite> overlays = new HashMap<TransmissionType, TextureAtlasSprite>();
private static float lightmapLastX;
private static float lightmapLastY;
private static boolean optifineBreak = false;
public static int[] directionMap = new int[] {3, 0, 1, 2};
public static RenderConfigurableMachine machineRenderer = new RenderConfigurableMachine();
private static String[] simpleSides = new String[] {"Bottom", "Top", "Front", "Back", "Left", "Right"};
public static void init()
{
MinecraftForge.EVENT_BUS.register(new MekanismRenderer());
}
public static TextureAtlasSprite missingIcon;
public static Map<FluidType, Map<Fluid, TextureAtlasSprite>> textureMap = new HashMap<FluidType, Map<Fluid, TextureAtlasSprite>>();
@SubscribeEvent
public void onStitch(TextureStitchEvent.Pre event)
{
for(EnumColor color : EnumColor.values())
{
colors[color.ordinal()] = event.getMap().registerSprite(new ResourceLocation("mekanism:blocks/overlay/overlay_" + color.unlocalizedName));
}
for(TransmissionType type : TransmissionType.values())
{
overlays.put(type, event.getMap().registerSprite(new ResourceLocation("mekanism:blocks/overlay/" + type.getTransmission() + "Overlay")));
}
energyIcon = event.getMap().registerSprite(new ResourceLocation("mekanism:blocks/liquid/LiquidEnergy"));
heatIcon = event.getMap().registerSprite(new ResourceLocation("mekanism:blocks/liquid/LiquidHeat"));
laserIcon = event.getMap().registerSprite(new ResourceLocation("mekanism:blocks/Laser"));
event.getMap().registerSprite(new ResourceLocation("mekanism:blocks/liquid/LiquidHeavyWater"));
TransmitterModel.registerIcons(event.getMap());
for(Gas gas : GasRegistry.getRegisteredGasses())
{
gas.registerIcon(event.getMap());
}
for(InfuseType type : InfuseRegistry.getInfuseMap().values())
{
type.setIcon(event.getMap().registerSprite(type.iconResource));
}
RenderDynamicTank.resetDisplayInts();
RenderThermalEvaporationController.resetDisplayInts();
RenderFluidTank.resetDisplayInts();
}
@SubscribeEvent
public void onStitch(TextureStitchEvent.Post event)
{
initFluidTextures(event.getMap());
RenderLogisticalTransporter.onStitch(event.getMap());
RenderMechanicalPipe.onStitch();
for(Gas gas : GasRegistry.getRegisteredGasses())
{
gas.updateIcon(event.getMap());
}
}
public static void registerItemRender(String domain, Item item)
{
if(item instanceof IMetaItem)
{
IMetaItem metaItem = (IMetaItem)item;
List<ModelResourceLocation> variants = new ArrayList<ModelResourceLocation>();
for(int i = 0; i < metaItem.getVariants(); i++)
{
if(metaItem.getTexture(i) == null)
{
continue;
}
ModelResourceLocation loc = new ModelResourceLocation(domain + ":" + metaItem.getTexture(i), "inventory");
ModelLoader.setCustomModelResourceLocation(item, i, loc);
variants.add(loc);
ModelBakery.registerItemVariants(item, new ResourceLocation(domain + ":" + metaItem.getTexture(i)));
}
return;
}
ModelLoader.setCustomModelResourceLocation(item, 0, new ModelResourceLocation(item.getRegistryName(), "inventory"));
}
public static void initFluidTextures(TextureMap map)
{
missingIcon = map.getMissingSprite();
textureMap.clear();
for(FluidType type : FluidType.values())
{
textureMap.put(type, new HashMap<Fluid, TextureAtlasSprite>());
}
for(Fluid fluid : FluidRegistry.getRegisteredFluids().values())
{
if(fluid.getFlowing() != null)
{
String flow = fluid.getFlowing().toString();
TextureAtlasSprite sprite;
if(map.getTextureExtry(flow) != null)
{
sprite = map.getTextureExtry(flow);
}
else {
sprite = map.registerSprite(fluid.getStill());
}
textureMap.get(FluidType.FLOWING).put(fluid, sprite);
}
if(fluid.getStill() != null)
{
String still = fluid.getStill().toString();
TextureAtlasSprite sprite;
if(map.getTextureExtry(still) != null)
{
sprite = map.getTextureExtry(still);
}
else {
sprite = map.registerSprite(fluid.getStill());
}
textureMap.get(FluidType.STILL).put(fluid, sprite);
}
}
}
public static TextureAtlasSprite getFluidTexture(Fluid fluid, FluidType type)
{
if(fluid == null || type == null)
{
return missingIcon;
}
Map<Fluid, TextureAtlasSprite> map = textureMap.get(type);
return map.containsKey(fluid) ? map.get(fluid) : missingIcon;
}
public static boolean isDrawing(Tessellator tessellator)
{
return (boolean)ReflectionUtils.getPrivateValue(tessellator.getBuffer(), VertexBuffer.class, ObfuscatedNames.VertexBuffer_isDrawing);
}
public static class Model3D
{
public double posX, posY, posZ;
public double minX, minY, minZ;
public double maxX, maxY, maxZ;
public double textureStartX = 0, textureStartY = 0, textureStartZ = 0;
public double textureSizeX = 16, textureSizeY = 16, textureSizeZ = 16;
public double textureOffsetX = 0, textureOffsetY = 0, textureOffsetZ = 0;
public int[] textureFlips = new int[] {2, 2, 2, 2, 2, 2};
public TextureAtlasSprite[] textures = new TextureAtlasSprite[6];
public boolean[] renderSides = new boolean[] {true, true, true, true, true, true, false};
public Block baseBlock = Blocks.SAND;
public final void setBlockBounds(double xNeg, double yNeg, double zNeg, double xPos, double yPos, double zPos)
{
minX = xNeg;
minY = yNeg;
minZ = zNeg;
maxX = xPos;
maxY = yPos;
maxZ = zPos;
}
public double sizeX()
{
return maxX-minX;
}
public double sizeY()
{
return maxY-minY;
}
public double sizeZ()
{
return maxZ-minZ;
}
public void setSideRender(EnumFacing side, boolean value)
{
renderSides[side.ordinal()] = value;
}
public boolean shouldSideRender(EnumFacing side)
{
return renderSides[side.ordinal()];
}
public TextureAtlasSprite getBlockTextureFromSide(int i)
{
return textures[i];
}
public void setTexture(TextureAtlasSprite tex)
{
Arrays.fill(textures, tex);
}
public void setTextures(TextureAtlasSprite down, TextureAtlasSprite up, TextureAtlasSprite north, TextureAtlasSprite south, TextureAtlasSprite west, TextureAtlasSprite east)
{
textures[0] = down;
textures[1] = up;
textures[2] = north;
textures[3] = south;
textures[4] = west;
textures[5] = east;
}
}
public static BakedQuad iconTransform(BakedQuad quad, TextureAtlasSprite sprite)
{
int[] vertices = new int[quad.getVertexData().length];
System.arraycopy(quad.getVertexData(), 0, vertices, 0, vertices.length);
for(int i = 0; i < 4; ++i)
{
int j = quad.getFormat().getIntegerSize() * i;
int uvIndex = quad.getFormat().getUvOffsetById(0) / 4;
vertices[j + uvIndex] = Float.floatToRawIntBits(sprite.getInterpolatedU(quad.getSprite().getUnInterpolatedU(Float.intBitsToFloat(vertices[j + uvIndex]))));
vertices[j + uvIndex + 1] = Float.floatToRawIntBits(sprite.getInterpolatedV(quad.getSprite().getUnInterpolatedV(Float.intBitsToFloat(vertices[j + uvIndex + 1]))));
}
return new BakedQuad(vertices, quad.getTintIndex(), quad.getFace(), sprite, quad.shouldApplyDiffuseLighting(), quad.getFormat());
}
public static BakedQuad rotate(BakedQuad quad, int amount)
{
int[] vertices = new int[quad.getVertexData().length];
System.arraycopy(quad.getVertexData(), 0, vertices, 0, vertices.length);
for(int i = 0; i < 4; i++)
{
int nextIndex = (i+amount)%4;
int quadSize = quad.getFormat().getIntegerSize();
int uvIndex = quad.getFormat().getUvOffsetById(0) / 4;
vertices[quadSize*i + uvIndex] = quad.getVertexData()[quadSize*nextIndex + uvIndex];
vertices[quadSize*i + uvIndex + 1] = quad.getVertexData()[quadSize*nextIndex + uvIndex + 1];
}
return new BakedQuad(vertices, quad.getTintIndex(), quad.getFace(), quad.getSprite(), quad.shouldApplyDiffuseLighting(), quad.getFormat());
}
public static void prepFlowing(Model3D model, Fluid fluid)
{
TextureAtlasSprite still = getFluidTexture(fluid, FluidType.STILL);
TextureAtlasSprite flowing = getFluidTexture(fluid, FluidType.FLOWING);
model.setTextures(still, still, flowing, flowing, flowing, flowing);
}
public static void renderObject(Model3D object)
{
if(object == null)
{
return;
}
GlStateManager.pushMatrix();
GL11.glTranslated(object.minX, object.minY, object.minZ);
RenderResizableCuboid.INSTANCE.renderCube(object);
GlStateManager.popMatrix();
}
public static void color(EnumColor color)
{
color(color, 1.0F);
}
public static void color(EnumColor color, float alpha)
{
color(color, alpha, 1.0F);
}
public static void color(EnumColor color, float alpha, float multiplier)
{
GL11.glColor4f(color.getColor(0)*multiplier, color.getColor(1)*multiplier, color.getColor(2)*multiplier, alpha);
}
public static void resetColor()
{
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
}
public static TextureAtlasSprite getColorIcon(EnumColor color)
{
return colors[color.ordinal()];
}
public static void glowOn()
{
glowOn(15);
}
public static void glowOn(int glow)
{
GL11.glPushAttrib(GL11.GL_LIGHTING_BIT);
try {
lightmapLastX = OpenGlHelper.lastBrightnessX;
lightmapLastY = OpenGlHelper.lastBrightnessY;
} catch(NoSuchFieldError e) {
optifineBreak = true;
}
float glowRatioX = Math.min((glow/15F)*240F + lightmapLastX, 240);
float glowRatioY = Math.min((glow/15F)*240F + lightmapLastY, 240);
if(!optifineBreak)
{
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, glowRatioX, glowRatioY);
}
}
public static void glowOff()
{
if(!optifineBreak)
{
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, lightmapLastX, lightmapLastY);
}
GL11.glPopAttrib();
}
public static void blendOn()
{
GL11.glPushAttrib(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
GL11.glShadeModel(GL11.GL_SMOOTH);
GL11.glDisable(GL11.GL_ALPHA_TEST);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
public static void blendOff()
{
GL11.glPopAttrib();
}
/**
* Blender .objs have a different handedness of coordinate system to MC, so faces are wound backwards.
*/
public static void cullFrontFace()
{
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glCullFace(GL11.GL_FRONT);
}
public static void disableCullFace()
{
GL11.glCullFace(GL11.GL_BACK);
GL11.glDisable(GL11.GL_CULL_FACE);
}
public static void colorFluid(Fluid fluid)
{
int color = fluid.getColor();
float cR = (color >> 16 & 0xFF) / 255.0F;
float cG = (color >> 8 & 0xFF) / 255.0F;
float cB = (color & 0xFF) / 255.0F;
GL11.glColor3f(cR, cG, cB);
}
public static class DisplayInteger
{
public int display;
@Override
public int hashCode()
{
int code = 1;
code = 31 * code + display;
return code;
}
@Override
public boolean equals(Object obj)
{
return obj instanceof DisplayInteger && ((DisplayInteger)obj).display == display;
}
public static DisplayInteger createAndStart()
{
DisplayInteger newInteger = new DisplayInteger();
newInteger.display = GLAllocation.generateDisplayLists(1);
GL11.glNewList(newInteger.display, GL11.GL_COMPILE);
return newInteger;
}
public static void endList()
{
GL11.glEndList();
}
public void render()
{
GL11.glCallList(display);
}
}
public static float getPartialTick()
{
try {
Timer t = (Timer)ReflectionUtils.getPrivateValue(Minecraft.getMinecraft(), Minecraft.class, ObfuscatedNames.Minecraft_timer);
return t.renderPartialTicks;
} catch(Exception e) {}
return 0;
}
public static ResourceLocation getBlocksTexture()
{
return TextureMap.LOCATION_BLOCKS_TEXTURE;
}
public static interface ICustomBlockIcon
{
public ResourceLocation getIcon(ItemStack stack, int side);
}
}