#include "stdafx.h"
#include "..\..\Minecraft.h"
#include "..\..\ScreenSizeCalculator.h"
#include "..\..\EntityRenderDispatcher.h"
#include "..\..\PlayerRenderer.h"
#include "..\..\HumanoidModel.h"
#include "..\..\Lighting.h"
#include "..\..\..\Minecraft.World\Class.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.entity.player.h"
#include "XUI_Ctrl_MinecraftSkinPreview.h"
#include "XUI_Scene_AbstractContainer.h"
#include "XUI_Scene_Inventory.h"
#include "..\..\Options.h"
#include "..\..\stubs.h"
#include "..\..\ModelPart.h"

//#define SKIN_PREVIEW_BOB_ANIM
#define SKIN_PREVIEW_WALKING_ANIM

//-----------------------------------------------------------------------------
//  CXuiCtrlMinecraftSkinPreview class
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
CXuiCtrlMinecraftSkinPreview::CXuiCtrlMinecraftSkinPreview() :
	m_bDirty(FALSE),
	m_fScale(1.0f),
	m_fAlpha(1.0f)
{
	Minecraft *pMinecraft=Minecraft::GetInstance();

	ScreenSizeCalculator ssc(pMinecraft->options, pMinecraft->width_phys, pMinecraft->height_phys);
	m_fScreenWidth=(float)pMinecraft->width_phys;
	m_fRawWidth=(float)ssc.rawWidth;
	m_fScreenHeight=(float)pMinecraft->height_phys;
	m_fRawHeight=(float)ssc.rawHeight;

	m_customTextureUrl = L"default";
	m_backupTexture = TN_MOB_CHAR;
	m_capeTextureUrl = L"";

	m_yRot = 0;
	m_xRot = 0;

	m_swingTime = 0.0f;
	m_bobTick = 0.0f;
	m_walkAnimSpeedO = 0.0f;
	m_walkAnimSpeed = 0.0f;
	m_walkAnimPos = 0.0f;

	m_bAutoRotate = false;
	m_bRotatingLeft = false;

	m_incXRot = false;
	m_decXRot = false;
	m_incYRot = false;
	m_decYRot = false;

	m_currentAnimation = e_SkinPreviewAnimation_Walking;

	m_fTargetRotation = 0.0f;
	m_fOriginalRotation = 0.0f;
	m_framesAnimatingRotation = 0;
	m_bAnimatingToFacing = false;
	m_pvAdditionalModelParts=NULL;
	m_uiAnimOverrideBitmask=0L;
}

//-----------------------------------------------------------------------------
HRESULT CXuiCtrlMinecraftSkinPreview::OnInit(XUIMessageInit* pInitData, BOOL& rfHandled)
{
	HRESULT hr=S_OK;

	return hr;
}

void CXuiCtrlMinecraftSkinPreview::SetTexture(const wstring &url, TEXTURE_NAME backupTexture)
{
	m_customTextureUrl = url;
	m_backupTexture = backupTexture;

	unsigned int uiAnimOverrideBitmask = Player::getSkinAnimOverrideBitmask( app.getSkinIdFromPath(m_customTextureUrl) );

	if(app.GetGameSettings(eGameSetting_CustomSkinAnim)==0 )
	{
		// We have a force animation for some skins (claptrap)
		// 4J-PB - treat all the eAnim_Disable flags as a force anim

		if((uiAnimOverrideBitmask & HumanoidModel::m_staticBitmaskIgnorePlayerCustomAnimSetting)!=0)
		{
			m_uiAnimOverrideBitmask=uiAnimOverrideBitmask;
		}
		else
		{
			m_uiAnimOverrideBitmask=0;
		}
	}
	else
	{
		m_uiAnimOverrideBitmask = uiAnimOverrideBitmask;
	}

	app.DebugPrintf("+++ SetTexture - %d, %8x\n",app.getSkinIdFromPath(m_customTextureUrl)&0xFFFFFFF,m_uiAnimOverrideBitmask);
	m_pvAdditionalModelParts=app.GetAdditionalModelParts(app.getSkinIdFromPath(m_customTextureUrl));
}

void CXuiCtrlMinecraftSkinPreview::SetFacing(ESkinPreviewFacing facing, bool bAnimate /*= false*/)
{
	switch(facing)
	{
	case e_SkinPreviewFacing_Forward:
		m_fTargetRotation = 0;
		m_bRotatingLeft = true;
		break;
	case e_SkinPreviewFacing_Left:
		m_fTargetRotation = LOOK_LEFT_EXTENT;
		m_bRotatingLeft = false;
		break;
	case e_SkinPreviewFacing_Right:
		m_fTargetRotation = LOOK_RIGHT_EXTENT;
		m_bRotatingLeft = true;
		break;
	}

	if(!bAnimate)
	{
		m_yRot = m_fTargetRotation;
		m_bAnimatingToFacing = false;
	}
	else
	{
		m_fOriginalRotation = m_yRot;
		m_bAnimatingToFacing = true;
		m_framesAnimatingRotation = 0;
	}
}

void CXuiCtrlMinecraftSkinPreview::CycleNextAnimation()
{
	m_currentAnimation = (ESkinPreviewAnimations)(m_currentAnimation + 1);
	if(m_currentAnimation >= e_SkinPreviewAnimation_Count) m_currentAnimation = e_SkinPreviewAnimation_Walking;

	m_swingTime = 0.0f;
}

void CXuiCtrlMinecraftSkinPreview::CyclePreviousAnimation()
{
	m_currentAnimation = (ESkinPreviewAnimations)(m_currentAnimation - 1);	
	if(m_currentAnimation < e_SkinPreviewAnimation_Walking) m_currentAnimation = (ESkinPreviewAnimations)(e_SkinPreviewAnimation_Count - 1);

	m_swingTime = 0.0f;
}

HRESULT CXuiCtrlMinecraftSkinPreview::OnRender(XUIMessageRender *pRenderData, BOOL &bHandled )
{
	if( m_bAnimatingToFacing )
	{
		++m_framesAnimatingRotation;
		m_yRot = m_fOriginalRotation + m_framesAnimatingRotation * ( (m_fTargetRotation - m_fOriginalRotation) / CHANGING_SKIN_FRAMES );

		//if(m_framesAnimatingRotation == CHANGING_SKIN_FRAMES) m_bAnimatingToFacing = false;
	}
	else
	{
		if( m_incXRot ) IncrementXRotation();
		if( m_decXRot ) DecrementXRotation();
		if( m_incYRot ) IncrementYRotation();
		if( m_decYRot ) DecrementYRotation();

		if(m_bAutoRotate)
		{
			++m_rotateTick;

			if(m_rotateTick%4==0)
			{
				if(m_yRot >= LOOK_LEFT_EXTENT)
				{
					m_bRotatingLeft = false;
				}
				else if(m_yRot <= LOOK_RIGHT_EXTENT)
				{
					m_bRotatingLeft = true;
				}

				if(m_bRotatingLeft)
				{
					IncrementYRotation();
				}
				else
				{
					DecrementYRotation();
				}
			}
		}
	}

	HXUIDC hDC = pRenderData->hDC;

	// build and render with the game call

	RenderManager.Set_matrixDirty();

	Minecraft *pMinecraft=Minecraft::GetInstance();

	float alpha = 1.0f;
	//GetOpacity( &alpha );

	glColor4f(1, 1, 1, alpha);
	glClear(GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, m_fRawWidth, m_fRawHeight, 0, 1000, 3000);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslatef(0, 0, -2000);


	D3DXMATRIX matrix;
	GetFullXForm(&matrix);
	float bwidth,bheight;
	GetBounds(&bwidth,&bheight);

	float xo = ( (matrix._41 + ( (bwidth*matrix._11)/2) ) / m_fScreenWidth ) * m_fRawWidth;
	float yo = ( (matrix._42 + (bheight*matrix._22) ) / m_fScreenHeight ) * m_fRawHeight;

	glEnable(GL_RESCALE_NORMAL);
	glEnable(GL_COLOR_MATERIAL);

	glPushMatrix();
	glTranslatef(xo, yo - 3.5f, 50.0f);
	float ss;

	// Base scale on height of this control
	// Potentially we might want separate x & y scales here
	ss = ( ( (bheight*matrix._22) / m_fScreenHeight ) * m_fRawHeight )/2;

	glScalef(-ss, ss, ss);
	glRotatef(180, 0, 0, 1);

	//glRotatef(45 + 90, 0, 1, 0);
	Lighting::turnOn();
	//glRotatef(-45 - 90, 0, 1, 0);

	glRotatef(-(float)m_xRot, 1, 0, 0);

	// 4J Stu - Turning on hideGui while we do this stops the name rendering in split-screen
	bool wasHidingGui = pMinecraft->options->hideGui;
	pMinecraft->options->hideGui = true;

	//EntityRenderDispatcher::instance->render(pMinecraft->localplayers[0], 0, 0, 0, 0, 1);
	EntityRenderer *renderer = EntityRenderDispatcher::instance->getRenderer(eTYPE_PLAYER);
    if (renderer != NULL)
	{
		// 4J-PB - any additional parts to turn on for this player (skin dependent)
		//vector<ModelPart *> *pAdditionalModelParts=mob->GetAdditionalModelParts();
		
		if(m_pvAdditionalModelParts && m_pvAdditionalModelParts->size()!=0)
		{	
			for(AUTO_VAR(it, m_pvAdditionalModelParts->begin()); it != m_pvAdditionalModelParts->end(); ++it)
			{
				ModelPart *pModelPart=*it;

				pModelPart->visible=true;
			}
		}

		render(renderer,0,0,0,0,1);
        //renderer->postRender(entity, x, y, z, rot, a);

		// hide the additional parts
		if(m_pvAdditionalModelParts && m_pvAdditionalModelParts->size()!=0)
		{	
			for(AUTO_VAR(it, m_pvAdditionalModelParts->begin()); it != m_pvAdditionalModelParts->end(); ++it)
			{
				ModelPart *pModelPart=*it;

				pModelPart->visible=false;
			}
		}
    }

	pMinecraft->options->hideGui = wasHidingGui;

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

	XuiRenderRestoreState(hDC);

	bHandled = TRUE;

	return S_OK;
}

// 4J Stu - Modified version of MobRenderer::render that does not require an actual entity
void CXuiCtrlMinecraftSkinPreview::render(EntityRenderer *renderer, double x, double y, double z, float rot, float a)
{
    glPushMatrix();
    glDisable(GL_CULL_FACE);

	HumanoidModel *model = (HumanoidModel *)renderer->getModel();

   //getAttackAnim(mob, a);
    //if (armor != NULL) armor->attackTime = model->attackTime;
    //model->riding = mob->isRiding();
    //if (armor != NULL) armor->riding = model->riding;

	// 4J Stu - Remember to reset these values once the rendering is done if you add another one
	model->attackTime = 0;
	model->sneaking = false;
	model->holdingRightHand = false;
	model->holdingLeftHand = false;
	model->idle = false;
	model->eating = false;
	model->eating_swing = 0;
	model->eating_t = 0;
	model->young = false;
	model->riding = false;

	model->m_uiAnimOverrideBitmask = m_uiAnimOverrideBitmask;

	if( !m_bAnimatingToFacing )
	{
		switch( m_currentAnimation )
		{
			case e_SkinPreviewAnimation_Sneaking:
				model->sneaking = true;
				break;
			case e_SkinPreviewAnimation_Attacking:
				model->holdingRightHand = true;
				m_swingTime++;
				if (m_swingTime >= (Player::SWING_DURATION * 3) )
				{
					m_swingTime = 0;
				}
				model->attackTime = m_swingTime / (float) (Player::SWING_DURATION * 3);
				break;
			default:
				break;
		};
	}


    float bodyRot = m_yRot; //(mob->yBodyRotO + (mob->yBodyRot - mob->yBodyRotO) * a);
    float headRot = m_yRot; //(mob->yRotO + (mob->yRot - mob->yRotO) * a);
    float headRotx = 0; //(mob->xRotO + (mob->xRot - mob->xRotO) * a);
	
	//setupPosition(mob, x, y, z);
	// is equivalent to
	glTranslatef((float) x, (float) y, (float) z);

    //float bob = getBob(mob, a);
#ifdef SKIN_PREVIEW_BOB_ANIM
	float bob = (m_bobTick + a)/2;

	++m_bobTick;
	if(m_bobTick>=360*2) m_bobTick = 0;
#else
	float bob = 0.0f;
#endif

    //setupRotations(mob, bob, bodyRot, a);
	// is equivalent to
	glRotatef(180 - bodyRot, 0, 1, 0);

    float _scale = 1 / 16.0f;
    glEnable(GL_RESCALE_NORMAL);
    glScalef(-1, -1, 1);

    //scale(mob, a);
	// is equivalent to
	float s = 15 / 16.0f;
	glScalef(s, s, s);

    glTranslatef(0, -24 * _scale - 0.125f / 16.0f, 0);

#ifdef SKIN_PREVIEW_WALKING_ANIM
	m_walkAnimSpeedO = m_walkAnimSpeed;
	m_walkAnimSpeed += (0.1f - m_walkAnimSpeed) * 0.4f;
	m_walkAnimPos += m_walkAnimSpeed;
    float ws = m_walkAnimSpeedO + (m_walkAnimSpeed - m_walkAnimSpeedO) * a;
    float wp = m_walkAnimPos - m_walkAnimSpeed * (1 - a);
#else
    float ws = 0;
    float wp = 0;
#endif

    if (ws > 1) ws = 1;

	MemSect(31);
    bindTexture(m_customTextureUrl, m_backupTexture);
	MemSect(0);
    glEnable(GL_ALPHA_TEST);

    //model->prepareMobModel(mob, wp, ws, a);
    model->render(nullptr, wp, ws, bob, headRot - bodyRot, headRotx, _scale, true);
    /*for (int i = 0; i < MAX_ARMOR_LAYERS; i++)
	{
        if (prepareArmor(mob, i, a))
		{
            armor->render(wp, ws, bob, headRot - bodyRot, headRotx, _scale, true);
            glDisable(GL_BLEND);
            glEnable(GL_ALPHA_TEST);
        }
    }*/

    //additionalRendering(mob, a);
	if (bindTexture(m_capeTextureUrl, L"" ))
	{
        glPushMatrix();
        glTranslatef(0, 0, 2 / 16.0f);

        double xd = 0;//(mob->xCloakO + (mob->xCloak - mob->xCloakO) * a) - (mob->xo + (mob->x - mob->xo) * a);
        double yd = 0;//(mob->yCloakO + (mob->yCloak - mob->yCloakO) * a) - (mob->yo + (mob->y - mob->yo) * a);
        double zd = 0;//(mob->zCloakO + (mob->zCloak - mob->zCloakO) * a) - (mob->zo + (mob->z - mob->zo) * a);

        float yr = 1;//mob->yBodyRotO + (mob->yBodyRot - mob->yBodyRotO) * a;

        double xa = sin(yr * PI / 180);
        double za = -cos(yr * PI / 180);

        float flap = (float) yd * 10;
        if (flap < -6) flap = -6;
        if (flap > 32) flap = 32;
        float lean = (float) (xd * xa + zd * za) * 100;
        float lean2 = (float) (xd * za - zd * xa) * 100;
        if (lean < 0) lean = 0;

        //float pow = 1;//mob->oBob + (bob - mob->oBob) * a;

        flap += 1;//sin((mob->walkDistO + (mob->walkDist - mob->walkDistO) * a) * 6) * 32 * pow;
        if (model->sneaking)
		{
            flap += 25;
        }

        glRotatef(6.0f + lean / 2 + flap, 1, 0, 0);
        glRotatef(lean2 / 2, 0, 0, 1);
        glRotatef(-lean2 / 2, 0, 1, 0);
        glRotatef(180, 0, 1, 0);
        model->renderCloak(1 / 16.0f,true);
        glPopMatrix();
    }
	/*
    float br = mob->getBrightness(a);
    int overlayColor = getOverlayColor(mob, br, a);

    if (((overlayColor >> 24) & 0xff) > 0 || mob->hurtTime > 0 || mob->deathTime > 0)
	{
        glDisable(GL_TEXTURE_2D);
        glDisable(GL_ALPHA_TEST);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glDepthFunc(GL_EQUAL);

		// 4J - changed these renders to not use the compiled version of their models, because otherwise the render states set
		// about (in particular the depth & alpha test) don't work with our command buffer versions
        if (mob->hurtTime > 0 || mob->deathTime > 0)
		{
            glColor4f(br, 0, 0, 0.4f);
            model->render(wp, ws, bob, headRot - bodyRot, headRotx, _scale, false);
            for (int i = 0; i < MAX_ARMOR_LAYERS; i++)
			{
                if (prepareArmorOverlay(mob, i, a))
				{
                    glColor4f(br, 0, 0, 0.4f);
                    armor->render(wp, ws, bob, headRot - bodyRot, headRotx, _scale, false);
                }
            }
        }

        if (((overlayColor >> 24) & 0xff) > 0)
		{
            float r = ((overlayColor >> 16) & 0xff) / 255.0f;
            float g = ((overlayColor >> 8) & 0xff) / 255.0f;
            float b = ((overlayColor) & 0xff) / 255.0f;
            float aa = ((overlayColor >> 24) & 0xff) / 255.0f;
            glColor4f(r, g, b, aa);
            model->render(wp, ws, bob, headRot - bodyRot, headRotx, _scale, false);
            for (int i = 0; i < MAX_ARMOR_LAYERS; i++)
			{
                if (prepareArmorOverlay(mob, i, a))
				{
                    glColor4f(r, g, b, aa);
                    armor->render(wp, ws, bob, headRot - bodyRot, headRotx, _scale, false);
                }
            }
        }

        glDepthFunc(GL_LEQUAL);
        glDisable(GL_BLEND);
        glEnable(GL_ALPHA_TEST);
        glEnable(GL_TEXTURE_2D);
    }
	*/
    glDisable(GL_RESCALE_NORMAL);

    glEnable(GL_CULL_FACE);

    glPopMatrix();

	MemSect(31);
    //renderName(mob, x, y, z);
	MemSect(0);

	// Reset the model values to stop the changes we made here affecting anything in game (like the player hand render)
	model->attackTime = 0;
	model->sneaking = false;
	model->holdingRightHand = false;
	model->holdingLeftHand = false;
}

bool CXuiCtrlMinecraftSkinPreview::bindTexture(const wstring& urlTexture, int backupTexture)
{
    Textures *t = Minecraft::GetInstance()->textures;

	// 4J-PB - no http textures on the xbox, mem textures instead
	
	//int id = t->loadHttpTexture(urlTexture, backupTexture);
	int id = t->loadMemTexture(urlTexture, backupTexture);

	if (id >= 0)
	{
        t->bind(id);
        return true;
    }
	else
	{
        return false;
    }
}

bool CXuiCtrlMinecraftSkinPreview::bindTexture(const wstring& urlTexture, const wstring& backupTexture)
{
    Textures *t = Minecraft::GetInstance()->textures;

	// 4J-PB - no http textures on the xbox, mem textures instead
	
	//int id = t->loadHttpTexture(urlTexture, backupTexture);
	int id = t->loadMemTexture(urlTexture, backupTexture);

	if (id >= 0)
	{
        t->bind(id);
        return true;
    }
	else
	{
        return false;
    }
}