matteroverdrive.util.RenderUtils.java Source code

Java tutorial

Introduction

Here is the source code for matteroverdrive.util.RenderUtils.java

Source

/*
 * This file is part of Matter Overdrive
 * Copyright (c) 2015., Simeon Radivoev, All rights reserved.
 *
 * Matter Overdrive is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Matter Overdrive is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Matter Overdrive.  If not, see <http://www.gnu.org/licenses>.
 */

package matteroverdrive.util;

import matteroverdrive.client.data.Color;
import matteroverdrive.client.render.tileentity.TileEntityRendererPatternMonitor;
import matteroverdrive.util.math.MOMathHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.IIcon;
import net.minecraft.util.MathHelper;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.Vec3;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.client.model.obj.Face;
import net.minecraftforge.client.model.obj.GroupObject;
import net.minecraftforge.common.util.ForgeDirection;
import org.apache.commons.lang3.StringUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
import org.lwjgl.util.vector.Vector4f;

import java.util.List;

import static org.lwjgl.opengl.GL11.*;

public class RenderUtils {
    private static FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer;
    private static TextureManager textureManager = Minecraft.getMinecraft().getTextureManager();
    private static RenderItem renderItem = new RenderItem();
    private static float lastLightMapX, lastLightMapY;

    public static void renderStack(int x, int y, ItemStack stack) {
        renderStack(x, y, 32, stack, false);
    }

    public static void renderStack(int x, int y, int z, ItemStack stack, boolean renderOverlay) {
        if (stack != null && stack.getItem() != null) {
            glPushMatrix();
            glColor3f(1, 1, 1);
            RenderHelper.enableGUIStandardItemLighting();
            glEnable(GL_LIGHTING);
            glEnable(GL_DEPTH_TEST);
            GL11.glTranslatef(0.0F, 0.0F, z);
            //this.zLevel = 200.0F;
            renderItem.zLevel = -50f;
            FontRenderer font = null;
            if (stack != null)
                font = stack.getItem().getFontRenderer(stack);
            if (font == null)
                font = Minecraft.getMinecraft().fontRenderer;
            renderItem.renderItemAndEffectIntoGUI(font, Minecraft.getMinecraft().getTextureManager(), stack, x, y);
            if (renderOverlay)
                renderItemOverlayIntoGUI(font, stack, x, y,
                        stack.stackSize > 1 ? Integer.toString(stack.stackSize) : null);
            renderItem.zLevel = 0.0F;

            glEnable(GL_ALPHA_TEST);
            glDisable(GL_LIGHTING);
            glPopMatrix();
        }
    }

    /**
     * Should be the same as {@link RenderItem#renderItemOverlayIntoGUI(FontRenderer, TextureManager, ItemStack, int, int,String)}
     */
    public static void renderItemOverlayIntoGUI(FontRenderer p_94148_1_, ItemStack p_94148_3_, int p_94148_4_,
            int p_94148_5_, String p_94148_6_) {
        if (p_94148_3_ != null) {
            if (p_94148_3_.stackSize > 1 || p_94148_6_ != null) {
                String s1 = p_94148_6_ == null ? String.valueOf(p_94148_3_.stackSize) : p_94148_6_;
                GL11.glDisable(GL11.GL_LIGHTING);
                //GL11.glDisable(GL11.GL_DEPTH_TEST);
                GL11.glDisable(GL11.GL_BLEND);
                p_94148_1_.drawStringWithShadow(s1, p_94148_4_ + 19 - 2 - p_94148_1_.getStringWidth(s1),
                        p_94148_5_ + 6 + 3, 16777215);
                GL11.glEnable(GL11.GL_LIGHTING);
                //GL11.glEnable(GL11.GL_DEPTH_TEST);
            }

            if (p_94148_3_.getItem().showDurabilityBar(p_94148_3_)) {
                double health = p_94148_3_.getItem().getDurabilityForDisplay(p_94148_3_);
                int j1 = (int) Math.round(13.0D - health * 13.0D);
                int k = (int) Math.round(255.0D - health * 255.0D);
                GL11.glDisable(GL11.GL_LIGHTING);
                //GL11.glDisable(GL11.GL_DEPTH_TEST);
                GL11.glDisable(GL11.GL_TEXTURE_2D);
                GL11.glDisable(GL11.GL_ALPHA_TEST);
                GL11.glDisable(GL11.GL_BLEND);
                Tessellator tessellator = Tessellator.instance;
                int l = 255 - k << 16 | k << 8;
                int i1 = (255 - k) / 4 << 16 | 16128;
                drawPlaneWithUV(p_94148_4_ + 2, p_94148_5_ + 13, 0, 13, 2, 0, 0, 0, 0, 0);
                drawPlaneWithUV(p_94148_4_ + 2, p_94148_5_ + 13, 0, 12, 1, 0, 0, 0, 0, i1);
                drawPlaneWithUV(p_94148_4_ + 2, p_94148_5_ + 13, 0, j1, 1, 0, 0, 0, 0, l);
                GL11.glEnable(GL11.GL_BLEND); // Forge: Disable Bled because it screws with a lot of things down the line.
                GL11.glEnable(GL11.GL_ALPHA_TEST);
                GL11.glEnable(GL11.GL_TEXTURE_2D);
                GL11.glEnable(GL11.GL_LIGHTING);
                //GL11.glEnable(GL11.GL_DEPTH_TEST);
                GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
            }
        }
    }

    public static void renderStack(int x, int y, ItemStack stack, float opacity) {
        if (stack != null && stack.getItem() != null) {
            glColor3f(1, 1, 1);
            glDisable(GL_CULL_FACE);
            glDepthMask(true);
            RenderHelper.enableGUIStandardItemLighting();
            renderItem.renderItemIntoGUI(fontRenderer, textureManager, stack, x, y);
            RenderHelper.disableStandardItemLighting();
            glEnable(GL_CULL_FACE);
        }
    }

    public static void rotateFromBlock(World world, int x, int y, int z) {
        if (world != null) {
            int metadata = world.getBlockMetadata(x, y, z);

            ForgeDirection direction = ForgeDirection.values()[metadata];

            if (direction == ForgeDirection.WEST) {
                GL11.glRotated(-90, 0, 1, 0);
            } else if (direction == ForgeDirection.EAST) {
                GL11.glRotated(90, 0, 1, 0);
            } else if (direction == ForgeDirection.NORTH) {
                GL11.glRotated(-180, 0, 1, 0);
            }
        }

        //System.out.println("Metadata " + metadata + "at [" + x +","+ y +","+ z + "]");
    }

    public static void rotateFromBlock(Matrix4f mat, IBlockAccess world, int x, int y, int z) {
        if (world != null) {
            int metadata = world.getBlockMetadata(x, y, z);

            ForgeDirection direction = ForgeDirection.values()[metadata];
            Vector3f axis = new Vector3f(0, 1, 0);

            if (direction == ForgeDirection.WEST) {
                mat.rotate(-(float) (Math.PI / 2), axis);
            } else if (direction == ForgeDirection.EAST) {
                mat.rotate((float) (Math.PI / 2), axis);
            } else if (direction == ForgeDirection.NORTH) {
                mat.rotate(-(float) (Math.PI), axis);
            }
        }
    }

    public static void drawCircle(double radius, int segments) {
        glBegin(GL_POLYGON);
        for (int i = 0; i < segments; i++) {
            glVertex3d(Math.sin((i / (double) segments) * Math.PI * 2) * radius,
                    Math.cos((i / (double) segments) * Math.PI * 2) * radius, 0);
        }
        glEnd();
    }

    public static void drawPlane(double size) {
        drawPlane(size, size);
    }

    public static void drawPlane(double x, double y, double z, double sizeX, double sizeY) {
        drawPlaneWithUV(x, y, z, sizeX, sizeY, 0, 0, 1, 1);
    }

    public static void drawPlane(double sizeX, double sizeY) {
        drawPlaneWithUV(0, 0, 0, sizeX, sizeY, 0, 0, 1, 1);
    }

    public static void drawPlaneWithUV(double sizeX, double sizeY, double uStart, double vStart, double uSize,
            double vSize) {
        drawPlaneWithUV(0, 0, 0, sizeX, sizeY, uStart, vStart, uSize, vSize);
    }

    public static void drawPlaneWithUV(double x, double y, double z, double sizeX, double sizeY, double uStart,
            double vStart, double uSize, double vSize) {
        Tessellator tessellator = Tessellator.instance;

        tessellator.startDrawingQuads();
        tessellator.addVertexWithUV(x + sizeX, y + sizeY, z, uStart + uSize, vStart + vSize);
        tessellator.addVertexWithUV(x + sizeX, y, z, uStart + uSize, vStart);
        tessellator.addVertexWithUV(x, y, z, uStart, vStart);
        tessellator.addVertexWithUV(x, y + sizeY, z, uStart, vStart + vSize);
        tessellator.draw();
    }

    public static void drawPlaneWithUV(double x, double y, double z, double sizeX, double sizeY, double uStart,
            double vStart, double uSize, double vSize, int color) {
        Tessellator tessellator = Tessellator.instance;

        tessellator.startDrawingQuads();
        tessellator.setColorOpaque_I(color);
        tessellator.addVertexWithUV(x + sizeX, y + sizeY, z, uStart + uSize, vStart + vSize);
        tessellator.addVertexWithUV(x + sizeX, y, z, uStart + uSize, vStart);
        tessellator.addVertexWithUV(x, y, z, uStart, vStart);
        tessellator.addVertexWithUV(x, y + sizeY, z, uStart, vStart + vSize);
        tessellator.draw();
    }

    public static void drawStencil(int xMin, int yMin, int xMax, int yMax, int mask) {
        GL11.glDisable(GL_TEXTURE_2D);
        GL11.glStencilFunc(GL_ALWAYS, mask, mask);
        GL11.glStencilOp(0, 0, GL_REPLACE);
        GL11.glStencilMask(1);
        GL11.glColorMask(false, false, false, false);
        GL11.glDepthMask(false);
        Tessellator.instance.startDrawingQuads();
        Tessellator.instance.addVertex((double) xMin, (double) yMax, 0.0D);
        Tessellator.instance.addVertex((double) xMax, (double) yMax, 0.0D);
        Tessellator.instance.addVertex((double) xMax, (double) yMin, 0.0D);
        Tessellator.instance.addVertex((double) xMin, (double) yMin, 0.0D);
        Tessellator.instance.draw();
        GL11.glEnable(GL_TEXTURE_2D);
        GL11.glStencilFunc(GL_EQUAL, mask, mask);
        GL11.glStencilMask(0);
        GL11.glColorMask(true, true, true, true);
        GL11.glDepthMask(true);
    }

    public static void drawCube(double sizeX, double sizeY, double sizeZ, Color color) {
        drawCube(0, 0, 0, sizeX, sizeY, sizeZ, color);
    }

    public static void drawCube(double sizeX, double sizeY, double sizeZ, Color color, float multiply) {
        drawCube(0, 0, 0, sizeX, sizeY, sizeZ, new Color((int) (color.getIntR() * multiply),
                (int) (color.getIntG() * multiply), (int) (color.getIntB() * multiply)));
    }

    public static void drawCube(double x, double y, double z, double sizeX, double sizeY, double sizeZ,
            Color color) {
        drawCube(x, y, z, sizeX, sizeY, sizeZ, 0, 0, 1, 1, color);
    }

    public static void drawCube(double x, double y, double z, double sizeX, double sizeY, double sizeZ, double minU,
            double minV, double maxU, double maxV, Color color) {
        Tessellator tessellator = Tessellator.instance;

        tessellator.startDrawingQuads();
        if (color != null)
            tessellator.setColorRGBA(color.getIntR(), color.getIntG(), color.getIntB(), color.getIntA());
        //tessellator.setBrightness(255);

        //base
        tessellator.addVertexWithUV(x, y, z, minU, minV);
        tessellator.addVertexWithUV(x + sizeX, y, z, maxU, minV);
        tessellator.addVertexWithUV(x + sizeX, y, z + sizeZ, maxU, maxV);
        tessellator.addVertexWithUV(x, y, z + sizeZ, minU, maxV);

        //top
        tessellator.addVertexWithUV(x + sizeX, y + sizeY, z, maxU, minV);
        tessellator.addVertexWithUV(x, y + sizeY, z, minU, minV);
        tessellator.addVertexWithUV(x, y + sizeY, z + sizeZ, minU, maxV);
        tessellator.addVertexWithUV(x + sizeX, y + sizeY, z + sizeZ, maxU, maxV);

        //west
        tessellator.addVertexWithUV(x, y, z, minU, minV);
        tessellator.addVertexWithUV(x, y, z + sizeZ, maxU, minV);
        tessellator.addVertexWithUV(x, y + sizeY, z + sizeZ, maxU, maxV);
        tessellator.addVertexWithUV(x, y + sizeY, z, minU, maxV);

        //east
        tessellator.addVertexWithUV(x + sizeX, y, z + sizeZ, maxU, minV);
        tessellator.addVertexWithUV(x + sizeX, y, z, minU, minV);
        tessellator.addVertexWithUV(x + sizeX, y + sizeY, z, minU, maxV);
        tessellator.addVertexWithUV(x + sizeX, y + sizeY, z + sizeZ, maxU, maxV);

        //north
        tessellator.addVertexWithUV(x, y, z, minU, minV);
        tessellator.addVertexWithUV(x, y + sizeY, z, minU, maxV);
        tessellator.addVertexWithUV(x + sizeX, y + sizeY, z, maxU, maxV);
        tessellator.addVertexWithUV(x + sizeX, y, z, maxU, minV);

        //south
        tessellator.addVertexWithUV(x, y + sizeY, z + sizeZ, minU, maxV);
        tessellator.addVertexWithUV(x, y, z + sizeZ, minU, minV);
        tessellator.addVertexWithUV(x + sizeX, y, z + sizeZ, maxU, minV);
        tessellator.addVertexWithUV(x + sizeX, y + sizeY, z + sizeZ, maxU, maxV);

        tessellator.draw();
    }

    public static void tesseleteModelAsBlock(Matrix4f mat, GroupObject object, IIcon icon, int x, int y, int z,
            int brightness, boolean lighting, Color color) {
        float uSize = icon.getMaxU() - icon.getMinU();
        float vSize = icon.getMaxV() - icon.getMinV();
        float textureOffset = 0.00005F;
        Vector4f pos = new Vector4f(0, 0, 0, 1);

        for (Face face : object.faces) {
            if (face.faceNormal == null) {
                face.faceNormal = face.calculateFaceNormal();
            }
            float averageU = 0F;
            float averageV = 0F;

            if ((face.textureCoordinates != null) && (face.textureCoordinates.length > 0)) {
                for (int i = 0; i < face.textureCoordinates.length; ++i) {
                    averageU += face.textureCoordinates[i].u;
                    averageV += face.textureCoordinates[i].v;
                }

                averageU = averageU / face.textureCoordinates.length;
                averageV = averageV / face.textureCoordinates.length;
            }

            float offsetU, offsetV;

            for (int i = 0; i < face.vertices.length; ++i) {

                if ((face.textureCoordinates != null) && (face.textureCoordinates.length > 0)) {
                    offsetU = textureOffset;
                    offsetV = textureOffset;

                    if (face.textureCoordinates[i].u > averageU) {
                        offsetU = -offsetU;
                    }
                    if (face.textureCoordinates[i].v > averageV) {
                        offsetV = -offsetV;
                    }

                    pos.x = face.vertices[i].x;
                    pos.y = face.vertices[i].y;
                    pos.z = face.vertices[i].z;
                    pos.w = 1;
                    Matrix4f.transform(mat, pos, pos);

                    Tessellator.instance.setNormal(face.faceNormal.x, face.faceNormal.y, face.faceNormal.z);
                    float colorMul = 1f;
                    if (lighting) {
                        colorMul = 0.7f + 0.3f * Vector3f.dot(
                                new Vector3f(face.faceNormal.x, face.faceNormal.y, face.faceNormal.z),
                                new Vector3f(-0.3f, 1, 0));
                    }
                    if (color != null) {
                        Tessellator.instance.setColorOpaque_F(color.getFloatR() * colorMul,
                                color.getFloatG() * colorMul, color.getFloatB() * colorMul);
                    } else {
                        Tessellator.instance.setColorOpaque_F(colorMul, colorMul, colorMul);
                    }
                    if (brightness >= 0) {
                        Tessellator.instance.setBrightness(brightness);
                    }
                    Tessellator.instance.addVertexWithUV(x + 0.5f + pos.x, y + pos.y, z + 0.5f + pos.z,
                            icon.getMinU() + face.textureCoordinates[i].u * uSize + offsetU,
                            icon.getMinV() + face.textureCoordinates[i].v * vSize + offsetV);
                } else {
                    Tessellator.instance.addVertex(x + face.vertices[i].x, y + face.vertices[i].y,
                            z + face.vertices[i].z);
                }
            }
        }
    }

    public static int lerp(int a, int b, float lerp) {
        int MASK1 = 0xff00ff;
        int MASK2 = 0x00ff00;

        int f2 = Math.round(256 * lerp);
        int f1 = Math.round(256 - f2);

        return (((((a & MASK1) * f1) + ((b & MASK1) * f2)) >> 8) & MASK1)
                | (((((a & MASK2) * f1) + ((b & MASK2) * f2)) >> 8) & MASK2);
    }

    public static Color lerp(Color a, Color b, float lerp) {
        return new Color(lerp(a.getIntR(), b.getIntR(), lerp), lerp(a.getIntG(), b.getIntG(), lerp),
                lerp(a.getIntB(), b.getIntB(), lerp), lerp(a.getIntA(), b.getIntA(), lerp));
    }

    public static void applyColor(int color) {
        glColor4f((float) (color >> 16 & 255) / 255f, (float) (color >> 8 & 255) / 255f,
                (float) (color >> 0 & 255) / 256f, (float) (color >> 24 & 255) / 255f);
    }

    public static void applyColor(Color color) {
        glColor3f(color.getFloatR(), color.getFloatG(), color.getFloatB());
    }

    public static void applyColorWithMultipy(Color color, float mul) {
        glColor3f(color.getFloatR() * mul, color.getFloatG() * mul, color.getFloatB() * mul);
    }

    public static void applyColorWithMultipy(int color, float mul) {
        glColor4f((float) ((color >> 16 & 255) / 255f) * mul, (float) ((color >> 8 & 255) / 255f) * mul,
                (float) ((color >> 0 & 255) / 256f) * mul, (float) (color >> 24 & 255) / 255f);
    }

    public static void applyColorWithAdd(Color color, float add) {
        glColor3f(color.getFloatR() + add, color.getFloatG() + add, color.getFloatB() + add);
    }

    public static void applyColorWithAlpha(Color color, float alphaMultiply) {
        glColor4f(color.getFloatR(), color.getFloatG(), color.getFloatB(), color.getFloatA() * alphaMultiply);
    }

    public static void applyColorWithAlpha(Color color) {
        glColor4f(color.getFloatR(), color.getFloatG(), color.getFloatB(), color.getFloatA());
    }

    public static void beginDrawinngBlockScreen(double x, double y, double z, ForgeDirection side, Color color,
            TileEntity entity) {
        beginDrawinngBlockScreen(x, y, z, side, color, entity, 0.05, 1);
    }

    public static void beginDrawinngBlockScreen(double x, double y, double z, ForgeDirection side, Color color,
            TileEntity entity, double offset, float glowAlpha) {
        glEnable(GL_BLEND);
        glDisable(GL_LIGHTING);
        disableLightmap();

        Vector3f dir = new Vector3f(side.offsetX, side.offsetY, side.offsetZ);
        Vector3f front = new Vector3f(0, 0, -1);
        Vector3f c = Vector3f.cross(front, dir, null);
        double omega = Math.acos(Vector3f.dot(front, dir));
        if (omega == Math.PI) {
            c.y = 1;
        }

        glPushMatrix();
        glTranslated(dir.x * (0.5 + offset), dir.y * (0.5 + offset), dir.z * (0.5 + offset));
        glTranslated(x + 0.5, y + 0.5, z + 0.5);
        glRotated(omega * (180 / Math.PI), c.x, c.y, c.z);
        glRotated(180, 0, 0, 1);
        glTranslated(-0.5, -0.5, 0);

        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);

        double multiply = (MOMathHelper.noise(entity.xCoord, entity.getWorldObj().getWorldTime() * 0.01,
                entity.zCoord) * 0.5 + 0.5) * glowAlpha;
        glColor3d(color.getFloatR() * multiply, color.getFloatG() * multiply, color.getFloatB() * multiply);
        Minecraft.getMinecraft().getTextureManager()
                .bindTexture(TileEntityRendererPatternMonitor.screenTextureGlow);
        RenderUtils.drawPlane(1);

        glTranslated(0, 0, -0.05);
        glColor3d(color.getFloatR() * 0.05f, color.getFloatG() * 0.05f, color.getFloatB() * 0.05f);
        Minecraft.getMinecraft().getTextureManager()
                .bindTexture(TileEntityRendererPatternMonitor.screenTextureBack);
        RenderUtils.drawPlane(1);
    }

    public static void drawScreenInfoWithGlobalAutoSize(String[] info, Color color, ForgeDirection side,
            int leftMargin, int rightMargin, float maxScaleFactor) {
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glPushMatrix();
        glTranslated(0, 0, -0.03);
        glScaled(0.01, 0.01, 0.01);
        int height = 0;
        int maxWidth = 0;

        int sizeX = 100 - leftMargin - rightMargin;
        int sizeY = 80;

        float scaleFactor = 1;

        for (int i = 0; i < info.length; i++) {
            if (maxWidth < fontRenderer.getStringWidth(info[i])) {
                maxWidth = fontRenderer.getStringWidth(info[i]);
            }
        }

        if (maxWidth > 0) {
            scaleFactor = MathHelper.clamp_float((float) sizeX / (float) maxWidth, 0.02f, maxScaleFactor);
        }

        for (int i = 0; i < info.length; i++) {
            int scaledHeight = (int) (fontRenderer.FONT_HEIGHT * scaleFactor);

            if (height + scaledHeight < sizeY) {
                height += scaledHeight;
            }
        }

        height = MathHelper.clamp_int(height, 0, sizeY);

        int yCount = 0;
        for (int i = 0; i < info.length; i++) {
            glPushMatrix();
            int scaledHeight = (int) (fontRenderer.FONT_HEIGHT * scaleFactor);

            if (yCount + scaledHeight < sizeY) {
                int width = fontRenderer.getStringWidth(info[i]);
                glTranslated(leftMargin + sizeX / 2, 50 + yCount + scaledHeight / 2 - height / 2, 0);
                glScaled(scaleFactor, scaleFactor, 0);
                fontRenderer.drawString(info[i], -width / 2, -fontRenderer.FONT_HEIGHT / 2, color.getColor());

            } else {
                glPopMatrix();
                break;
            }

            glPopMatrix();
            yCount += scaledHeight;
        }
        glPopMatrix();
    }

    public static void drawScreenInfoWithLocalAutoSize(String[] info, Color color, ForgeDirection side,
            int leftMargin, int rightMargin, float maxScaleFactor) {
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glPushMatrix();
        glTranslated(0, 0, -0.03);
        glScaled(0.01, 0.01, 0.01);
        int height = 0;
        int maxWidth = 0;

        int sizeX = 100 - leftMargin - rightMargin;
        int sizeY = 80;

        for (int i = 0; i < info.length; i++) {
            float scaleFactor = 1;
            int width = fontRenderer.getStringWidth(info[i]);
            if (width > 0) {
                scaleFactor = MathHelper.clamp_float((float) sizeX / (float) width, 0.02f, maxScaleFactor);
            }
            int scaledHeight = (int) (fontRenderer.FONT_HEIGHT * scaleFactor);

            if (maxWidth < fontRenderer.getStringWidth(info[i])) {
                maxWidth = fontRenderer.getStringWidth(info[i]);
            }

            if (height + scaledHeight < sizeY) {
                height += scaledHeight;
            }
        }

        height = MathHelper.clamp_int(height, 0, sizeY);

        int yCount = 0;
        for (int i = 0; i < info.length; i++) {

            glPushMatrix();
            float scaleFactor = 1;
            int width = fontRenderer.getStringWidth(info[i]);
            if (width > 0) {
                scaleFactor = MathHelper.clamp_float((float) sizeX / (float) width, 0.02f, maxScaleFactor);
            }
            int scaledHeight = (int) (fontRenderer.FONT_HEIGHT * scaleFactor);

            if (yCount + scaledHeight < sizeY) {
                glTranslated(leftMargin + sizeX / 2, 50 + yCount + scaledHeight / 2 - height / 2, 0);
                glScaled(scaleFactor, scaleFactor, 0);
                fontRenderer.drawString(info[i], -width / 2, -fontRenderer.FONT_HEIGHT / 2, color.getColor());

            } else {
                glPopMatrix();
                break;
            }

            glPopMatrix();
            yCount += scaledHeight;
        }
        glPopMatrix();
    }

    public static void endDrawinngBlockScreen() {
        glPopMatrix();
        glDisable(GL_BLEND);
        glEnable(GL_LIGHTING);
    }

    public static void disableLightmap() {
        lastLightMapX = OpenGlHelper.lastBrightnessX;
        lastLightMapY = OpenGlHelper.lastBrightnessY;
        OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
    }

    public static void enableLightmap() {
        OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, lastLightMapX, lastLightMapY);
    }

    public static void DrawMultilineInfo(List infos, int x, int y, int maxLines, int maxLineWidth, int color) {
        try {
            int linesCounter = 0;
            String infoText = StringUtils.join(infos, "\n");
            fontRenderer.drawSplitString(infoText, x, y + linesCounter * 10, maxLineWidth, color);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void DrawMultilineInfoCentered(List infos, int x, int y, int maxLines, int maxLineWidth,
            int color) {
        try {
            for (int i = 0; i < Math.min(maxLines, infos.size()); i++) {
                String info = infos.get(i).toString();
                info = info.substring(0, Math.min(maxLineWidth, info.length()));
                int width = fontRenderer.getStringWidth(info);
                fontRenderer.drawStringWithShadow(info, x - (width / 2), y + i * 10, color);
            }
        } catch (Exception e) {

        }
    }

    public static void bindTexture(ResourceLocation texture) {
        Minecraft.getMinecraft().getTextureManager().bindTexture(texture);
    }

    //From CodeChickenLib
    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;

        GL11.glTranslated(-interpPosX, -interpPosY, -interpPosZ);
    }

    public static void rotateTo(Entity viewer) {
        glRotated(viewer.rotationYaw, 0, -1, 0);
        glRotated(viewer.rotationPitch, 1, 0, 0);
    }

    public static void tessalateParticle(EntityLivingBase viewer, IIcon particleIcon, double scale, Vec3 position,
            Color color) {
        tessalateParticle(viewer, particleIcon, scale, position, color.getFloatR(), color.getFloatG(),
                color.getFloatB(), color.getFloatA());
    }

    public static void tessalateParticle(EntityLivingBase viewer, IIcon particleIcon, double scale, Vec3 position,
            float r, float g, float b, float a) {
        float f1 = MathHelper.cos(viewer.rotationYaw * 0.017453292F);
        float f2 = MathHelper.sin(viewer.rotationYaw * 0.017453292F);
        float f3 = -f2 * MathHelper.sin(viewer.rotationPitch * 0.017453292F);
        float f4 = f1 * MathHelper.sin(viewer.rotationPitch * 0.017453292F);
        float f5 = MathHelper.cos(viewer.rotationPitch * 0.017453292F);

        float uMin = particleIcon.getMinU();
        float uMax = particleIcon.getMaxU();
        float vMin = particleIcon.getMinV();
        float vMax = particleIcon.getMaxV();

        float x = (float) position.xCoord;
        float y = (float) position.yCoord;
        float z = (float) position.zCoord;
        Tessellator.instance.setColorRGBA_F(r, g, b, a);
        Tessellator.instance.addVertexWithUV((double) (x - f1 * scale - f3 * scale), (double) (y - f5 * scale),
                (double) (z - f2 * scale - f4 * scale), (double) uMax, (double) vMax);
        Tessellator.instance.addVertexWithUV((double) (x - f1 * scale + f3 * scale), (double) (y + f5 * scale),
                (double) (z - f2 * scale + f4 * scale), (double) uMax, (double) vMin);
        Tessellator.instance.addVertexWithUV((double) (x + f1 * scale + f3 * scale), (double) (y + f5 * scale),
                (double) (z + f2 * scale + f4 * scale), (double) uMin, (double) vMin);
        Tessellator.instance.addVertexWithUV((double) (x + f1 * scale - f3 * scale), (double) (y - f5 * scale),
                (double) (z + f2 * scale - f4 * scale), (double) uMin, (double) vMax);
    }

    public static void enable3DRender() {
        GL11.glEnable(GL11.GL_LIGHTING);
        GL11.glEnable(GL11.GL_DEPTH_TEST);
        GL11.glDisable(GL11.GL_CULL_FACE);
    }

    public static void enable2DRender() {
        GL11.glDisable(GL11.GL_LIGHTING);
        GL11.glDisable(GL11.GL_DEPTH_TEST);
        GL11.glEnable(GL11.GL_CULL_FACE);
    }

    public static void drawSizedTexturedModalRect(int x, int y, int u, int v, int width, int height, int widthU,
            int heightV, float texW, float texH, float zLevel) {
        Tessellator.instance.startDrawingQuads();
        tessalateSizedModelRect(x, y, u, v, width, height, widthU, heightV, texW, texH, zLevel);
        Tessellator.instance.draw();
    }

    public static void tessalateSizedModelRect(int x, int y, int u, int v, int width, int height, int widthU,
            int heightV, float texW, float texH, float zLevel) {
        float texU = 1 / texW;
        float texV = 1 / texH;
        Tessellator.instance.addVertexWithUV(x, y + height, zLevel, u * texU, (v + heightV) * texV);
        Tessellator.instance.addVertexWithUV(x + width, y + height, zLevel, (u + widthU) * texU,
                (v + heightV) * texV);
        Tessellator.instance.addVertexWithUV(x + width, y, zLevel, (u + widthU) * texU, v * texV);
        Tessellator.instance.addVertexWithUV(x, y, zLevel, u * texU, v * texV);
    }

    public static void drawString(String string, int x, int y, Color color, float multiply) {
        drawString(Minecraft.getMinecraft().fontRenderer, string, x, y, color, multiply);
    }

    public static void drawString(FontRenderer fontRenderer, String string, int x, int y, Color color,
            float multiply) {
        fontRenderer.drawString(string, x, y, color.multiplyWithoutAlpha(multiply).getColor());
    }

    public static void beginStencil() {
        glEnable(GL_STENCIL_TEST);
        glColorMask(false, false, false, false);
        glDepthMask(false);
        glStencilFunc(GL_ALWAYS, 1, 0xFF); // Set any stencil to 1
        glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
        glStencilMask(0xFF); // Write to stencil buffer
        glClear(GL_STENCIL_BUFFER_BIT);
    }

    public static void beginDrawingDepthMask() {
        glClear(GL_DEPTH_BUFFER_BIT);
        glClearDepth(1f);
        GL11.glDepthFunc(GL11.GL_LESS);
        glEnable(GL_DEPTH_TEST);
        glDepthMask(true);
        glColorMask(false, false, false, false);
        glDisable(GL_TEXTURE_2D);
    }

    public static void beginDepthMasking() {
        glEnable(GL_TEXTURE_2D);
        glDepthMask(false);
        glColorMask(true, true, true, true);
        GL11.glEnable(GL11.GL_DEPTH_TEST);
        GL11.glDepthFunc(GL11.GL_GREATER);
    }

    public static void endStencil() {
        glStencilFunc(GL_EQUAL, 1, 0xFF); // Pass test if stencil value is 1
        glStencilMask(0x00); // Don't write anything to stencil buffer
        glDepthMask(true); // Write to depth buffer
        glColorMask(true, true, true, true);
        glDisable(GL_STENCIL_TEST);
    }

    public static void endDepthMask() {
        glDepthFunc(GL_LEQUAL);
        glDepthMask(true);
        GL11.glDisable(GL11.GL_DEPTH_TEST);
    }

    public static void drawSizeableBackground(int left, int top, int width, int height, int texW, int texH,
            ResourceLocation texture, float zLevel, int chunkSize) {
        Minecraft.getMinecraft().renderEngine.bindTexture(texture);

        //topLeft
        drawSizedTexturedModalRect(left, top, 0, 0, chunkSize, chunkSize, chunkSize, chunkSize, 255, 255, zLevel);
        //top middle
        drawSizedTexturedModalRect(left + chunkSize, top, chunkSize, 0, width - chunkSize * 2, chunkSize,
                texW - chunkSize * 2, chunkSize, 255, 255, zLevel);
        //top right
        drawSizedTexturedModalRect(left + width - chunkSize, top, texW - chunkSize, 0, chunkSize, chunkSize,
                chunkSize, chunkSize, 255, 255, zLevel);
        //left middle
        drawSizedTexturedModalRect(left, top + chunkSize, 0, chunkSize, chunkSize, height - chunkSize * 2,
                chunkSize, texH - chunkSize * 2, 255, 255, zLevel);
        //right middle
        drawSizedTexturedModalRect(left + width - chunkSize, top + chunkSize, texW - chunkSize, chunkSize,
                chunkSize, height - chunkSize * 2, chunkSize, texH - chunkSize * 2, 255, 255, zLevel);
        //bottom left
        drawSizedTexturedModalRect(left, top + height - chunkSize, 0, texH - chunkSize, chunkSize, chunkSize,
                chunkSize, chunkSize, 255, 255, zLevel);
        //bottom right
        drawSizedTexturedModalRect(left + width - chunkSize, top + height - chunkSize, texW - chunkSize,
                texH - chunkSize, chunkSize, chunkSize, chunkSize, chunkSize, 255, 255, zLevel);
        //bottom middle
        drawSizedTexturedModalRect(left + chunkSize, top + height - chunkSize, chunkSize, texH - chunkSize,
                width - chunkSize * 2, chunkSize, texW - chunkSize * 2, chunkSize, 255, 255, zLevel);
        //midddle
        drawSizedTexturedModalRect(left + chunkSize, top + chunkSize, chunkSize, chunkSize, width - chunkSize * 2,
                height - chunkSize * 2, texW - chunkSize * 2, texH - chunkSize * 2, 255, 255, zLevel);
    }

    public static void drawSizeableVertical(int left, int top, int u, int v, int width, int height, int texW,
            int texH, ResourceLocation texture, float zLevel, int chunkSize) {
        Minecraft.getMinecraft().renderEngine.bindTexture(texture);

        //top
        drawSizedTexturedModalRect(left, top, u + 0, v + 0, width, v + chunkSize, width, chunkSize, texW, texH,
                zLevel);
        //middle
        drawSizedTexturedModalRect(left, top + chunkSize, u + 0, chunkSize, width, height - chunkSize * 2, width,
                texH - chunkSize * 2, texW, texH, zLevel);
        //bottom
        drawSizedTexturedModalRect(left, top + height - chunkSize, u + 0, v + texH - chunkSize, width, chunkSize,
                width, chunkSize, texW, texH, zLevel);
    }

    public static void drawSizeableHorizontal(int left, int top, int u, int v, int width, int height, int texW,
            int texH, ResourceLocation texture, float zLevel, int chunkSize) {
        Minecraft.getMinecraft().renderEngine.bindTexture(texture);

        //left
        drawSizedTexturedModalRect(left, top, u, v, chunkSize, height, chunkSize, height, texW, texH, zLevel);
        //middle
        drawSizedTexturedModalRect(left + chunkSize, top, u + chunkSize, v, width - chunkSize * 2, height,
                texW - chunkSize * 2, height, texW, texH, zLevel);
        //right
        drawSizedTexturedModalRect(left + width - chunkSize, top, u + texW - chunkSize, v, chunkSize, height,
                chunkSize, height, texW, texH, zLevel);
    }

    public static void drawShip(double x, double y, double z, double size) {
        Tessellator.instance.startDrawing(GL_TRIANGLES);
        Tessellator.instance.addVertex(x - size, y, z);
        Tessellator.instance.addVertex(x + size, y, z - size);
        Tessellator.instance.addVertex(x + size, y, z + size);

        Tessellator.instance.addVertex(x - size, y, z);
        Tessellator.instance.addVertex(x + size, y, z + size);
        Tessellator.instance.addVertex(x + size, y + size, z);

        Tessellator.instance.addVertex(x - size, y, z);
        Tessellator.instance.addVertex(x + size, y + size, z);
        Tessellator.instance.addVertex(x + size, y, z - size);

        Tessellator.instance.addVertex(x + size, y, z - size);
        Tessellator.instance.addVertex(x + size, y + size, z);
        Tessellator.instance.addVertex(x + size, y, z + size);
        Tessellator.instance.draw();
    }

    public static void rotateTowards(Vec3 from, Vec3 to, Vec3 up) {
        double dot = from.dotProduct(to);
        if (Math.abs(dot - (-1.0)) < Double.MIN_VALUE) {
            glRotated(180, up.xCoord, up.yCoord, up.zCoord);
        }
        if (Math.abs(dot - (1.0)) < Double.MIN_VALUE) {
            return;
        }

        double rotAngle = Math.acos(dot);
        Vec3 rotAxis = from.crossProduct(to).normalize();
        glRotated(rotAngle * (180d / Math.PI), rotAxis.xCoord, rotAxis.yCoord, rotAxis.zCoord);
    }

    public static void renderIcon(double x, double y, double z, IIcon icon, int width, int height) {
        Tessellator var9 = Tessellator.instance;
        var9.startDrawingQuads();
        var9.addVertexWithUV(x, y + (double) height, z, (double) icon.getMinU(), (double) icon.getMaxV());
        var9.addVertexWithUV(x + (double) width, y + (double) height, z, (double) icon.getMaxU(),
                (double) icon.getMaxV());
        var9.addVertexWithUV(x + (double) width, y, z, (double) icon.getMaxU(), (double) icon.getMinV());
        var9.addVertexWithUV(x, y, z, (double) icon.getMinU(), (double) icon.getMinV());
        var9.draw();
    }

    public static final void setBlockTextureSheet() {
        new ResourceLocation("textures/atlas/blocks.png");
    }
}