package codechicken.lib.render;
import codechicken.lib.vec.Cuboid6;
import codechicken.lib.vec.Rectangle4i;
import codechicken.lib.vec.Vector3;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.shader.Framebuffer;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import org.lwjgl.opengl.GL11;
public class RenderUtils {
static Vector3[] vectors = new Vector3[8];
/*static RenderItem uniformRenderItem = new RenderItem()
{
public boolean shouldBob()
{
return false;
}
};*/
static EntityItem entityItem;
static {
for (int i = 0; i < vectors.length; i++) {
vectors[i] = new Vector3();
}
//uniformRenderItem.setRenderManager(RenderManager.instance);
entityItem = new EntityItem(null);
entityItem.hoverStart = 0;
}
public static void renderFluidQuad(Vector3 point1, Vector3 point2, Vector3 point3, Vector3 point4, TextureAtlasSprite icon, double res) {
renderFluidQuad(point2, vectors[0].set(point4).subtract(point1), vectors[1].set(point1).subtract(point2), icon, res);
}
/**
* Draws a tessellated quadrilateral bottom to top, left to right
*
* @param base The bottom left corner of the quad
* @param wide The bottom of the quad
* @param high The left side of the quad
* @param res Units per icon
*/
public static void renderFluidQuad(Vector3 base, Vector3 wide, Vector3 high, TextureAtlasSprite icon, double res) {
WorldRenderer r = Tessellator.getInstance().getWorldRenderer();
double u1 = icon.getMinU();
double du = icon.getMaxU() - icon.getMinU();
double v2 = icon.getMaxV();
double dv = icon.getMaxV() - icon.getMinV();
double wlen = wide.mag();
double hlen = high.mag();
double x = 0;
while (x < wlen) {
double rx = wlen - x;
if (rx > res) {
rx = res;
}
double y = 0;
while (y < hlen) {
double ry = hlen - y;
if (ry > res) {
ry = res;
}
Vector3 dx1 = vectors[2].set(wide).multiply(x / wlen);
Vector3 dx2 = vectors[3].set(wide).multiply((x + rx) / wlen);
Vector3 dy1 = vectors[4].set(high).multiply(y / hlen);
Vector3 dy2 = vectors[5].set(high).multiply((y + ry) / hlen);
r.pos(base.x + dx1.x + dy2.x, base.y + dx1.y + dy2.y, base.z + dx1.z + dy2.z).tex(u1, v2 - ry / res * dv).endVertex();
r.pos(base.x + dx1.x + dy1.x, base.y + dx1.y + dy1.y, base.z + dx1.z + dy1.z).tex(u1, v2).endVertex();
r.pos(base.x + dx2.x + dy1.x, base.y + dx2.y + dy1.y, base.z + dx2.z + dy1.z).tex(u1 + rx / res * du, v2).endVertex();
r.pos(base.x + dx2.x + dy2.x, base.y + dx2.y + dy2.y, base.z + dx2.z + dy2.z).tex(u1 + rx / res * du, v2 - ry / res * dv).endVertex();
y += ry;
}
x += rx;
}
}
public static void translateToWorldCoords(Entity entity, float frame) {
double interpPosX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * frame;
double interpPosY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * frame;
double interpPosZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * frame;
GlStateManager.translate(-interpPosX, -interpPosY, -interpPosZ);
}
public static void drawCuboidOutline(Cuboid6 c) {
WorldRenderer r = CCRenderState.startDrawing(3, DefaultVertexFormats.POSITION);
r.pos(c.min.x, c.min.y, c.min.z).endVertex();
r.pos(c.max.x, c.min.y, c.min.z).endVertex();
r.pos(c.max.x, c.min.y, c.max.z).endVertex();
r.pos(c.min.x, c.min.y, c.max.z).endVertex();
r.pos(c.min.x, c.min.y, c.min.z).endVertex();
CCRenderState.draw();
CCRenderState.startDrawing(3, DefaultVertexFormats.POSITION);
r.pos(c.min.x, c.max.y, c.min.z).endVertex();
r.pos(c.max.x, c.max.y, c.min.z).endVertex();
r.pos(c.max.x, c.max.y, c.max.z).endVertex();
r.pos(c.min.x, c.max.y, c.max.z).endVertex();
r.pos(c.min.x, c.max.y, c.min.z).endVertex();
CCRenderState.draw();
CCRenderState.startDrawing(1, DefaultVertexFormats.POSITION);
r.pos(c.min.x, c.min.y, c.min.z).endVertex();
r.pos(c.min.x, c.max.y, c.min.z).endVertex();
r.pos(c.max.x, c.min.y, c.min.z).endVertex();
r.pos(c.max.x, c.max.y, c.min.z).endVertex();
r.pos(c.max.x, c.min.y, c.max.z).endVertex();
r.pos(c.max.x, c.max.y, c.max.z).endVertex();
r.pos(c.min.x, c.min.y, c.max.z).endVertex();
r.pos(c.min.x, c.max.y, c.max.z).endVertex();
CCRenderState.draw();
}
public static void renderFluidCuboid(Cuboid6 bound, TextureAtlasSprite tex, double res) {
renderFluidQuad(//bottom
new Vector3(bound.min.x, bound.min.y, bound.min.z), new Vector3(bound.max.x, bound.min.y, bound.min.z), new Vector3(bound.max.x, bound.min.y, bound.max.z), new Vector3(bound.min.x, bound.min.y, bound.max.z), tex, res);
renderFluidQuad(//top
new Vector3(bound.min.x, bound.max.y, bound.min.z), new Vector3(bound.min.x, bound.max.y, bound.max.z), new Vector3(bound.max.x, bound.max.y, bound.max.z), new Vector3(bound.max.x, bound.max.y, bound.min.z), tex, res);
renderFluidQuad(//-x
new Vector3(bound.min.x, bound.max.y, bound.min.z), new Vector3(bound.min.x, bound.min.y, bound.min.z), new Vector3(bound.min.x, bound.min.y, bound.max.z), new Vector3(bound.min.x, bound.max.y, bound.max.z), tex, res);
renderFluidQuad(//+x
new Vector3(bound.max.x, bound.max.y, bound.max.z), new Vector3(bound.max.x, bound.min.y, bound.max.z), new Vector3(bound.max.x, bound.min.y, bound.min.z), new Vector3(bound.max.x, bound.max.y, bound.min.z), tex, res);
renderFluidQuad(//-z
new Vector3(bound.max.x, bound.max.y, bound.min.z), new Vector3(bound.max.x, bound.min.y, bound.min.z), new Vector3(bound.min.x, bound.min.y, bound.min.z), new Vector3(bound.min.x, bound.max.y, bound.min.z), tex, res);
renderFluidQuad(//+z
new Vector3(bound.min.x, bound.max.y, bound.max.z), new Vector3(bound.min.x, bound.min.y, bound.max.z), new Vector3(bound.max.x, bound.min.y, bound.max.z), new Vector3(bound.max.x, bound.max.y, bound.max.z), tex, res);
}
public static void renderBlockOverlaySide(int x, int y, int z, int side, double tx1, double tx2, double ty1, double ty2) {
double[] points = new double[] { x - 0.009, x + 1.009, y - 0.009, y + 1.009, z - 0.009, z + 1.009 };
WorldRenderer r = Tessellator.getInstance().getWorldRenderer();
switch (side) {
case 0:
r.pos(points[0], points[2], points[4]).tex(tx1, ty1).endVertex();
r.pos(points[1], points[2], points[4]).tex(tx2, ty1).endVertex();
r.pos(points[1], points[2], points[5]).tex(tx2, ty2).endVertex();
r.pos(points[0], points[2], points[5]).tex(tx1, ty2).endVertex();
break;
case 1:
r.pos(points[1], points[3], points[4]).tex(tx2, ty1).endVertex();
r.pos(points[0], points[3], points[4]).tex(tx1, ty1).endVertex();
r.pos(points[0], points[3], points[5]).tex(tx1, ty2).endVertex();
r.pos(points[1], points[3], points[5]).tex(tx2, ty2).endVertex();
break;
case 2:
r.pos(points[0], points[3], points[4]).tex(tx2, ty1).endVertex();
r.pos(points[1], points[3], points[4]).tex(tx1, ty1).endVertex();
r.pos(points[1], points[2], points[4]).tex(tx1, ty2).endVertex();
r.pos(points[0], points[2], points[4]).tex(tx2, ty2).endVertex();
break;
case 3:
r.pos(points[1], points[3], points[5]).tex(tx2, ty1).endVertex();
r.pos(points[0], points[3], points[5]).tex(tx1, ty1).endVertex();
r.pos(points[0], points[2], points[5]).tex(tx1, ty2).endVertex();
r.pos(points[1], points[2], points[5]).tex(tx2, ty2).endVertex();
break;
case 4:
r.pos(points[0], points[3], points[5]).tex(tx2, ty1).endVertex();
r.pos(points[0], points[3], points[4]).tex(tx1, ty1).endVertex();
r.pos(points[0], points[2], points[4]).tex(tx1, ty2).endVertex();
r.pos(points[0], points[2], points[5]).tex(tx2, ty2).endVertex();
break;
case 5:
r.pos(points[1], points[3], points[4]).tex(tx2, ty1).endVertex();
r.pos(points[1], points[3], points[5]).tex(tx1, ty1).endVertex();
r.pos(points[1], points[2], points[5]).tex(tx1, ty2).endVertex();
r.pos(points[1], points[2], points[4]).tex(tx2, ty2).endVertex();
break;
}
}
public static boolean shouldRenderFluid(FluidStack stack) {
return stack.amount > 0 && stack.getFluid() != null;
}
/**
* @param stack The fluid stack to render
* @return The icon of the fluid
*/
public static TextureAtlasSprite prepareFluidRender(FluidStack stack, int alpha) {
GlStateManager.disableLighting();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
Fluid fluid = stack.getFluid();
CCRenderState.setColour(fluid.getColor(stack) << 8 | alpha);
CCRenderState.changeTexture(TextureMap.locationBlocksTexture);
String iconName = null;
if (fluid == FluidRegistry.LAVA) {
iconName = "minecraft:blocks/lava_still";
} else if (fluid == FluidRegistry.WATER) {
iconName = "minecraft:blocks/water_still";
}
return Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(iconName);
}
/**
* Re-enables lighting and disables blending.
*/
public static void postFluidRender() {
GlStateManager.enableLighting();
GlStateManager.disableBlend();
}
public static double fluidDensityToAlpha(double density) {
return Math.pow(density, 0.4);
}
/**
* Renders a fluid within a bounding box.
* If the fluid is a liquid it will render as a normal tank with height equal to density/bound.height.
* If the fluid is a gas, it will render the full box with an alpha equal to density.
* Warning, bound will be mutated if the fluid is a liquid
*
* @param stack The fluid to render.
* @param bound The box within which the fluid is contained.
* @param density The volume of fluid / the capacity of the tank. For gases this determines the alpha, for liquids this determines the height.
* @param res The resolution to render at.
*/
public static void renderFluidCuboid(FluidStack stack, Cuboid6 bound, double density, double res) {
if (!shouldRenderFluid(stack)) {
return;
}
int alpha = 255;
if (stack.getFluid().isGaseous()) {
alpha = (int) (fluidDensityToAlpha(density) * 255);
} else {
bound.max.y = bound.min.y + (bound.max.y - bound.min.y) * density;
}
TextureAtlasSprite tex = prepareFluidRender(stack, alpha);
CCRenderState.startDrawing();
renderFluidCuboid(bound, tex, res);
CCRenderState.draw();
postFluidRender();
}
public static void renderFluidGauge(FluidStack stack, Rectangle4i rect, double density, double res) {
if (!shouldRenderFluid(stack)) {
return;
}
int alpha = 255;
if (stack.getFluid().isGaseous()) {
alpha = (int) (fluidDensityToAlpha(density) * 255);
} else {
int height = (int) (rect.h * density);
rect.y += rect.h - height;
rect.h = height;
}
TextureAtlasSprite tex = prepareFluidRender(stack, alpha);
CCRenderState.startDrawing();
renderFluidQuad(new Vector3(rect.x, rect.y + rect.h, 0), new Vector3(rect.w, 0, 0), new Vector3(0, -rect.h, 0), tex, res);
CCRenderState.draw();
postFluidRender();
}
/**
* Renders items and blocks in the world at 0,0,0 with transformations that size them appropriately
*/
/*public static void renderItemUniform(ItemStack item) {
renderItemUniform(item, 0);
}*/
/**
* Renders items and blocks in the world at 0,0,0 with transformations that size them appropriately
*
* @param spin The spin angle of the item around the y axis in degrees
*/
/*public static void renderItemUniform(ItemStack item, double spin)
{
IItemRenderer customRenderer = MinecraftForgeClient.getItemRenderer(item, ENTITY);
boolean is3D = customRenderer != null && customRenderer.shouldUseRenderHelper(ENTITY, item, BLOCK_3D);
boolean larger = false;
if (item.getItem() instanceof ItemBlock && RenderBlocks.renderItemIn3d(Block.getBlockFromItem(item.getItem()).getRenderType()))
{
int renderType = Block.getBlockFromItem(item.getItem()).getRenderType();
larger = !(renderType == 1 || renderType == 19 || renderType == 12 || renderType == 2);
}
else if(is3D)
{
larger = true;
}
double d = 2;
double d1 = 1/d;
if(larger)
GLStateManager.scale(d, d, d);
GLStateManager.color(1, 1, 1, 1);
entityItem.setEntityItemStack(item);
uniformRenderItem.doRender(entityItem, 0, larger ? 0.09 : 0.06, 0, 0, (float)(spin*9/Math.PI));
if(larger)
GLStateManager.scale(d1, d1, d1);
}/*
/**
* Checks if stencil buffer is supported and attempts to enable it if so.
*/
public static boolean checkEnableStencil() {
Framebuffer fb = Minecraft.getMinecraft().getFramebuffer();
return fb.isStencilEnabled() || fb.enableStencil();
}
}