#include "stdafx.h"
#include "ItemInHandRenderer.h"
#include "TileRenderer.h"
#include "Tesselator.h"
#include "Textures.h"
#include "EntityRenderer.h"
#include "PlayerRenderer.h"
#include "EntityRenderDispatcher.h"
#include "Lighting.h"
#include "MultiplayerLocalPlayer.h"
#include "Minimap.h"
#include "MultiPlayerLevel.h"
#include "..\Minecraft.World\net.minecraft.world.item.h"
#include "..\Minecraft.World\net.minecraft.world.level.tile.h"
#include "..\Minecraft.World\net.minecraft.world.entity.h"
#include "..\Minecraft.World\net.minecraft.world.entity.player.h"
#include "..\Minecraft.World\net.minecraft.world.level.h"
#include "..\Minecraft.World\net.minecraft.world.h"

int ItemInHandRenderer::list = -1;
int ItemInHandRenderer::listGlint = -1;

ItemInHandRenderer::ItemInHandRenderer(Minecraft *mc, bool optimisedMinimap)
{
	// 4J - added
	height = 0;
	oHeight = 0;
	selectedItem = nullptr;
	tileRenderer = new TileRenderer();
	lastSlot = -1;

    this->mc = mc;
    minimap = new Minimap(mc->font, mc->options, mc->textures, optimisedMinimap);

	// 4J - replaced mesh that is used to render held items with individual cubes, so we can make it all join up properly without seams. This
	// has a lot more quads in it than the original, so is now precompiled with a UV matrix offset to put it in the final place for the
	// current icon. Compile it on demand for the first ItemInHandRenderer (list is static)
	if( list == -1 )
	{
		list = MemoryTracker::genLists(1);
		float dd = 1 / 16.0f;

		glNewList(list, GL_COMPILE);
		Tesselator *t = Tesselator::getInstance();
		t->begin();
		for( int yp = 0; yp < 16; yp++ )
			for( int xp = 0; xp < 16; xp++ )
			{
				float u = (15-xp) / 256.0f;
				float v = (15-yp) / 256.0f;
				u += 0.5f / 256.0f;
				v += 0.5f / 256.0f;
				float x0 = xp / 16.0f;
				float x1 = x0 + 1.0f/16.0f;
				float y0 = yp / 16.0f;
				float y1 = y0 + 1.0f/16.0f;
				float z0 = 0.0f;
				float z1 = -dd;

				t->normal(0, 0, 1);
				t->vertexUV(x0, y0, z0, u, v);
				t->vertexUV(x1, y0, z0, u, v);
				t->vertexUV(x1, y1, z0, u, v);
				t->vertexUV(x0, y1, z0, u, v);
				t->normal(0, 0, -1);
				t->vertexUV(x0, y1, z1, u, v);
				t->vertexUV(x1, y1, z1, u, v);
				t->vertexUV(x1, y0, z1, u, v);
				t->vertexUV(x0, y0, z1, u, v);
				t->normal(-1, 0, 0);
				t->vertexUV(x0, y0, z1, u, v);
				t->vertexUV(x0, y0, z0, u, v);
				t->vertexUV(x0, y1, z0, u, v);
				t->vertexUV(x0, y1, z1, u, v);
				t->normal(1, 0, 0);
				t->vertexUV(x1, y1, z1, u, v);
				t->vertexUV(x1, y1, z0, u, v);
				t->vertexUV(x1, y0, z0, u, v);
				t->vertexUV(x1, y0, z1, u, v);
				t->normal(0, 1, 0);
				t->vertexUV(x1, y0, z0, u, v);
				t->vertexUV(x0, y0, z0, u, v);
				t->vertexUV(x0, y0, z1, u, v);
				t->vertexUV(x1, y0, z1, u, v);
				t->normal(0, -1, 0);
				t->vertexUV(x1, y1, z1, u, v);
				t->vertexUV(x0, y1, z1, u, v);
				t->vertexUV(x0, y1, z0, u, v);
				t->vertexUV(x1, y1, z0, u, v);
			}					
		t->end();
		glEndList();
	}

	// Also create special object for glint overlays - this is the same as the previous one, with a different UV scalings, and depth test set to equal
	if( listGlint == -1 )
	{
		listGlint = MemoryTracker::genLists(1);
		float dd = 1 / 16.0f;

		glNewList(listGlint, GL_COMPILE);
		glDepthFunc(GL_EQUAL);
		Tesselator *t = Tesselator::getInstance();
		t->begin();
		for( int yp = 0; yp < 16; yp++ )
			for( int xp = 0; xp < 16; xp++ )
			{
				float u0 = (15-xp) / 16.0f;
				float v0 = (15-yp) / 16.0f;
				float u1 = u0 - (1.0f/16.0f);
				float v1 = v0 - (1.0f/16.0f);;

				float x0 = xp / 16.0f;
				float x1 = x0 + 1.0f/16.0f;
				float y0 = yp / 16.0f;
				float y1 = y0 + 1.0f/16.0f;
				float z0 = 0.0f;
				float z1 = -dd;

				float br = 0.76f;
				t->color(0.5f * br, 0.25f * br, 0.8f * br, 1.0f); // MGH - added the color here, as the glColour below wasn't making it through to render

				t->normal(0, 0, 1);
				t->vertexUV(x0, y0, z0, u0, v0);
				t->vertexUV(x1, y0, z0, u1, v0);
				t->vertexUV(x1, y1, z0, u1, v1);
				t->vertexUV(x0, y1, z0, u0, v1);
				t->normal(0, 0, -1);
				t->vertexUV(x0, y1, z1, u0, v1);
				t->vertexUV(x1, y1, z1, u1, v1);
				t->vertexUV(x1, y0, z1, u1, v0);
				t->vertexUV(x0, y0, z1, u0, v0);
				t->normal(-1, 0, 0);
				t->vertexUV(x0, y0, z1, u0, v0);
				t->vertexUV(x0, y0, z0, u0, v0);
				t->vertexUV(x0, y1, z0, u0, v1);
				t->vertexUV(x0, y1, z1, u0, v1);
				t->normal(1, 0, 0);
				t->vertexUV(x1, y1, z1, u1, v1);
				t->vertexUV(x1, y1, z0, u1, v1);
				t->vertexUV(x1, y0, z0, u1, v0);
				t->vertexUV(x1, y0, z1, u1, v0);
				t->normal(0, 1, 0);
				t->vertexUV(x1, y0, z0, u1, v0);
				t->vertexUV(x0, y0, z0, u0, v0);
				t->vertexUV(x0, y0, z1, u0, v0);
				t->vertexUV(x1, y0, z1, u1, v0);
				t->normal(0, -1, 0);
				t->vertexUV(x1, y1, z1, u1, v1);
				t->vertexUV(x0, y1, z1, u0, v1);
				t->vertexUV(x0, y1, z0, u0, v1);
				t->vertexUV(x1, y1, z0, u1, v1);
			}					
		t->end();
		glDepthFunc(GL_LEQUAL);
		glEndList();
	}

}

void ItemInHandRenderer::renderItem(shared_ptr<Mob> mob, shared_ptr<ItemInstance> item, int layer, bool setColor/* = true*/)
{
	// 4J - code borrowed from render method below, although not factoring in brightness as that should already be being taken into account
	// by texture lighting. This is for colourising things held in 3rd person view.
    if ( (setColor) && (item != NULL) )
	{
        int col = Item::items[item->id]->getColor(item,0);
        float red = ((col >> 16) & 0xff) / 255.0f;
        float g = ((col >> 8) & 0xff) / 255.0f;
        float b = ((col) & 0xff) / 255.0f;

        glColor4f(red, g, b, 1);
    }

    glPushMatrix();
	Tile *tile = Tile::tiles[item->id];
    if (item->getIconType() == Icon::TYPE_TERRAIN && tile != NULL && TileRenderer::canRender(tile->getRenderShape()))
	{
		MemSect(31);
        mc->textures->bindTexture(TN_TERRAIN);	// 4J was L"/terrain.png"
		MemSect(0);
        tileRenderer->renderTile(tile, item->getAuxValue(), SharedConstants::TEXTURE_LIGHTING ? 1.0f : mob->getBrightness(1));		// 4J - change brought forward from 1.8.2
    }
	else
	{
		MemSect(31);
		Icon *icon = mob->getItemInHandIcon(item, layer);
		if (icon == NULL)
		{
			glPopMatrix();
			MemSect(0);
			return;
		}

		if (item->getIconType() == Icon::TYPE_TERRAIN)
		{
            mc->textures->bindTexture(TN_TERRAIN);	// 4J was L"/terrain.png"
        }
		else
		{
            mc->textures->bindTexture(TN_GUI_ITEMS);	// 4J was L"/gui/items.png"
        }
		MemSect(0);
        Tesselator *t = Tesselator::getInstance();

		// Consider forcing the mipmap LOD level to use, if this is to be rendered from a larger than standard source texture. 
		int iconWidth = icon->getWidth();
		int LOD = -1;	// Default to not doing anything special with LOD forcing
		if( iconWidth == 32 )
		{
			LOD = 1;	// Force LOD level 1 to achieve texture reads from 256x256 map
		}
		else if( iconWidth == 64 )
		{
			LOD = 2;	// Force LOD level 2 to achieve texture reads from 256x256 map
		}
		RenderManager.StateSetForceLOD(LOD);

		// 4J Original comment
		// Yes, these are backwards.
		// No, I don't know why.
		// 4J Stu - Make them the right way round...u coords were swapped
		float u0 = icon->getU0();
		float u1 = icon->getU1();
		float v0 = icon->getV0();
		float v1 = icon->getV1();

        float xo = 0.0f;
        float yo = 0.3f;

        glEnable(GL_RESCALE_NORMAL);
        glTranslatef(-xo, -yo, 0);
        float s = 1.5f;
        glScalef(s, s, s);

        glRotatef(50, 0, 1, 0);
        glRotatef(45 + 290, 0, 0, 1);
        glTranslatef(-15 / 16.0f, -1 / 16.0f, 0);
        float dd = 1 / 16.0f;

        renderItem3D(t, u0, v0, u1, v1, icon->getSourceWidth(), icon->getSourceHeight(), 1 / 16.0f, false);

        if (item != NULL && item->isFoil() && layer == 0)
		{
            glDepthFunc(GL_EQUAL);
            glDisable(GL_LIGHTING);
            mc->textures->bind(mc->textures->loadTexture(TN__BLUR__MISC_GLINT)); // 4J was L"%blur%/misc/glint.png"
            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_COLOR, GL_ONE);
            float br = 0.76f;
			glColor4f(0.5f * br, 0.25f * br, 0.8f * br, 1);		// MGH - for some reason this colour isn't making it through to the render, so I've added to the tesselator for the glint geom above
             glMatrixMode(GL_TEXTURE);
             glPushMatrix();
             float ss = 1 / 8.0f;
             glScalef(ss, ss, ss);
             float sx = Minecraft::currentTimeMillis() % (3000) / (3000.0f) * 8;
             glTranslatef(sx, 0, 0);
             glRotatef(-50, 0, 0, 1);

            renderItem3D(t, 0, 0, 1, 1, 256, 256, 1 / 16.0f, true);
            glPopMatrix();
            glPushMatrix();
            glScalef(ss, ss, ss);
            sx = System::currentTimeMillis() % (3000 + 1873) / (3000 + 1873.0f) * 8;
            glTranslatef(-sx, 0, 0);
            glRotatef(10, 0, 0, 1);
            renderItem3D(t, 0, 0, 1, 1, 256, 256, 1 / 16.0f, true);
            glPopMatrix();
            glMatrixMode(GL_MODELVIEW);
            glDisable(GL_BLEND);
            glEnable(GL_LIGHTING);
            glDepthFunc(GL_LEQUAL);
        }

		RenderManager.StateSetForceLOD(-1);

        glDisable(GL_RESCALE_NORMAL);
    }
    glPopMatrix();
}

// 4J added useList parameter
void ItemInHandRenderer::renderItem3D(Tesselator *t, float u0, float v0, float u1, float v1, int width, int height, float depth, bool isGlint)
{
    float r = 1.0f;

	// 4J - replaced mesh that is used to render held items with individual cubes, so we can make it all join up properly without seams. This
	// has a lot more quads in it than the original, so is now precompiled with a UV matrix offset to put it in the final place for the
	// current icon

	if( isGlint )
	{
		glCallList(listGlint);
	}
	else
	{
		// 4J - replaced mesh that is used to render held items with individual cubes, so we can make it all join up properly without seams. This
		// has a lot more quads in it than the original, so is now precompiled with a UV matrix offset to put it in the final place for the
		// current icon

		glMatrixMode(GL_TEXTURE);
		glLoadIdentity();
		glTranslatef(u0, v0, 0);
		glCallList(list);
		glLoadIdentity();
		glMatrixMode(GL_MODELVIEW);
	}
	// 4J added since we are setting the colour to other values at the start of the function now
	glColor4f(1.0f,1.0f,1.0f,1.0f);
}

void ItemInHandRenderer::render(float a)
{
    float h = oHeight + (height - oHeight) * a;
    shared_ptr<Player> player = mc->player;

	// 4J - added so we can adjust the position of the hands for horizontal & vertical split screens
	float fudgeX = 0.0f;
	float fudgeY = 0.0f;
	float fudgeZ = 0.0f;
	bool splitHoriz = false;
	shared_ptr<LocalPlayer> localPlayer = dynamic_pointer_cast<LocalPlayer>(player);
	if( localPlayer )
	{
		if( localPlayer->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM ||
			localPlayer->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_TOP )
		{
			fudgeY = 0.08f;
			splitHoriz = true;
		}
		else if( localPlayer->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_LEFT ||
				 localPlayer->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT )
		{
			fudgeX = -0.18f;
		}
	}

    float xr = player->xRotO + (player->xRot - player->xRotO) * a;

    glPushMatrix();
    glRotatef(xr, 1, 0, 0);
    glRotatef(player->yRotO + (player->yRot - player->yRotO) * a, 0, 1, 0);
    Lighting::turnOn();
    glPopMatrix();

    if (localPlayer)
	{
        float xrr = localPlayer->xBobO + (localPlayer->xBob - localPlayer->xBobO) * a;
        float yrr = localPlayer->yBobO + (localPlayer->yBob - localPlayer->yBobO) * a;
		// 4J - was using player->xRot and yRot directly here rather than interpolating between old & current with a
		float yr = player->yRotO + (player->yRot - player->yRotO) * a;
        glRotatef((xr - xrr) * 0.1f, 1, 0, 0);
        glRotatef((yr - yrr) * 0.1f, 0, 1, 0);
    }

    shared_ptr<ItemInstance> item = selectedItem;

    float br = mc->level->getBrightness(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z));
	// 4J - change brought forward from 1.8.2
    if (SharedConstants::TEXTURE_LIGHTING)
	{
        br = 1;
        int col = mc->level->getLightColor(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z), 0);
        int u = col % 65536;
        int v = col / 65536;
        glMultiTexCoord2f(GL_TEXTURE1, u / 1.0f, v / 1.0f);
        glColor4f(1, 1, 1, 1);
    }
    if (item != NULL)
	{
        int col = Item::items[item->id]->getColor(item,0);
        float red = ((col >> 16) & 0xff) / 255.0f;
        float g = ((col >> 8) & 0xff) / 255.0f;
        float b = ((col) & 0xff) / 255.0f;

        glColor4f(br * red, br * g, br * b, 1);
    }
	else
	{
	    glColor4f(br, br, br, 1);
	}

    if (item != NULL && item->id == Item::map->id)
	{
        glPushMatrix();
        float d = 0.8f;

		// 4J - move the map away a bit if we're in horizontal split screen, so it doesn't clip out of the save zone
		if( splitHoriz )
		{
			glTranslatef(0.0f, 0.0f, -0.3f );
		}

        {
            float swing = player->getAttackAnim(a);

            float swing1 = Mth::sin(swing * PI);
            float swing2 = Mth::sin((sqrt(swing)) * PI);
            glTranslatef(-swing2 * 0.4f, Mth::sin(sqrt(swing) * PI * 2) * 0.2f, -swing1 * 0.2f);
        }

        float tilt = 1 - xr / 45.0f + 0.1f;
        if (tilt < 0) tilt = 0;
        if (tilt > 1) tilt = 1;
        tilt = -Mth::cos(tilt * PI) * 0.5f + 0.5f;

        glTranslatef(0.0f, 0.0f * d - (1 - h) * 1.2f - tilt * 0.5f + 0.04f, -0.9f * d);

        glRotatef(90, 0, 1, 0);
        glRotatef((tilt) * -85, 0, 0, 1);
        glEnable(GL_RESCALE_NORMAL);


        {
			// 4J-PB - if we've got a player texture, use that
           //glBindTexture(GL_TEXTURE_2D, mc->textures->loadHttpTexture(mc->player->customTextureUrl, mc->player->getTexture()));
		   glBindTexture(GL_TEXTURE_2D, mc->textures->loadMemTexture(mc->player->customTextureUrl, mc->player->getTexture()));
		   mc->textures->clearLastBoundId();
            for (int i = 0; i < 2; i++)
			{
                int flip = i * 2 - 1;
                glPushMatrix();

                glTranslatef(-0.0f, -0.6f, 1.1f * flip);
                glRotatef((float)(-45 * flip), 1, 0, 0);
                glRotatef(-90, 0, 0, 1);
                glRotatef(59, 0, 0, 1);
                glRotatef((float)(-65 * flip), 0, 1, 0);

                EntityRenderer *er = EntityRenderDispatcher::instance->getRenderer(mc->player);
                PlayerRenderer *playerRenderer = (PlayerRenderer *) er;
                float ss = 1;
                glScalef(ss, ss, ss);

				// Can't turn off the hand if the player is holding a map
				shared_ptr<ItemInstance> itemInstance = player->inventory->getSelected();
				if ((itemInstance && (itemInstance->getItem()->id==Item::map_Id)) || app.GetGameSettings(localPlayer->GetXboxPad(),eGameSetting_DisplayHand)!=0 )
                {
					playerRenderer->renderHand();
				}
                glPopMatrix();
            }
        }

        {
            float swing = player->getAttackAnim(a);
            float swing3 = Mth::sin(swing * swing * PI);
            float swing2 = Mth::sin(sqrt(swing) * PI);
            glRotatef(-swing3 * 20, 0, 1, 0);
            glRotatef(-swing2 * 20, 0, 0, 1);
            glRotatef(-swing2 * 80, 1, 0, 0);
        }

        float ss = 0.38f;
        glScalef(ss, ss, ss);

        glRotatef(90, 0, 1, 0);
        glRotatef(180, 0, 0, 1);

        glTranslatef(-1, -1, +0);

        float s = 2 / 128.0f;
        glScalef(s, s, s);

		MemSect(31);
        mc->textures->bindTexture(TN_MISC_MAPBG);	// 4J was L"/misc/mapbg.png"
		MemSect(0);
        Tesselator *t = Tesselator::getInstance();

//        glNormal3f(0, 0, -1);	// 4J - changed to use tesselator
        t->begin();
		int vo = 7;
		t->normal(0,0,-1);
        t->vertexUV((float)(0 - vo), (float)( 128 + vo), (float)( 0), (float)( 0), (float)( 1));
        t->vertexUV((float)(128 + vo), (float)( 128 + vo), (float)( 0), (float)( 1), (float)( 1));
        t->vertexUV((float)(128 + vo), (float)( 0 - vo), (float)( 0), (float)( 1), (float)( 0));
        t->vertexUV((float)(0 - vo), (float)( 0 - vo), (float)( 0), (float)( 0), (float)( 0));
        t->end();

        shared_ptr<MapItemSavedData> data = Item::map->getSavedData(item, mc->level);
		PIXBeginNamedEvent(0,"Minimap render");
		if(data != NULL) minimap->render(mc->player, mc->textures, data, mc->player->entityId);
		PIXEndNamedEvent();

        glPopMatrix();
    }
	else if (item != NULL)
	{
        glPushMatrix();
        float d = 0.8f;

#if defined __PS3__
		static const float swingPowFactor = 1.0f;
#else
		static const float swingPowFactor = 4.0f;		// 4J added, to slow the swing down when nearest the player for avoiding luminance flash issues
#endif
        if (player->getUseItemDuration() > 0)
		{
            UseAnim anim = item->getUseAnimation();
            if ( (anim == UseAnim_eat) || (anim == UseAnim_drink) )
			{
                float t = (player->getUseItemDuration() - a + 1);
                float swing = 1 - (t / item->getUseDuration());

                float is = 1 - swing;
                is = is * is * is;
                is = is * is * is;
                is = is * is * is;
                float iss = 1 - is;
                glTranslatef(0, Mth::abs(Mth::cos(t / 4 * PI) * 0.1f) * (swing > 0.2 ? 1 : 0), 0);
                glTranslatef(iss * 0.6f, -iss * 0.5f, 0);
                glRotatef(iss * 90, 0, 1, 0);
                glRotatef(iss * 10, 1, 0, 0);
                glRotatef(iss * 30, 0, 0, 1);
            }
        }
		else
		{
			float swing = powf(player->getAttackAnim(a),swingPowFactor);

			float swing1 = Mth::sin(swing * PI);
			float swing2 = Mth::sin((sqrt(swing)) * PI);
			glTranslatef(-swing2 * 0.4f, Mth::sin(sqrt(swing) * PI * 2) * 0.2f, -swing1 * 0.2f);

		}

        glTranslatef(0.7f * d, -0.65f * d - (1 - h) * 0.6f, -0.9f * d);
		glTranslatef(fudgeX, fudgeY, fudgeZ);	// 4J added

        glRotatef(45, 0, 1, 0);
        glEnable(GL_RESCALE_NORMAL);

		float swing = powf(player->getAttackAnim(a),swingPowFactor);
		float swing3 = Mth::sin(swing * swing * PI);
		float swing2 = Mth::sin(sqrt(swing) * PI);
		glRotatef(-swing3 * 20, 0, 1, 0);
		glRotatef(-swing2 * 20, 0, 0, 1);
		glRotatef(-swing2 * 80, 1, 0, 0);

        float ss = 0.4f;
        glScalef(ss, ss, ss);

        if (player->getUseItemDuration() > 0)
		{
            UseAnim anim = item->getUseAnimation();
            if (anim == UseAnim_block)
			{
                glTranslatef(-0.5f, 0.2f, 0.0f);
                glRotatef(30, 0, 1, 0);
                glRotatef(-80, 1, 0, 0);
                glRotatef(60, 0, 1, 0);
            }
			else if (anim == UseAnim_bow)
			{

                glRotatef(-18, 0, 0, 1);
                glRotatef(-12, 0, 1, 0);
                glRotatef(-8, 1, 0, 0);
                glTranslatef(-0.9f, 0.2f, 0.0f);
                float timeHeld = (item->getUseDuration() - (player->getUseItemDuration() - a + 1));
                float pow = timeHeld / (float) (BowItem::MAX_DRAW_DURATION);
                pow = ((pow * pow) + pow * 2) / 3;
                if (pow > 1) pow = 1;
                if (pow > 0.1f)
				{
                    glTranslatef(0, Mth::sin((timeHeld - 0.1f) * 1.3f) * 0.01f * (pow - 0.1f), 0);
                }
                glTranslatef(0, 0, pow * 0.1f);

                glRotatef(-45 - 290, 0, 0, 1);
                glRotatef(-50, 0, 1, 0);
                glTranslatef(0, 0.5f, 0);
                float ys = 1 + pow * 0.2f;
                glScalef(1, 1, ys);
                glTranslatef(0, -0.5f, 0);
                glRotatef(50, 0, 1, 0);
                glRotatef(45 + 290, 0, 0, 1);
            }
        }


        if (item->getItem()->isMirroredArt())
		{
            glRotatef(180, 0, 1, 0);
        }

        if (item->getItem()->hasMultipleSpriteLayers())
		{
            // special case for potions, refactor this when we get more
            // items that have two layers
            renderItem(player, item, 0, false);

			int col = Item::items[item->id]->getColor(item, 1);
			float red = ((col >> 16) & 0xff) / 255.0f;
			float g = ((col >> 8) & 0xff) / 255.0f;
			float b = ((col) & 0xff) / 255.0f;

			glColor4f(br * red, br * g, br * b, 1);

            renderItem(player, item, 1, false);
        }
		else
		{
            renderItem(player, item, 0, false);
        }
        glPopMatrix();
    }
	else if (!player->isInvisible())
	{
        glPushMatrix();
        float d = 0.8f;

        {
            float swing = player->getAttackAnim(a);

            float swing1 = Mth::sin(swing * PI);
            float swing2 = Mth::sin((sqrt(swing)) * PI);
            glTranslatef(-swing2 * 0.3f, Mth::sin(sqrt(swing) * PI * 2) * 0.4f, -swing1 * 0.4f);
        }

        glTranslatef(0.8f * d, -0.75f * d - (1 - h) * 0.6f, -0.9f * d);
		glTranslatef(fudgeX, fudgeY, fudgeZ);	// 4J added

        glRotatef(45, 0, 1, 0);
        glEnable(GL_RESCALE_NORMAL);
        {
            float swing = player->getAttackAnim(a);
            float swing3 = Mth::sin(swing * swing * PI);
            float swing2 = Mth::sin(sqrt(swing) * PI);
            glRotatef(swing2 * 70, 0, 1, 0);
            glRotatef(-swing3 * 20, 0, 0, 1);
        }

		// 4J-PB - if we've got a player texture, use that

		//glBindTexture(GL_TEXTURE_2D, mc->textures->loadHttpTexture(mc->player->customTextureUrl, mc->player->getTexture()));

		MemSect(31);
		glBindTexture(GL_TEXTURE_2D, mc->textures->loadMemTexture(mc->player->customTextureUrl, mc->player->getTexture()));
		MemSect(0);
		mc->textures->clearLastBoundId();
        glTranslatef(-1.0f, +3.6f, +3.5f);
        glRotatef(120, 0, 0, 1);
        glRotatef(180 + 20, 1, 0, 0);
        glRotatef(-90 - 45, 0, 1, 0);
        glScalef(1.5f / 24.0f * 16, 1.5f / 24.0f * 16, 1.5f / 24.0f * 16);
        glTranslatef(5.6f, 0, 0);

        EntityRenderer *er = EntityRenderDispatcher::instance->getRenderer(mc->player);
        PlayerRenderer *playerRenderer = (PlayerRenderer *) er;
        float ss = 1;
        glScalef(ss, ss, ss);
		MemSect(31);
		// Can't turn off the hand if the player is holding a map
		shared_ptr<ItemInstance> itemInstance = player->inventory->getSelected();

		if ( (itemInstance && (itemInstance->getItem()->id==Item::map_Id)) || app.GetGameSettings(localPlayer->GetXboxPad(),eGameSetting_DisplayHand)!=0 )
		{
			playerRenderer->renderHand();
		}
		MemSect(0);
        glPopMatrix();
    }

    glDisable(GL_RESCALE_NORMAL);
    Lighting::turnOff();

}

void ItemInHandRenderer::renderScreenEffect(float a)
{
    glDisable(GL_ALPHA_TEST);
    if (mc->player->isOnFire())
	{
		MemSect(31);
        mc->textures->bindTexture(TN_TERRAIN);	// 4J was L"/terrain.png"
		MemSect(0);
        renderFire(a);
    }


    if (mc->player->isInWall()) // Inside a tile
    {
        int x = Mth::floor(mc->player->x);
        int y = Mth::floor(mc->player->y);
        int z = Mth::floor(mc->player->z);

		MemSect(31);
        mc->textures->bindTexture(TN_TERRAIN);	// 4J was L"/terrain.png"
		MemSect(0);
        int tile = mc->level->getTile(x, y, z);
        if (mc->level->isSolidBlockingTile(x, y, z))
		{
            renderTex(a, Tile::tiles[tile]->getTexture(2));
        }
		else
		{
            for (int i = 0; i < 8; i++)
			{
                float xo = ((i >> 0) % 2 - 0.5f) * mc->player->bbWidth * 0.9f;
                float yo = ((i >> 1) % 2 - 0.5f) * mc->player->bbHeight * 0.2f;
                float zo = ((i >> 2) % 2 - 0.5f) * mc->player->bbWidth * 0.9f;
                int xt = Mth::floor(x + xo);
                int yt = Mth::floor(y + yo);
                int zt = Mth::floor(z + zo);
                if (mc->level->isSolidBlockingTile(xt, yt, zt))
				{
                    tile = mc->level->getTile(xt, yt, zt);
                }
            }
        }

        if (Tile::tiles[tile] != NULL) renderTex(a, Tile::tiles[tile]->getTexture(2));
    }

    if (mc->player->isUnderLiquid(Material::water))
	{
		MemSect(31);
        mc->textures->bindTexture(TN_MISC_WATER);	// 4J was L"/misc/water.png"
		MemSect(0);
        renderWater(a);
    }
    glEnable(GL_ALPHA_TEST);

}

void ItemInHandRenderer::renderTex(float a, Icon *slot)
{
    Tesselator *t = Tesselator::getInstance();

    float br = 0.1f;
    br = 0.1f;
    glColor4f(br, br, br, 0.5f);

    glPushMatrix();

    float x0 = -1;
    float x1 = +1;
    float y0 = -1;
    float y1 = +1;
    float z0 = -0.5f;

    float r = 2 / 256.0f;
    float u0 = slot->getU0();
    float u1 = slot->getU1();
    float v0 = slot->getV0();
    float v1 = slot->getV1();

    t->begin();
    t->vertexUV((float)(x0), (float)( y0), (float)( z0), (float)( u1), (float)( v1));
    t->vertexUV((float)(x1), (float)( y0), (float)( z0), (float)( u0), (float)( v1));
    t->vertexUV((float)(x1), (float)( y1), (float)( z0), (float)( u0), (float)( v0));
    t->vertexUV((float)(x0), (float)( y1), (float)( z0), (float)( u1), (float)( v0));
    t->end();
    glPopMatrix();

    glColor4f(1, 1, 1, 1);

}

void ItemInHandRenderer::renderWater(float a)
{
    Tesselator *t = Tesselator::getInstance();

    float br = mc->player->getBrightness(a);
    glColor4f(br, br, br, 0.5f);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glPushMatrix();

    float size = 4;

    float x0 = -1;
    float x1 = +1;
    float y0 = -1;
    float y1 = +1;
    float z0 = -0.5f;

    float uo = -mc->player->yRot / 64.0f;
    float vo = +mc->player->xRot / 64.0f;

    t->begin();
    t->vertexUV((float)(x0), (float)( y0), (float)( z0), (float)( size + uo), (float)( size + vo));
    t->vertexUV((float)(x1), (float)( y0), (float)( z0), (float)( 0 + uo), (float)( size + vo));
    t->vertexUV((float)(x1), (float)( y1), (float)( z0), (float)( 0 + uo), (float)( 0 + vo));
    t->vertexUV((float)(x0), (float)( y1), (float)( z0), (float)( size + uo), (float)( 0 + vo));
    t->end();
    glPopMatrix();

    glColor4f(1, 1, 1, 1);
    glDisable(GL_BLEND);

}

void ItemInHandRenderer::renderFire(float a)
{
    Tesselator *t = Tesselator::getInstance();
    glColor4f(1, 1, 1, 0.9f);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    float size = 1;
    for (int i = 0; i < 2; i++)
	{
        glPushMatrix();
		Icon *slot = Tile::fire->getTextureLayer(1);

		float u0 = slot->getU0(true);
		float u1 = slot->getU1(true);
		float v0 = slot->getV0(true);
		float v1 = slot->getV1(true);

        float x0 = (0 - size) / 2;
        float x1 = x0 + size;
        float y0 = 0 - size / 2;
        float y1 = y0 + size;
        float z0 = -0.5f;
        glTranslatef(-(i * 2 - 1) * 0.24f, -0.3f, 0);
        glRotatef((i * 2 - 1) * 10.0f, 0, 1, 0);

        t->begin();
        t->vertexUV((float)(x0), (float)( y0), (float)( z0), (float)( u1), (float)( v1));
        t->vertexUV((float)(x1), (float)( y0), (float)( z0), (float)( u0), (float)( v1));
        t->vertexUV((float)(x1), (float)( y1), (float)( z0), (float)( u0), (float)( v0));
        t->vertexUV((float)(x0), (float)( y1), (float)( z0), (float)( u1), (float)( v0));
        t->end();
        glPopMatrix();
    }
    glColor4f(1, 1, 1, 1);
    glDisable(GL_BLEND);

}

void ItemInHandRenderer::tick()
{
    oHeight = height;


    shared_ptr<Player> player = mc->player;
    shared_ptr<ItemInstance> nextTile = player->inventory->getSelected();

    bool matches = lastSlot == player->inventory->selected && nextTile == selectedItem;
    if (selectedItem == NULL && nextTile == NULL)
	{
        matches = true;
    }
    if (nextTile != NULL && selectedItem != NULL && nextTile != selectedItem && nextTile->id == selectedItem->id && nextTile->getAuxValue() == selectedItem->getAuxValue())
	{
        selectedItem = nextTile;
        matches = true;
    }

    float max = 0.4f;
    float tHeight = matches ? 1.0f : 0;
    float dd = tHeight - height;
    if (dd < -max) dd = -max;
    if (dd > max) dd = max;

    height += dd;
    if (height < 0.1f)
	{
        selectedItem = nextTile;
        lastSlot = player->inventory->selected;
    }

}

void ItemInHandRenderer::itemPlaced()
{
	height = 0;
}

void ItemInHandRenderer::itemUsed()
{
	height = 0;
}

