package client.renderer;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.List;
import java.util.function.Predicate;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;

import client.Client;
import client.renderer.particle.EffectRenderer;
import client.renderer.texture.DynamicTexture;
import client.renderer.texture.TextureMap;
import client.world.WorldClient;
import common.biome.Biome;
import common.block.Block;
import common.block.Material;
import common.entity.Entity;
import common.entity.npc.EntityNPC;
import common.entity.types.EntityAnimal;
import common.entity.types.EntityLiving;
import common.init.Blocks;
import common.init.Items;
import common.init.SoundEvent;
import common.model.BlockLayer;
import common.model.ParticleType;
import common.potion.Potion;
import common.rng.Random;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.util.ExtMath;
import common.util.HitPosition;
import common.util.Vec3;
import common.world.World;

public class EntityRenderer {
	private static final String locationMoltenPng = "textures/world/molten.png";
	private static final String locationRainPng = "textures/world/rain.png";
	private static final String locationHailPng = "textures/world/hail.png";
    private static final String locationSnowPng = "textures/world/snow.png";
    private static final String locationLightMap = "dynamic/lightmap";
    private static final float FOG_DENSITY = 0.05f;
    private static final float FOG_DISTANCE = 0.4f;
    private static final float SQRT_2 = ExtMath.sqrtf(2.0F);
    
    private Client gm;
    private Random random = new Random();
    private float farPlaneDistance;
    public final ItemRenderer itemRenderer;
    private int rendererUpdateCount;
    private Entity pointedEntity;
    private float thirdPersonDistance = 4.0F;
    private float thirdPersonDistanceTemp = 4.0F;
    private float fovModifierHand;
    private float fovModifierHandPrev;
    private final DynamicTexture lightmapTexture;
    private final int[] lightmapColors;
    private boolean lightmapUpdateNeeded;
    private float torchFlickerX;
    private float torchFlickerDX;
    private int rainSoundCounter;
    private float[] rainXCoords = new float[1024];
    private float[] rainYCoords = new float[1024];
    private FloatBuffer fogColorBuffer = ByteBuffer.allocateDirect(16 << 2).order(ByteOrder.nativeOrder()).asFloatBuffer();
    private float fogColorRed;
    private float fogColorGreen;
    private float fogColorBlue;
    private float lastFogMult;
    private float fogMult;
    private double cameraYaw;
    private double cameraPitch;
    private int frameCount;

    public EntityRenderer(Client gmIn)
    {
        this.frameCount = 0;
        this.gm = gmIn;
        this.itemRenderer = gmIn.getItemRenderer();
        this.lightmapTexture = new DynamicTexture(16, 16);
        gmIn.getTextureManager().loadTexture(locationLightMap, this.lightmapTexture);
        this.lightmapColors = this.lightmapTexture.getTextureData();

        for (int i = 0; i < 32; ++i)
        {
            for (int j = 0; j < 32; ++j)
            {
                float f = (float)(j - 16);
                float f1 = (float)(i - 16);
                float f2 = ExtMath.sqrtf(f * f + f1 * f1);
                this.rainXCoords[i << 5 | j] = -f1 / f2;
                this.rainYCoords[i << 5 | j] = f / f2;
            }
        }
    }

    /**
     * Updates the entity renderer
     */
    public void updateRenderer()
    {
//        if (/* OpenGl.SHADERS_SUPPORTED && */ ShaderLinkHelper.getStaticShaderLinkHelper() == null)
//        {
//            ShaderLinkHelper.setNewStaticShaderLinkHelper();
//        }

        this.updateFovModifierHand();
        this.updateTorchFlicker();
        this.lastFogMult = this.fogMult;
        this.thirdPersonDistanceTemp = this.thirdPersonDistance;

//        if (this.gm.smoothCamera)
//        {
//            float f = this.gm.mouseSensitivity * 0.6F + 0.2F;
//            float f1 = f * f * f * 8.0F;
//            this.smoothCamFilterX = this.mouseFilterXAxis.smooth(this.smoothCamYaw, 0.05F * f1);
//            this.smoothCamFilterY = this.mouseFilterYAxis.smooth(this.smoothCamPitch, 0.05F * f1);
//            this.smoothCamPartialTicks = 0.0F;
//            this.smoothCamYaw = 0.0F;
//            this.smoothCamPitch = 0.0F;
//        }
//        else
//        {
//            this.smoothCamFilterX = 0.0F;
//            this.smoothCamFilterY = 0.0F;
//            this.mouseFilterXAxis.reset();
//            this.mouseFilterYAxis.reset();
//        }

        if (this.gm.getRenderViewEntity() == null)
        {
            this.gm.setRenderViewEntity(this.gm.player);
        }

        float light = this.gm.world.getLightBrightness(new BlockPos(this.gm.getRenderViewEntity()));
//        Log.info(String.format("%.3f", light));
        float dist = (float)this.gm.renderDistance / 32.0F;
        float shift = light * (1.0F - dist) + dist;
        this.fogMult += (shift - this.fogMult) * 0.1F;
        ++this.rendererUpdateCount;
        this.itemRenderer.updateEquippedItem();
        this.addRainParticles();
//        this.bossColorModifierPrev = this.bossColorModifier;
//
//        if (BossStatus.hasColorModifier)
//        {
//            this.bossColorModifier += 0.05F;
//
//            if (this.bossColorModifier > 1.0F)
//            {
//                this.bossColorModifier = 1.0F;
//            }
//
//            BossStatus.hasColorModifier = false;
//        }
//        else if (this.bossColorModifier > 0.0F)
//        {
//            this.bossColorModifier -= 0.0125F;
//        }
    }

//    public ShaderGroup getShaderGroup()
//    {
//        return this.theShaderGroup;
//    }

//    public void updateShaderGroupSize(int width, int height)
//    {
////        if (OpenGl.SHADERS_SUPPORTED)
////        {
////            if (this.theShaderGroup != null)
////            {
////                this.theShaderGroup.createBindFramebuffers(width, height);
////            }
//
//            this.gm.renderGlobal.createBindEntityOutlineFbs(width, height);
////        }
//    }

    /**
     * Finds what block or object the mouse is over at the specified partial tick time. Args: partialTickTime
     */
    public void getMouseOver(float partialTicks)
    {
        Entity entity = this.gm.getRenderViewEntity();

        if (entity != null)
        {
            if (this.gm.world != null)
            {
                this.gm.setPointedEntity(null);
                double max = this.gm.player != null ? this.gm.player.getReachDistance() : 5.0;
                this.gm.pointed = entity.rayTrace(max, partialTicks);
                double dist = max;
                Vec3 eye = entity.getPositionEyes(partialTicks);
//                boolean far = false;
                int i = 3;

//                if (this.gm.controller.extendedReach())
//                {
                max += 1.0D;
                dist += 1.0D;
//                }
//                else
//                {
//                    if (max > 3.0D)
//                    {
//                        far = true;
//                    }
//                }

                if (this.gm.pointed != null)
                {
                    dist = this.gm.pointed.vec.distanceTo(eye);
                }

                Vec3 look = entity.getLook(partialTicks);
                Vec3 eyelook = eye.addVector(look.xCoord * max, look.yCoord * max, look.zCoord * max);
                this.pointedEntity = null;
                Vec3 hit = null;
                float exp = 1.0F;
                List<Entity> list = this.gm.world.getEntitiesInAABBexcluding(entity, entity.getEntityBoundingBox().addCoord(look.xCoord * max, look.yCoord * max, look.zCoord * max).expand((double)exp, (double)exp, (double)exp), new Predicate<Entity>()
                {
                    public boolean test(Entity p_apply_1_)
                    {
                        return p_apply_1_.canBeCollidedWith();
                    }
                });
                double edist = dist;

                for (int j = 0; j < list.size(); ++j)
                {
                    Entity entity1 = (Entity)list.get(j);
                    float f1 = entity1.getCollisionBorderSize();
                    BoundingBox axisalignedbb = entity1.getEntityBoundingBox().expand((double)f1, (double)f1, (double)f1);
                    HitPosition objpos = axisalignedbb.calculateIntercept(eye, eyelook);

                    if (axisalignedbb.isVecInside(eye))
                    {
                        if (edist >= 0.0D)
                        {
                            this.pointedEntity = entity1;
                            hit = objpos == null ? eye : objpos.vec;
                            edist = 0.0D;
                        }
                    }
                    else if (objpos != null)
                    {
                        double eyehit = eye.distanceTo(objpos.vec);

                        if (eyehit < edist || edist == 0.0D)
                        {
                            if (entity1 == entity.vehicle)
                            {
                                if (edist == 0.0D)
                                {
                                    this.pointedEntity = entity1;
                                    hit = objpos.vec;
                                }
                            }
                            else
                            {
                                this.pointedEntity = entity1;
                                hit = objpos.vec;
                                edist = eyehit;
                            }
                        }
                    }
                }

//                if (this.pointedEntity != null && far && eye.distanceTo(hit) > 3.0D)
//                {
//                    this.pointedEntity = null;
//                    this.gm.pointed = new MovingObjectPosition(MovingObjectPosition.MovingObjectType.MISS, hit, (EnumFacing)null, new BlockPos(hit));
//                }

                if (this.pointedEntity != null && (edist < dist || this.gm.pointed == null))
                {
                    this.gm.pointed = new HitPosition(this.pointedEntity, hit);

                    if (this.pointedEntity instanceof EntityLiving) // || this.pointedEntity instanceof EntityFrame)
                    {
                        this.gm.setPointedEntity(this.pointedEntity);
                    }
                }
            }
        }
    }

    /**
     * Update FOV modifier hand
     */
    private void updateFovModifierHand()
    {
        float f = 1.0F;

        if (this.gm.getRenderViewEntity() != null && this.gm.getRenderViewEntity().isPlayer())
        {
            EntityNPC player = (EntityNPC)this.gm.getRenderViewEntity();
            f = getFovModifier(player);
        }

        this.fovModifierHandPrev = this.fovModifierHand;
        this.fovModifierHand += (f - this.fovModifierHand) * 0.5F;

        if (this.fovModifierHand > 1.5F)
        {
            this.fovModifierHand = 1.5F;
        }

        if (this.fovModifierHand < 0.1F)
        {
            this.fovModifierHand = 0.1F;
        }
    }
    
    private static float getFovModifier(EntityNPC player)
    {
        float f = 1.0F;

//        if (player.flying)
//        {
//            f *= 1.1F;
//        }

//        AttributeInstance iattributeinstance = player.getEntityAttribute(Attributes.MOVEMENT_SPEED);
//        f = (float)((double)f * ((iattributeinstance.getAttributeValue() / 0.1D + 1.0D) / 2.0D));

//        if (Float.isNaN(f) || Float.isInfinite(f))
//        {
//            f = 1.0F;
//        }

        if (player.isUsingItem() && player.getItemInUse().getItem() == Items.bow)
        {
            int i = player.getItemInUseDuration();
            float f1 = (float)i / 20.0F;

            if (f1 > 1.0F)
            {
                f1 = 1.0F;
            }
            else
            {
                f1 = f1 * f1;
            }

            f *= 1.0F - f1 * 0.15F;
        }

        return f;
    }

    /**
     * Changes the field of view of the player depending on if they are underwater or not
     *  
     * @param useFOVSetting If true the FOV set in the settings will be use in the calculation
     */
    private float getFOVModifier(float partialTicks, boolean useFOVSetting)
    {
//        if (this.debugView)
//        {
//            return 90.0F;
//        }
//        else
//        {
        Entity entity = this.gm.getRenderViewEntity();
        float f = 70.0F;

        if (useFOVSetting)
        {
            f = this.gm.fov;
            if(this.gm.zooming) {
            	f /= this.gm.zoomLevel;
            }
            f = f * (this.fovModifierHandPrev + (this.fovModifierHand - this.fovModifierHandPrev) * partialTicks);
        }

        if (entity instanceof EntityLiving && ((EntityLiving)entity).getHealth() <= 0)
        {
            float f1 = (float)((EntityLiving)entity).deathTime + partialTicks;
            f /= (1.0F - 500.0F / (f1 + 500.0F)) * 2.0F + 1.0F;
        }

//            Block block = ActiveRenderInfo.getBlockAtEntityViewpoint(this.gm.theWorld, entity, partialTicks);
//
//            if (block.getMaterial().isColdLiquid())
//            {
//                f = f * 60.0F / 70.0F;
//            }

        return f;
//        }
    }

    private void hurtCameraEffect(float partialTicks)
    {
        if (this.gm.getRenderViewEntity() instanceof EntityLiving)
        {
            EntityLiving entitylivingbase = (EntityLiving)this.gm.getRenderViewEntity();
            float f = (float)entitylivingbase.hurtTime - partialTicks;

            if (entitylivingbase.getHealth() <= 0)
            {
                float f1 = (float)entitylivingbase.deathTime + partialTicks;
                GL11.glRotatef(40.0F - 8000.0F / (f1 + 200.0F), 0.0F, 0.0F, 1.0F);
            }

            if (f < 0.0F || entitylivingbase.hasEffect(Potion.STABILITY))
            {
                return;
            }

            f = f / (float)entitylivingbase.maxHurtTime;
            f = ExtMath.sin(f * f * f * f * (float)Math.PI);
            float f2 = entitylivingbase.attackedYaw;
            GL11.glRotatef(-f2, 0.0F, 1.0F, 0.0F);
            GL11.glRotatef(-f * 14.0F, 0.0F, 0.0F, 1.0F);
            GL11.glRotatef(f2, 0.0F, 1.0F, 0.0F);
        }
    }

    /**
     * Setups all the GL settings for view bobbing. Args: partialTickTime
     */
    private void setupViewBobbing(float partialTicks)
    {
        if (this.gm.getRenderViewEntity() != null && this.gm.getRenderViewEntity().isPlayer())
        {
            EntityNPC entityplayer = (EntityNPC)this.gm.getRenderViewEntity();
            float f = entityplayer.walkDistMod - entityplayer.prevWalkDistMod;
            float f1 = -(entityplayer.walkDistMod + f * partialTicks);
            float f2 = entityplayer.prevCameraYaw + (entityplayer.cameraYaw - entityplayer.prevCameraYaw) * partialTicks;
            float f3 = entityplayer.prevCamPitch + (entityplayer.camPitch - entityplayer.prevCamPitch) * partialTicks;
            GL11.glTranslatef(ExtMath.sin(f1 * (float)Math.PI) * f2 * 0.5F, -Math.abs(ExtMath.cos(f1 * (float)Math.PI) * f2), 0.0F);
            GL11.glRotatef(ExtMath.sin(f1 * (float)Math.PI) * f2 * 3.0F, 0.0F, 0.0F, 1.0F);
            GL11.glRotatef(Math.abs(ExtMath.cos(f1 * (float)Math.PI - 0.2F) * f2) * 5.0F, 1.0F, 0.0F, 0.0F);
            GL11.glRotatef(f3, 1.0F, 0.0F, 0.0F);
        }
    }

    /**
     * sets up player's eye (or camera in third person mode)
     */
    private void orientCamera(float partialTicks)
    {
        Entity entity = this.gm.getRenderViewEntity();
        float f = entity.getEyeHeight();
        double d0 = entity.prevX + (entity.posX - entity.prevX) * (double)partialTicks;
        double d1 = entity.prevY + (entity.posY - entity.prevY) * (double)partialTicks + (double)f;
        double d2 = entity.prevZ + (entity.posZ - entity.prevZ) * (double)partialTicks;

//        if (entity instanceof EntityLivingBase && ((EntityLivingBase)entity).isPlayerSleeping())
//        {
//            f = (float)((double)f + 1.0D);
//            SKC.glTranslatef(0.0F, 0.3F, 0.0F);
//
//            if (!this.gm.debugCamEnable)
//            {
//                BlockPos blockpos = new BlockPos(entity);
//                IBlockState iblockstate = this.gm.theWorld.getBlockState(blockpos);
//                Block block = iblockstate.getBlock();
//
//                if (block instanceof BlockBed)
//                {
//                    int j = ((EnumFacing)iblockstate.getValue(BlockBed.FACING)).getHorizontalIndex();
//                    SKC.glRotatef((float)(j * 90), 0.0F, 1.0F, 0.0F);
//                }
//
//                SKC.glRotatef(entity.prevYaw + (entity.rotYaw - entity.prevYaw) * partialTicks + 180.0F, 0.0F, -1.0F, 0.0F);
//                SKC.glRotatef(entity.prevPitch + (entity.rotPitch - entity.prevPitch) * partialTicks, -1.0F, 0.0F, 0.0F);
//            }
//        }
//        else
        if (this.gm.thirdPersonView > 0)
        {
            double d3 = (double)(this.thirdPersonDistanceTemp + (this.thirdPersonDistance - this.thirdPersonDistanceTemp) * partialTicks);

            if (this.gm.debugCamEnable)
            {
                GL11.glTranslatef(0.0F, 0.0F, (float)(-d3));
            }
            else
            {
                float f1 = entity.rotYaw;
                float f2 = entity.rotPitch;

                if (this.gm.thirdPersonView == 2)
                {
                    f2 += 180.0F;
                }

                double d4 = (double)(-ExtMath.sin(f1 / 180.0F * (float)Math.PI) * ExtMath.cos(f2 / 180.0F * (float)Math.PI)) * d3;
                double d5 = (double)(ExtMath.cos(f1 / 180.0F * (float)Math.PI) * ExtMath.cos(f2 / 180.0F * (float)Math.PI)) * d3;
                double d6 = (double)(-ExtMath.sin(f2 / 180.0F * (float)Math.PI)) * d3;

                for (int i = 0; i < 8; ++i)
                {
                    float f3 = (float)((i & 1) * 2 - 1);
                    float f4 = (float)((i >> 1 & 1) * 2 - 1);
                    float f5 = (float)((i >> 2 & 1) * 2 - 1);
                    f3 = f3 * 0.1F;
                    f4 = f4 * 0.1F;
                    f5 = f5 * 0.1F;
                    HitPosition movingobjectposition = this.gm.world.rayTraceBlocks(new Vec3(d0 + (double)f3, d1 + (double)f4, d2 + (double)f5), new Vec3(d0 - d4 + (double)f3 + (double)f5, d1 - d6 + (double)f4, d2 - d5 + (double)f5));

                    if (movingobjectposition != null)
                    {
                        double d7 = movingobjectposition.vec.distanceTo(new Vec3(d0, d1, d2));

                        if (d7 < d3)
                        {
                            d3 = d7;
                        }
                    }
                }

                if (this.gm.thirdPersonView == 2)
                {
                    GL11.glRotatef(180.0F, 0.0F, 1.0F, 0.0F);
                }

                GL11.glRotatef(entity.rotPitch - f2, 1.0F, 0.0F, 0.0F);
                GL11.glRotatef(entity.rotYaw - f1, 0.0F, 1.0F, 0.0F);
                GL11.glTranslatef(0.0F, 0.0F, (float)(-d3));
                GL11.glRotatef(f1 - entity.rotYaw, 0.0F, 1.0F, 0.0F);
                GL11.glRotatef(f2 - entity.rotPitch, 1.0F, 0.0F, 0.0F);
            }
        }
        else
        {
            GL11.glTranslatef(0.0F, 0.0F, -0.1F);
        }

        if (!this.gm.debugCamEnable || this.gm.thirdPersonView == 0)
        {
            GL11.glRotatef(entity.prevPitch + (entity.rotPitch - entity.prevPitch) * partialTicks, 1.0F, 0.0F, 0.0F);

            if (entity instanceof EntityAnimal)
            {
                EntityAnimal entityanimal = (EntityAnimal)entity;
                GL11.glRotatef(entityanimal.prevHeadYaw + (entityanimal.headYaw - entityanimal.prevHeadYaw) * partialTicks + 180.0F, 0.0F, 1.0F, 0.0F);
            }
            else
            {
                GL11.glRotatef(entity.prevYaw + (entity.rotYaw - entity.prevYaw) * partialTicks + 180.0F, 0.0F, 1.0F, 0.0F);
            }
        }

        GL11.glTranslatef(0.0F, -f, 0.0F);
        d0 = entity.prevX + (entity.posX - entity.prevX) * (double)partialTicks;
        d1 = entity.prevY + (entity.posY - entity.prevY) * (double)partialTicks + (double)f;
        d2 = entity.prevZ + (entity.posZ - entity.prevZ) * (double)partialTicks;
//        this.cloudFog = this.gm.renderGlobal.hasCloudFog(d0, d1, d2, partialTicks);
    }
    
    public void rotateCamera(Entity entity, float partialTicks) {
        GL11.glRotatef(360.0f - (entity.prevPitch + (entity.rotPitch - entity.prevPitch) * partialTicks), 1.0F, 0.0F, 0.0F);

        if (entity instanceof EntityAnimal)
        {
            EntityAnimal entityanimal = (EntityAnimal)entity;
            GL11.glRotatef(entityanimal.prevHeadYaw + (entityanimal.headYaw - entityanimal.prevHeadYaw) * partialTicks + 180.0F, 0.0F, 1.0F, 0.0F);
        }
        else
        {
            GL11.glRotatef(entity.prevYaw + (entity.rotYaw - entity.prevYaw) * partialTicks + 180.0F, 0.0F, 1.0F, 0.0F);
        }
    }

    /**
     * sets up projection, view effects, camera position/rotation
     */
    private void setupCameraTransform(float partialTicks)
    {
        this.farPlaneDistance = (float)(this.gm.renderDistance * 16);
        GL11.glMatrixMode(GL11.GL_PROJECTION);
        GL11.glLoadIdentity();
        float f = 0.07F;

//        if (this.gm.anaglyph)
//        {
//            SKC.glTranslatef((float)(-(pass * 2 - 1)) * f, 0.0F, 0.0F);
//        }

//        if (this.cameraZoom != 1.0D)
//        {
//            SKC.glTranslatef((float)this.cameraYaw, (float)(-this.cameraPitch), 0.0F);
//            SKC.glScaled(this.cameraZoom, this.cameraZoom, 1.0D);
//        }

        Project.gluPerspective(this.getFOVModifier(partialTicks, true), (float)this.gm.fb_raw_x / (float)this.gm.fb_raw_y, 0.05F, this.farPlaneDistance * SQRT_2);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glLoadIdentity();

//        if (this.gm.anaglyph)
//        {
//            SKC.glTranslatef((float)(pass * 2 - 1) * 0.1F, 0.0F, 0.0F);
//        }

        this.hurtCameraEffect(partialTicks);

//        if (this.gm.viewBobbing)
//        {
        this.setupViewBobbing(partialTicks);
//        }

//        float f1 = this.gm.thePlayer.prevNausea + (this.gm.thePlayer.nausea - this.gm.thePlayer.prevNausea) * partialTicks;
//
//        if (f1 > 0.0F)
//        {
//            int i = 7;
//
////            if (this.gm.thePlayer.hasEffect(Potion.confusion))
////            {
////                i = 7;
////            }
//
//            float f2 = 5.0F / (f1 * f1 + 5.0F) - f1 * 0.04F;
//            f2 = f2 * f2;
//            SKC.glRotatef(((float)this.rendererUpdateCount + partialTicks) * (float)i, 0.0F, 1.0F, 1.0F);
//            SKC.glScalef(1.0F / f2, 1.0F, 1.0F);
//            SKC.glRotatef(-((float)this.rendererUpdateCount + partialTicks) * (float)i, 0.0F, 1.0F, 1.0F);
//        }

        this.orientCamera(partialTicks);

//        if (this.debugView)
//        {
//            switch (this.debugViewDirection)
//            {
//                case 0:
//				SKC.glRotatef(90.0F, 0.0F, 1.0F, 0.0F);
//                    break;
//
//                case 1:
//				SKC.glRotatef(180.0F, 0.0F, 1.0F, 0.0F);
//                    break;
//
//                case 2:
//				SKC.glRotatef(-90.0F, 0.0F, 1.0F, 0.0F);
//                    break;
//
//                case 3:
//				SKC.glRotatef(90.0F, 1.0F, 0.0F, 0.0F);
//                    break;
//
//                case 4:
//				SKC.glRotatef(-90.0F, 1.0F, 0.0F, 0.0F);
//            }
//        }
    }

    /**
     * Render player hand
     */
    private void renderHand(float partialTicks)
    {
//        if (!this.debugView)
//        {
        GL11.glMatrixMode(GL11.GL_PROJECTION);
        GL11.glLoadIdentity();
        float f = 0.07F;

//            if (this.gm.anaglyph)
//            {
//                SKC.glTranslatef((float)(-(xOffset * 2 - 1)) * f, 0.0F, 0.0F);
//            }

        Project.gluPerspective(this.getFOVModifier(partialTicks, false), (float)this.gm.fb_raw_x / (float)this.gm.fb_raw_y, 0.05F, this.farPlaneDistance * 2.0F);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glLoadIdentity();

//            if (this.gm.anaglyph)
//            {
//                SKC.glTranslatef((float)(xOffset * 2 - 1) * 0.1F, 0.0F, 0.0F);
//            }

        GL11.glPushMatrix();
        this.hurtCameraEffect(partialTicks);

//            if (this.gm.viewBobbing)
//            {
        this.setupViewBobbing(partialTicks);
//            }

//            boolean flag = this.gm.getRenderViewEntity() instanceof EntityLivingBase && ((EntityLivingBase)this.gm.getRenderViewEntity()).isPlayerSleeping();

        if (this.gm.thirdPersonView == 0) // && /* !flag && */ !this.gm.hideGUI) // && !this.gm.controller.isSpectator())
        {
            this.enableLightmap();
            this.itemRenderer.renderItemInFirstPerson(partialTicks);
            this.disableLightmap();
        }

        GL11.glPopMatrix();

        if (this.gm.thirdPersonView == 0) // && !flag)
        {
            this.itemRenderer.renderOverlays(partialTicks);
            this.hurtCameraEffect(partialTicks);
        }

//            if (this.gm.viewBobbing)
//            {
        this.setupViewBobbing(partialTicks);
//            }
//        }
    }

    public void disableLightmap()
    {
        GlState.setActiveTexture(GL13.GL_TEXTURE1);
        GlState.disableTexture2D();
        GlState.setActiveTexture(GL13.GL_TEXTURE0);
    }

    public void enableLightmap()
    {
        GlState.setActiveTexture(GL13.GL_TEXTURE1);
        GL11.glMatrixMode(GL11.GL_TEXTURE);
        GL11.glLoadIdentity();
        float f = 0.00390625F;
        GL11.glScalef(f, f, f);
        GL11.glTranslatef(8.0F, 8.0F, 8.0F);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        this.gm.getTextureManager().bindTexture(locationLightMap);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
        GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
        GlState.enableTexture2D();
        GlState.setActiveTexture(GL13.GL_TEXTURE0);
    }

    /**
     * Recompute a random value that is applied to block color in updateLightmap()
     */
    private void updateTorchFlicker()
    {
        this.torchFlickerDX = (float)((double)this.torchFlickerDX + (Math.random() - Math.random()) * Math.random() * Math.random());
        this.torchFlickerDX = (float)((double)this.torchFlickerDX * 0.9D);
        this.torchFlickerX += (this.torchFlickerDX - this.torchFlickerX) * 1.0F;
        this.lightmapUpdateNeeded = true;
    }

    private void updateLightmap(float partialTicks)
    {
        if (this.lightmapUpdateNeeded)
        {
            WorldClient world = this.gm.world;

            if (world != null)
            {
                float sun = world.getSunBrightness(1.0F);
                float msun = sun * 0.95F + 0.05F;

                for (int n = 0; n < 256; ++n)
                {
                    float sky = World.BRIGHTNESS[world.dimension.getBrightness()][n / 16] * msun;
                    float block = World.BRIGHTNESS[world.dimension.getBrightness()][n % 16] * (this.torchFlickerX * 0.1F + 1.5F);

                    if (world.getLastLightning() > 0)
                    {
                        sky = World.BRIGHTNESS[world.dimension.getBrightness()][n / 16];
                    }

                    float sred = sky * (sun * 0.65F + 0.35F);
                    float sgreen = sky * (sun * 0.65F + 0.35F);
                    float bgreen = block * ((block * 0.6F + 0.4F) * 0.6F + 0.4F);
                    float bblue = block * (block * block * 0.6F + 0.4F);
                    float red = sred + block;
                    float green = sgreen + bgreen;
                    float blue = sky + bblue;
                    red = red * 0.96F + 0.03F;
                    green = green * 0.96F + 0.03F;
                    blue = blue * 0.96F + 0.03F;

//                    if (this.bossColorModifier > 0.0F)
//                    {
//                        float f11 = this.bossColorModifierPrev + (this.bossColorModifier - this.bossColorModifierPrev) * partialTicks;
//                        f8 = f8 * (1.0F - f11) + f8 * 0.7F * f11;
//                        f9 = f9 * (1.0F - f11) + f9 * 0.6F * f11;
//                        f10 = f10 * (1.0F - f11) + f10 * 0.6F * f11;
//                    }

//                    if (world.dimension.getDimensionId() == 1)
//                    {
//                        f8 = 0.22F + f3 * 0.75F;
//                        f9 = 0.28F + f6 * 0.75F;
//                        f10 = 0.25F + f7 * 0.75F;
//                    }

                    if (this.gm.player.hasEffect(Potion.NIGHT_VISION))
                    {
                        float vis = this.getNightVisionBrightness(this.gm.player, partialTicks);
                        float mult = 1.0F / red;

                        if (mult > 1.0F / green)
                        {
                            mult = 1.0F / green;
                        }

                        if (mult > 1.0F / blue)
                        {
                            mult = 1.0F / blue;
                        }

                        red = red * (1.0F - vis) + red * mult * vis;
                        green = green * (1.0F - vis) + green * mult * vis;
                        blue = blue * (1.0F - vis) + blue * mult * vis;
                    }

                    if (red > 1.0F)
                    {
                        red = 1.0F;
                    }

                    if (green > 1.0F)
                    {
                        green = 1.0F;
                    }

                    if (blue > 1.0F)
                    {
                        blue = 1.0F;
                    }

                    float bright = this.gm.setGamma || this.gm.xrayActive ? 100.0f : 0.1f;
                    float ri = 1.0F - red;
                    float gi = 1.0F - green;
                    float bi = 1.0F - blue;
                    ri = 1.0F - ri * ri * ri * ri;
                    gi = 1.0F - gi * gi * gi * gi;
                    bi = 1.0F - bi * bi * bi * bi;
                    red = red * (1.0F - bright) + ri * bright;
                    green = green * (1.0F - bright) + gi * bright;
                    blue = blue * (1.0F - bright) + bi * bright;
                    red = red * 0.96F + 0.03F;
                    green = green * 0.96F + 0.03F;
                    blue = blue * 0.96F + 0.03F;

                    if (red > 1.0F)
                    {
                        red = 1.0F;
                    }

                    if (green > 1.0F)
                    {
                        green = 1.0F;
                    }

                    if (blue > 1.0F)
                    {
                        blue = 1.0F;
                    }

                    if (red < 0.0F)
                    {
                        red = 0.0F;
                    }

                    if (green < 0.0F)
                    {
                        green = 0.0F;
                    }

                    if (blue < 0.0F)
                    {
                        blue = 0.0F;
                    }

                    int a = 255;
                    int r = (int)(red * 255.0F);
                    int g = (int)(green * 255.0F);
                    int b = (int)(blue * 255.0F);
                    this.lightmapColors[n] = a << 24 | r << 16 | g << 8 | b;
                }

                this.lightmapTexture.updateDynamicTexture();
                this.lightmapUpdateNeeded = false;
            }
        }
    }

    private float getNightVisionBrightness(EntityLiving entitylivingbaseIn, float partialTicks)
    {
        int i = entitylivingbaseIn.getEffect(Potion.NIGHT_VISION).getRemaining();
        return i > 200 ? 1.0F : 0.7F + ExtMath.sin(((float)i - partialTicks) * (float)Math.PI * 0.2F) * 0.3F;
    }

//    public void updateCameraAndRender(float partialTicks, long nanoTime)
//    {
//        if (this.gm.theWorld != null)
//        {
//            this.renderWorld(partialTicks, );

//            this.renderEndNanoTime = System.nanoTime();
//            if (!this.gm.hideGUI || this.gm.openGui != null)
//            {
//                this.gm.ingameGui.renderGameOverlay(partialTicks);
//            }
//        }
//        else
//        {
//            SKC.glMatrixMode(5889);
//            SKC.glLoadIdentity();
//            SKC.glMatrixMode(5888);
//            SKC.glLoadIdentity();
//            this.setupOverlayRendering();
//            this.renderEndNanoTime = System.nanoTime();
//        }
//    }

//    public void renderMainOverlay(float partialTicks)
//    {
//        this.setupOverlayRendering();
//        
//    }

    public void renderWorld(float partialTicks, long finishTimeNano)
    {
    	finishTimeNano = System.nanoTime() + Math.max((long)this.gm.maxBuildTime * 1000000L - finishTimeNano, 0L);
        this.updateLightmap(partialTicks);

        if (this.gm.getRenderViewEntity() == null)
        {
            this.gm.setRenderViewEntity(this.gm.player);
        }

        this.getMouseOver(partialTicks);
        GlState.enableDepth();
        GlState.enableAlpha();
        GlState.alphaFunc(GL11.GL_GREATER, 0.5F);

//        if (this.gm.anaglyph)
//        {
//            anaglyphField = 0;
//            GlState.colorMask(false, true, true, false);
//            this.renderWorldPass(0, partialTicks, finishTimeNano);
//            anaglyphField = 1;
//            GlState.colorMask(true, false, false, false);
//            this.renderWorldPass(1, partialTicks, finishTimeNano);
//            GlState.colorMask(true, true, true, false);
//        }
//        else
//        {
//        this.renderWorldPass(partialTicks, finishTimeNano);
//    }
//
//    private void renderWorldPass(float partialTicks, long finishTimeNano)
//    {
        RenderGlobal renderglobal = this.gm.renderGlobal;
        EffectRenderer effectrenderer = this.gm.effectRenderer;
        boolean flag = this.gm.getRenderViewEntity() != null && this.gm.getRenderViewEntity().isPlayer();
        GlState.enableCull();
        this.updateFogColor(partialTicks);
        GL11.glClear(16640);
        this.setupCameraTransform(partialTicks);
        ActiveRenderInfo.updateRenderInfo(this.gm.player, this.gm.thirdPersonView == 2);
        Entity entity = this.gm.getRenderViewEntity();
        double d0 = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * (double)partialTicks;
        double d1 = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * (double)partialTicks;
        double d2 = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * (double)partialTicks;
        Frustum.setPosition(d0, d1, d2);
        if (this.gm.renderDistance >= 4)
        {
            this.setupFog(-1, partialTicks);
            GL11.glMatrixMode(GL11.GL_PROJECTION);
            GL11.glLoadIdentity();
            Project.gluPerspective(this.getFOVModifier(partialTicks, true), (float)this.gm.fb_raw_x / (float)this.gm.fb_raw_y, 0.05F, this.farPlaneDistance * 2.0F);
            GL11.glMatrixMode(GL11.GL_MODELVIEW);
            renderglobal.renderSky(partialTicks);
            GL11.glMatrixMode(GL11.GL_PROJECTION);
            GL11.glLoadIdentity();
            Project.gluPerspective(this.getFOVModifier(partialTicks, true), (float)this.gm.fb_raw_x / (float)this.gm.fb_raw_y, 0.05F, this.farPlaneDistance * SQRT_2);
            GL11.glMatrixMode(GL11.GL_MODELVIEW);
        }

        this.setupFog(0, partialTicks);
        GlState.shadeModel(GL11.GL_SMOOTH);

        if (entity.posY + (double)entity.getEyeHeight() < (double)this.gm.world.dimension.getCloudHeight())
        {
            this.renderCloudsCheck(renderglobal, partialTicks);
        }
        this.setupFog(0, partialTicks);
        this.gm.getTextureManager().bindTexture(TextureMap.locationBlocksTexture);
        ItemRenderer.disableStandardItemLighting();
        renderglobal.setupTerrain(entity, (double)partialTicks, this.frameCount++, this.gm.player.noclip);
        this.gm.renderGlobal.updateChunks(finishTimeNano);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glPushMatrix();
        GlState.disableAlpha();
        renderglobal.renderBlockLayer(BlockLayer.SOLID, (double)partialTicks, entity);
        GlState.enableAlpha();
        renderglobal.renderBlockLayer(BlockLayer.CUTOUT_MIPPED, (double)partialTicks, entity);
//        this.gm.getTextureManager().getTexture(TextureMap.locationBlocksTexture).unsetMipmap();
        renderglobal.renderBlockLayer(BlockLayer.CUTOUT, (double)partialTicks, entity);
//        this.gm.getTextureManager().getTexture(TextureMap.locationBlocksTexture).restoreLastMipmap();
        GlState.shadeModel(GL11.GL_FLAT);
        GlState.alphaFunc(GL11.GL_GREATER, 0.1F);

//        if (!this.debugView)
//        {
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glPopMatrix();
        GL11.glPushMatrix();
        ItemRenderer.enableStandardItemLighting();
        renderglobal.renderEntities(entity, partialTicks);
        ItemRenderer.disableStandardItemLighting();
        this.disableLightmap();
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glPopMatrix();
        GL11.glPushMatrix();

        if (this.gm.pointed != null && entity.isInsideOfLiquid() && flag)
        {
            EntityNPC entityplayer = (EntityNPC)entity;
            GlState.disableAlpha();
            renderglobal.drawSelectionBox(entityplayer, this.gm.pointed, partialTicks);
            GlState.enableAlpha();
        }
//        }

        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glPopMatrix();

        if (flag && this.gm.pointed != null && !entity.isInsideOfLiquid())
        {
            EntityNPC entityplayer1 = (EntityNPC)entity;
            GlState.disableAlpha();
            renderglobal.drawSelectionBox(entityplayer1, this.gm.pointed, partialTicks);
            GlState.enableAlpha();
        }
        GlState.enableBlend();
        GlState.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ZERO);
//        this.gm.getTextureManager().getTexture(TextureMap.locationBlocksTexture).unsetMipmap();
//        Tessellator.getInstance();
		renderglobal.drawBlockDamageTexture(Tessellator.getBuffer(), entity, partialTicks);
//        this.gm.getTextureManager().getTexture(TextureMap.locationBlocksTexture).restoreLastMipmap();
        GlState.disableBlend();

//        if (!this.debugView)
//        {
        this.enableLightmap();
        effectrenderer.renderLitParticles(entity, partialTicks);
        ItemRenderer.disableStandardItemLighting();
        this.setupFog(0, partialTicks);
        effectrenderer.renderParticles(entity, partialTicks);
        this.disableLightmap();
//        }

        GlState.depthMask(false);
        GlState.enableCull();
        this.renderRainSnow(partialTicks);
        GlState.depthMask(true);
//        renderglobal.renderWorldBorder(entity, partialTicks);
        GlState.disableBlend();
        GlState.enableCull();
        GlState.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
        GlState.alphaFunc(GL11.GL_GREATER, 0.1F);
        this.setupFog(0, partialTicks);
        GlState.enableBlend();
        GlState.depthMask(false);
        this.gm.getTextureManager().bindTexture(TextureMap.locationBlocksTexture);
        GlState.shadeModel(GL11.GL_SMOOTH);
        renderglobal.renderBlockLayer(BlockLayer.TRANSLUCENT, (double)partialTicks, entity);
        GlState.shadeModel(GL11.GL_FLAT);
        GlState.depthMask(true);
        GlState.enableCull();
        GlState.disableBlend();
        GlState.disableFog();

        if (entity.posY + (double)entity.getEyeHeight() >= (double)this.gm.world.dimension.getCloudHeight())
        {
            this.renderCloudsCheck(renderglobal, partialTicks);
        }

//        if (this.renderHand)
//        {
        GL11.glClear(256);
        this.renderHand(partialTicks);
//        }
    }

    private void renderCloudsCheck(RenderGlobal renderGlobalIn, float partialTicks)
    {
		if (this.gm.renderDistance >= 4)
        {
            GL11.glMatrixMode(GL11.GL_PROJECTION);
            GL11.glLoadIdentity();
            Project.gluPerspective(this.getFOVModifier(partialTicks, true), (float)this.gm.fb_raw_x / (float)this.gm.fb_raw_y, 0.05F, this.farPlaneDistance * 4.0F);
            GL11.glMatrixMode(GL11.GL_MODELVIEW);
            GL11.glPushMatrix();
            this.setupFog(0, partialTicks);
//            renderGlobalIn.renderClouds(partialTicks);
            if(this.gm.world.dimension.getType().clouds)
            	renderGlobalIn.renderClouds(partialTicks);
            GlState.disableFog();
            GL11.glPopMatrix();
            GL11.glMatrixMode(GL11.GL_PROJECTION);
            GL11.glLoadIdentity();
            Project.gluPerspective(this.getFOVModifier(partialTicks, true), (float)this.gm.fb_raw_x / (float)this.gm.fb_raw_y, 0.05F, this.farPlaneDistance * SQRT_2);
            GL11.glMatrixMode(GL11.GL_MODELVIEW);
        }
    }

    private void addRainParticles()
    {
        float f = this.gm.world.getRainStrength();

//        if (this.gm.downfallSetting != 0)
//        {
//            f /= 2.0F;
//        }

        if (f != 0.0F) // && this.gm.downfallSetting < 2)
        {
            this.random.setSeed((long)this.rendererUpdateCount * 312987231L);
            Entity entity = this.gm.getRenderViewEntity();
            World world = this.gm.world;
            BlockPos blockpos = new BlockPos(entity);
            int i = 10;
            double d0 = 0.0D;
            double d1 = 0.0D;
            double d2 = 0.0D;
            int j = 0;
            int n = 0;
            int k = (int)(100.0F * f * f);

//            if (this.gm.particleSetting == 1)
//            {
//                k >>= 1;
//            }
//            else if (this.gm.particleSetting == 2)
//            {
//                k = 0;
//            }

//            boolean hail = !world.getWeather().isWet() && world.getWeather().hasDownfall();

            for (int l = 0; l < k; ++l)
            {
                BlockPos blockpos1 = world.getPrecipitationHeight(blockpos.add(this.random.zrange(i) - this.random.zrange(i), 0, this.random.zrange(i) - this.random.zrange(i)));
                Biome biomegenbase = world.getBiomeGenForCoords(blockpos1);
                BlockPos blockpos2 = blockpos1.down();
                Block block = world.getState(blockpos2).getBlock();
                float temp = World.ABSOLUTE_ZERO + world.getTempOffset() + biomegenbase.getTemperature(blockpos1);

                if (blockpos1.getY() <= blockpos.getY() + i && blockpos1.getY() >= blockpos.getY() - i && /* biomegenbase.canRain() && */ temp > 0.0F)
                {
                    double d3 = this.random.doublev();
                    double d4 = this.random.doublev();

                    if (temp >= 194.0f || block.getMaterial() == Material.LAVA)
                    {
                    	if(temp >= 194.0f) {
                    		++n;
                            if (this.random.zrange(n) == 0)
                            {
                                d0 = (double)blockpos2.getX() + d3;
                                d1 = (double)((float)blockpos2.getY() + 0.1F) + block.getBlockBoundsMaxY() - 1.0D;
                                d2 = (double)blockpos2.getZ() + d4;
                            }
                    	}
                    	if(temp < 194.0f || this.random.chance(5))
                    		this.gm.world.spawnParticle(temp >= 194.0f && this.random.chance(10) ? ParticleType.LAVA : ParticleType.SMOKE_NORMAL, (double)blockpos1.getX() + d3, (double)((float)blockpos1.getY() + 0.1F) - block.getBlockBoundsMinY(), (double)blockpos1.getZ() + d4, 0.0D, 0.0D, 0.0D);
                    }
                    else if (block != Blocks.air)
                    {
                        block.setBlockBoundsBasedOnState(world, blockpos2);
                        ++j;

                        if (this.random.zrange(j) == 0)
                        {
                            d0 = (double)blockpos2.getX() + d3;
                            d1 = (double)((float)blockpos2.getY() + 0.1F) + block.getBlockBoundsMaxY() - 1.0D;
                            d2 = (double)blockpos2.getZ() + d4;
                        }

                        this.gm.world.spawnParticle(temp <= 5.0f ? ParticleType.HAIL_CORN : ParticleType.WATER_DROP, (double)blockpos2.getX() + d3, (double)((float)blockpos2.getY() + 0.1F) + block.getBlockBoundsMaxY(), (double)blockpos2.getZ() + d4, 0.0D, 0.0D, 0.0D);
                    }
                }
            }

            if ((j > 0 || n > 0) && this.random.zrange(3) < this.rainSoundCounter++)
            {
                this.rainSoundCounter = 0;

                if (d1 > (double)(blockpos.getY() + 1) && world.getPrecipitationHeight(blockpos).getY() > ExtMath.floorf((float)blockpos.getY()))
                {
                    this.gm.world.playSound(d0, d1, d2, n >= j ? this.pickMoltenSound() : SoundEvent.RAIN, n >= j ? 0.2f : 0.1F);
                }
                else
                {
                    this.gm.world.playSound(d0, d1, d2, n >= j ? this.pickMoltenSound() : SoundEvent.RAIN, n >= j ? 0.4f : 0.2F);
                }
            }
        }
    }
    
    private SoundEvent pickMoltenSound() {
    	return this.random.chance(28) ? this.random.pick(SoundEvent.MOLTEN, SoundEvent.MOLTEN_POP) : SoundEvent.FIRE;
    }

    /**
     * Render rain and snow
     */
    protected void renderRainSnow(float partialTicks)
    {
        float f = this.gm.world.getRainStrength();

        if (f > 0.0F) // && this.gm.downfallSetting < 2)
        {
            this.enableLightmap();
            Entity entity = this.gm.getRenderViewEntity();
            World world = this.gm.world;
            int i = ExtMath.floord(entity.posX);
            int j = ExtMath.floord(entity.posY);
            int k = ExtMath.floord(entity.posZ);
//            Tessellator tessellator = Tessellator.getInstance();
            RenderBuffer worldrenderer = Tessellator.getBuffer();
            GlState.disableCull();
            GL11.glNormal3f(0.0F, 1.0F, 0.0F);
            GlState.enableBlend();
            GlState.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
            GlState.alphaFunc(GL11.GL_GREATER, 0.1F);
            double d0 = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * (double)partialTicks;
            double d1 = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * (double)partialTicks;
            double d2 = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * (double)partialTicks;
            int l = ExtMath.floord(d1);
            int i1 = 10;

//            if (this.gm.downfallSetting == 0)
//            {
//                i1 *= 2;
//            }

            int mode = -1;
            float f1 = (float)this.rendererUpdateCount + partialTicks;
            worldrenderer.setTranslation(-d0, -d1, -d2);
            GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
            BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
//            boolean hail = !world.getWeather().isWet() && world.getWeather().hasDownfall();

            for (int k1 = k - i1; k1 <= k + i1; ++k1)
            {
                for (int l1 = i - i1; l1 <= i + i1; ++l1)
                {
                    int i2 = (k1 - k + 16) * 32 + l1 - i + 16;
                    double d3 = (double)this.rainXCoords[i2] * 0.5D;
                    double d4 = (double)this.rainYCoords[i2] * 0.5D;
                    blockpos$mutableblockpos.set(l1, 0, k1);
                    Biome biomegenbase = world.getBiomeGenForCoords(blockpos$mutableblockpos);

//                    if (biomegenbase.canRain() || biomegenbase.isSnowyBiome())
//                    {
                    int j2 = world.getPrecipitationHeight(blockpos$mutableblockpos).getY();
                    int k2 = j - i1;
                    int l2 = j + i1;

                    if (k2 < j2)
                    {
                        k2 = j2;
                    }

                    if (l2 < j2)
                    {
                        l2 = j2;
                    }

                    int i3 = j2;

                    if (j2 < l)
                    {
                        i3 = l;
                    }

                    if (k2 != l2)
                    {
                        this.random.setSeed((long)(l1 * l1 * 3121 + l1 * 45238971 ^ k1 * k1 * 418711 + k1 * 13761));
                        blockpos$mutableblockpos.set(l1, k2, k1);
                        float f2 = World.ABSOLUTE_ZERO + world.getTempOffset() + biomegenbase.getTemperature(blockpos$mutableblockpos);

                        if(f2 >= 194.0f)
                        {
                        	if (mode != 2)
                            {
                                if (mode >= 0)
                                {
                                    Tessellator.draw();
                                }

                                mode = 2;
                                this.gm.getTextureManager().bindTexture(locationMoltenPng);
                                worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP);
                            }

                            double d5 = ((double)(this.rendererUpdateCount + l1 * l1 * 3121 + l1 * 45238971 + k1 * k1 * 418711 + k1 * 13761 & 63) + (double)partialTicks) / 64.0D * (3.0D + this.random.doublev());
                            double d6 = (double)((float)l1 + 0.5F) - entity.posX;
                            double d7 = (double)((float)k1 + 0.5F) - entity.posZ;
                            float f3 = ExtMath.sqrtd(d6 * d6 + d7 * d7) / (float)i1;
                            float f4 = ((1.0F - f3 * f3) * 0.5F + 0.5F) * f;
                            blockpos$mutableblockpos.set(l1, i3, k1);
                            int j3 = world.getCombinedLight(blockpos$mutableblockpos, 15);
                            int k3 = j3 >> 16 & 65535;
                            int l3 = j3 & 65535;
                            worldrenderer.pos((double)l1 - d3 + 0.5D, (double)k2, (double)k1 - d4 + 0.5D).tex(0.0D, (double)k2 * 0.25D + d5).color(1.0F, 1.0F, 1.0F, f4).lightmap(k3, l3).endVertex();
                            worldrenderer.pos((double)l1 + d3 + 0.5D, (double)k2, (double)k1 + d4 + 0.5D).tex(1.0D, (double)k2 * 0.25D + d5).color(1.0F, 1.0F, 1.0F, f4).lightmap(k3, l3).endVertex();
                            worldrenderer.pos((double)l1 + d3 + 0.5D, (double)l2, (double)k1 + d4 + 0.5D).tex(1.0D, (double)l2 * 0.25D + d5).color(1.0F, 1.0F, 1.0F, f4).lightmap(k3, l3).endVertex();
                            worldrenderer.pos((double)l1 - d3 + 0.5D, (double)l2, (double)k1 - d4 + 0.5D).tex(0.0D, (double)l2 * 0.25D + d5).color(1.0F, 1.0F, 1.0F, f4).lightmap(k3, l3).endVertex();
                        }
                        else if (/* world.getBiomeGenerator().getTemperatureAtHeight( */ f2 /* , j2) */ > 0.0F)
                        {
                            if (mode != (f2 <= 5.0f ? 3 : 0))
                            {
                                if (mode >= 0)
                                {
                                    Tessellator.draw();
                                }

                                mode = f2 <= 5.0f ? 3 : 0;
                                this.gm.getTextureManager().bindTexture(f2 <= 5.0f ? locationHailPng : locationRainPng);
                                worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP);
                            }

                            double d5 = ((double)(this.rendererUpdateCount + l1 * l1 * 3121 + l1 * 45238971 + k1 * k1 * 418711 + k1 * 13761 & 31) + (double)partialTicks) / 32.0D * (3.0D + this.random.doublev());
                            double d6 = (double)((float)l1 + 0.5F) - entity.posX;
                            double d7 = (double)((float)k1 + 0.5F) - entity.posZ;
                            float f3 = ExtMath.sqrtd(d6 * d6 + d7 * d7) / (float)i1;
                            float f4 = ((1.0F - f3 * f3) * 0.5F + 0.5F) * f;
                            blockpos$mutableblockpos.set(l1, i3, k1);
                            int j3 = world.getCombinedLight(blockpos$mutableblockpos, 0);
                            int k3 = j3 >> 16 & 65535;
                            int l3 = j3 & 65535;
                            worldrenderer.pos((double)l1 - d3 + 0.5D, (double)k2, (double)k1 - d4 + 0.5D).tex(0.0D, (double)k2 * 0.25D + d5).color(1.0F, 1.0F, 1.0F, f4).lightmap(k3, l3).endVertex();
                            worldrenderer.pos((double)l1 + d3 + 0.5D, (double)k2, (double)k1 + d4 + 0.5D).tex(1.0D, (double)k2 * 0.25D + d5).color(1.0F, 1.0F, 1.0F, f4).lightmap(k3, l3).endVertex();
                            worldrenderer.pos((double)l1 + d3 + 0.5D, (double)l2, (double)k1 + d4 + 0.5D).tex(1.0D, (double)l2 * 0.25D + d5).color(1.0F, 1.0F, 1.0F, f4).lightmap(k3, l3).endVertex();
                            worldrenderer.pos((double)l1 - d3 + 0.5D, (double)l2, (double)k1 - d4 + 0.5D).tex(0.0D, (double)l2 * 0.25D + d5).color(1.0F, 1.0F, 1.0F, f4).lightmap(k3, l3).endVertex();
                        }
                        else
                        {
                            if (mode != 1)
                            {
                                if (mode >= 0)
                                {
                                    Tessellator.draw();
                                }

                                mode = 1;
                                this.gm.getTextureManager().bindTexture(locationSnowPng);
                                worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP);
                            }

                            double d8 = (double)(((float)(this.rendererUpdateCount & 511) + partialTicks) / 512.0F);
                            double d9 = this.random.doublev() + (double)f1 * 0.01D * (double)((float)this.random.gaussian());
                            double d10 = this.random.doublev() + (double)(f1 * (float)this.random.gaussian()) * 0.001D;
                            double d11 = (double)((float)l1 + 0.5F) - entity.posX;
                            double d12 = (double)((float)k1 + 0.5F) - entity.posZ;
                            float f6 = ExtMath.sqrtd(d11 * d11 + d12 * d12) / (float)i1;
                            float f5 = ((1.0F - f6 * f6) * 0.3F + 0.5F) * f;
                            blockpos$mutableblockpos.set(l1, i3, k1);
                            int i4 = (world.getCombinedLight(blockpos$mutableblockpos, 0) * 3 + 15728880) / 4;
                            int j4 = i4 >> 16 & 65535;
                            int k4 = i4 & 65535;
                            worldrenderer.pos((double)l1 - d3 + 0.5D, (double)k2, (double)k1 - d4 + 0.5D).tex(0.0D + d9, (double)k2 * 0.25D + d8 + d10).color(1.0F, 1.0F, 1.0F, f5).lightmap(j4, k4).endVertex();
                            worldrenderer.pos((double)l1 + d3 + 0.5D, (double)k2, (double)k1 + d4 + 0.5D).tex(1.0D + d9, (double)k2 * 0.25D + d8 + d10).color(1.0F, 1.0F, 1.0F, f5).lightmap(j4, k4).endVertex();
                            worldrenderer.pos((double)l1 + d3 + 0.5D, (double)l2, (double)k1 + d4 + 0.5D).tex(1.0D + d9, (double)l2 * 0.25D + d8 + d10).color(1.0F, 1.0F, 1.0F, f5).lightmap(j4, k4).endVertex();
                            worldrenderer.pos((double)l1 - d3 + 0.5D, (double)l2, (double)k1 - d4 + 0.5D).tex(0.0D + d9, (double)l2 * 0.25D + d8 + d10).color(1.0F, 1.0F, 1.0F, f5).lightmap(j4, k4).endVertex();
                        }
                    }
//                    }
                }
            }

            if (mode >= 0)
            {
                Tessellator.draw();
            }

            worldrenderer.setTranslation(0.0D, 0.0D, 0.0D);
            GlState.enableCull();
            GlState.disableBlend();
            GlState.alphaFunc(GL11.GL_GREATER, 0.1F);
            this.disableLightmap();
        }
    }

    /**
     * Setup orthogonal projection for rendering GUI screen overlays
     */
//    public void setupOverlayRendering()
//    {
////        Scaler scaledresolution = new Scaler(this.gm);
//    }
    
//	/**
//	 * Returns a double value representing the Y value relative to the top of the
//	 * map at which void fog is at its maximum. The default factor of 0.03125
//	 * relative to 256, for example, means the void fog will be at its maximum at
//	 * (256*0.03125), or 8.
//	 */
//	public double getVoidFogYFactor() {
//		return 1.0D; // 0.03125D * 2.5D / (((double)this.worldObj.getSeaLevel() + 1) / 64.0);
//	}

    /**
     * calculates fog and calls glClearColor
     */
    private void updateFogColor(float partial)
    {
        WorldClient world = this.gm.world;
        Entity entity = this.gm.getRenderViewEntity();
        float dist = 0.25F + 0.75F * (float)this.gm.renderDistance / 32.0F;
        dist = 1.0F - (float)Math.pow((double)dist, 0.25D);
        Vec3 sky = world.getSkyColor(this.gm.getRenderViewEntity(), partial);
        float sr = (float)sky.xCoord;
        float sg = (float)sky.yCoord;
        float sb = (float)sky.zCoord;
        Vec3 fog = world.getFogColor(this.gm.getRenderViewEntity(), partial);
        this.fogColorRed = (float)fog.xCoord;
        this.fogColorGreen = (float)fog.yCoord;
        this.fogColorBlue = (float)fog.zCoord;

        if (this.gm.renderDistance >= 4)
        {
            double neg = -1.0D;
            Vec3 pos = ExtMath.sin(world.getCelestialAngleRadians(partial)) > 0.0F ? new Vec3(neg, 0.0D, 0.0D) : new Vec3(1.0D, 0.0D, 0.0D);
            float shift = (float)entity.getLook(partial).dotProduct(pos);

            if (shift < 0.0F)
            {
                shift = 0.0F;
            }

            if (shift > 0.0F)
            {
                float[] sun = world.dimension.getType().days ? 
                		RenderGlobal.calcSunriseSunsetColors(world.getCelestialAngle(partial), partial) : null;
                if (sun != null)
                {
                    shift = shift * sun[3];
                    this.fogColorRed = this.fogColorRed * (1.0F - shift) + sun[0] * shift;
                    this.fogColorGreen = this.fogColorGreen * (1.0F - shift) + sun[1] * shift;
                    this.fogColorBlue = this.fogColorBlue * (1.0F - shift) + sun[2] * shift;
                }
            }
        }

        this.fogColorRed += (sr - this.fogColorRed) * dist;
        this.fogColorGreen += (sg - this.fogColorGreen) * dist;
        this.fogColorBlue += (sb - this.fogColorBlue) * dist;
        float rain = world.getRainStrength();

        if (rain > 0.0F)
        {
            float rg = 1.0F - rain * 0.5F;
            float b = 1.0F - rain * 0.4F;
            this.fogColorRed *= rg;
            this.fogColorGreen *= rg;
            this.fogColorBlue *= b;
        }

        float dark = world.getDarkness();

        if (dark > 0.0F)
        {
            float mul = 1.0F - dark * 0.5F;
            this.fogColorRed *= mul;
            this.fogColorGreen *= mul;
            this.fogColorBlue *= mul;
        }

        Block block = ActiveRenderInfo.getBlockAtEntityViewpoint(this.gm.world, entity, partial);

//        if (this.cloudFog)
//        {
//            Vec3 cloud = world.getCloudColour(this.gm.getRenderViewEntity(), partial);
//            this.fogColorRed = (float)cloud.xCoord;
//            this.fogColorGreen = (float)cloud.yCoord;
//            this.fogColorBlue = (float)cloud.zCoord;
//        }
//        else
        if (block.getMaterial().isColdLiquid())
        {
            float cn = 0.4f; // (float)EnchantmentHelper.getRespiration(entity) * 0.2F;

//            if (entity instanceof EntityLivingBase && ((EntityLivingBase)entity).hasEffect(Potion.waterBreathing))
//            {
//                f12 = f12 * 0.3F + 0.6F;
//            }

            this.fogColorRed = 0.02F + cn;
            this.fogColorGreen = 0.02F + cn;
            this.fogColorBlue = 0.2F + cn;
        }
        else if (block.getMaterial().isHotLiquid())
        {
            this.fogColorRed = 0.6F;
            this.fogColorGreen = 0.1F;
            this.fogColorBlue = 0.0F;
        }

        float mult = this.lastFogMult + (this.fogMult - this.lastFogMult) * partial;
        this.fogColorRed *= mult;
        this.fogColorGreen *= mult;
        this.fogColorBlue *= mult;
        double vfog = (entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * (double)partial); // * world.dimension.getVoidFogYFactor();

        if (entity instanceof EntityLiving && ((EntityLiving)entity).hasEffect(Potion.BLINDNESS))
        {
            int blind = ((EntityLiving)entity).getEffect(Potion.BLINDNESS).getRemaining();

            if (blind < 20)
            {
                vfog *= (double)(1.0F - (float)blind / 20.0F);
            }
            else
            {
                vfog = 0.0D;
            }
        }

        if (vfog < 1.0D)
        {
            if (vfog < 0.0D)
            {
                vfog = 0.0D;
            }

            vfog = vfog * vfog;
            this.fogColorRed = (float)((double)this.fogColorRed * vfog);
            this.fogColorGreen = (float)((double)this.fogColorGreen * vfog);
            this.fogColorBlue = (float)((double)this.fogColorBlue * vfog);
        }

//        if (this.bossColorModifier > 0.0F)
//        {
//            float shift = this.bossColorModifierPrev + (this.bossColorModifier - this.bossColorModifierPrev) * partial;
//            this.fogColorRed = this.fogColorRed * (1.0F - shift) + this.fogColorRed * 0.7F * shift;
//            this.fogColorGreen = this.fogColorGreen * (1.0F - shift) + this.fogColorGreen * 0.6F * shift;
//            this.fogColorBlue = this.fogColorBlue * (1.0F - shift) + this.fogColorBlue * 0.6F * shift;
//        }

        if (entity instanceof EntityLiving && ((EntityLiving)entity).hasEffect(Potion.NIGHT_VISION))
        {
            float vis = this.getNightVisionBrightness((EntityLiving)entity, partial);
            float mul = 1.0F / this.fogColorRed;

            if (mul > 1.0F / this.fogColorGreen)
            {
                mul = 1.0F / this.fogColorGreen;
            }

            if (mul > 1.0F / this.fogColorBlue)
            {
                mul = 1.0F / this.fogColorBlue;
            }

            this.fogColorRed = this.fogColorRed * (1.0F - vis) + this.fogColorRed * mul * vis;
            this.fogColorGreen = this.fogColorGreen * (1.0F - vis) + this.fogColorGreen * mul * vis;
            this.fogColorBlue = this.fogColorBlue * (1.0F - vis) + this.fogColorBlue * mul * vis;
        }

//        if (this.gm.anaglyph)
//        {
//            float f16 = (this.fogColorRed * 30.0F + this.fogColorGreen * 59.0F + this.fogColorBlue * 11.0F) / 100.0F;
//            float f17 = (this.fogColorRed * 30.0F + this.fogColorGreen * 70.0F) / 100.0F;
//            float f7 = (this.fogColorRed * 30.0F + this.fogColorBlue * 70.0F) / 100.0F;
//            this.fogColorRed = f16;
//            this.fogColorGreen = f17;
//            this.fogColorBlue = f7;
//        }

        GlState.clearColor(this.fogColorRed, this.fogColorGreen, this.fogColorBlue, 0.0F);
    }

    /**
     * Sets up the fog to be rendered. If the arg passed in is -1 the fog starts at 0 and goes to 80% of far plane
     * distance and is used for sky rendering.
     *  
     * @param start If is -1 the fog start at 0.0
     */
    private void setupFog(int start, float partial)
    {
        Entity entity = this.gm.getRenderViewEntity();
        float fog = this.gm.world.getFogStrength();
        float distance = Math.min(0.995f, Math.max(0.005f, FOG_DISTANCE - (0.3f * fog)));
        float density = 1.0f - Math.min(1.0f, FOG_DENSITY * (1.0f - fog * 0.1f));
//        boolean flag = false;
//
//        if (entity.isPlayer())
//        {
//            flag = ((EntityNPC)entity).capabilities.isCreativeMode;
//        }

        GL11.glFogfv(GL11.GL_FOG_COLOR, (FloatBuffer)this.setFogColorBuffer(this.fogColorRed, this.fogColorGreen, this.fogColorBlue, 1.0F));
        GL11.glNormal3f(0.0F, -1.0F, 0.0F);
        GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
        Block block = ActiveRenderInfo.getBlockAtEntityViewpoint(this.gm.world, entity, partial);

        if(distance >= 1.0f) {
        	;
        }
        else if (entity instanceof EntityLiving && ((EntityLiving)entity).hasEffect(Potion.BLINDNESS))
        {
            float far = 5.0F;
            int effect = ((EntityLiving)entity).getEffect(Potion.BLINDNESS).getRemaining();

            if (effect < 20)
            {
                far = 5.0F + (this.farPlaneDistance - 5.0F) * (1.0F - (float)effect / 20.0F);
            }

            GlState.setFog(GL11.GL_LINEAR);

            if (start == -1)
            {
                GlState.setFogStart(0.0F);
                GlState.setFogEnd(far * 0.8F);
            }
            else
            {
                GlState.setFogStart(far * 0.25F);
                GlState.setFogEnd(far);
            }

//            if (GLContext.getCapabilities().GL_NV_fog_distance)
//            {
//                SKC.glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, NVFogDistance.GL_EYE_RADIAL_NV);
//            }
        }
//        else if (this.cloudFog)
//        {
//            GlState.setFog(SKC.GL_EXP);
//            GlState.setFogDensity(0.1F);
//        }
        else if (block.getMaterial().isColdLiquid())
        {
            GlState.setFog(GL11.GL_EXP);

//            if (entity instanceof EntityLivingBase && ((EntityLivingBase)entity).hasEffect(Potion.waterBreathing))
//            {
//                GlState.setFogDensity(0.01F);
//            }
//            else
//            {
            GlState.setFogDensity(0.04F); // - (float)EnchantmentHelper.getRespiration(entity) * 0.03F);
//            }
        }
        else if (block.getMaterial().isHotLiquid())
        {
            GlState.setFog(GL11.GL_EXP);
            GlState.setFogDensity(2.0F);
        }
        else
        {
            float far = this.farPlaneDistance;
            GlState.setFog(GL11.GL_LINEAR);

            if (start == -1)
            {
                GlState.setFogStart(0.0F);
                GlState.setFogEnd(far * Math.max(density * 2.0f, 0.01f));
            }
            else
            {
                GlState.setFogStart(far * distance);
                GlState.setFogEnd(far * Math.max(density * (distance / 0.75f) * 2.0f, distance + 0.01f));
            }

//            if (GLContext.getCapabilities().GL_NV_fog_distance)
//            {
//                SKC.glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, NVFogDistance.GL_EYE_RADIAL_NV);
//            }

            if (this.gm.world.dimension.hasDenseFog())
            {
                GlState.setFogStart(far * ((distance / 0.75f) * 0.05F));
                GlState.setFogEnd(Math.min(far, 192.0F) * Math.max(density * (distance / 0.75f), (distance / 0.75f) * 0.05F + 0.01f));
            }
        }

        GlState.enableColorMaterial();
        GlState.setFogEnabled(distance < 1.0f);
        GlState.colorMaterial(GL11.GL_FRONT, GL11.GL_AMBIENT);
    }

    /**
     * Update and return fogColorBuffer with the RGBA values passed as arguments
     */
    private FloatBuffer setFogColorBuffer(float red, float green, float blue, float alpha)
    {
        this.fogColorBuffer.clear();
        this.fogColorBuffer.put(red).put(green).put(blue).put(alpha);
        this.fogColorBuffer.flip();
        return this.fogColorBuffer;
    }

//    public MapItemRenderer getMapItemRenderer()
//    {
//        return this.theMapItemRenderer;
//    }
}
