/**
* Model Blur Effect
* @version: 03-04-2005
* @author Joseph 'Pcjoe' Florencio
*/
#include "hud.h"
#include "parsemsg.h"
#include "const.h"
#include "cl_util.h"
#include "r_efx.h"
#include "pm_defs.h"
#include "pmtrace.h"
#include "event_api.h"
#include "com_model.h"
#include "StudioModelRenderer.h"
#include "GameStudioModelRenderer.h"
#include "mdlblur.h"
#include "bonerec.h"
#include "mdlcontrol.h"

extern CBoneManager gBoneManager;
extern CModelControlManager gModelControl;

CModelBlurManager gModelBlur;

/*
* Model Blur
*/
// Check
bool CModelBlur::Check( int idx )
{	if(idx == getIndex())
	{	return true;
	}
	return false;
}

// Think (create blurs at emit rate)
void CModelBlur::Think( float flTime )
{	float flNextEmit = getLastEmit() + getEmitRate();
	// Time to emit another model
	if(flTime > flNextEmit)
	{	// Set time
		setLastEmit(flTime);
		// Create blur
		createBlur();
	}
}

// Create Blur
void CModelBlur::createBlur( void )
{	// Get bone accessor
	CBoneAccessor *pAccessor = getBoneAccessor();
	if(!pAccessor)
	{	return;
	}

	// Get source entity
	cl_entity_t *pSourceEnt = NULL;
	if(pAccessor->getTempEntity())
		pSourceEnt = pAccessor->getTempEntity();
	else
		pSourceEnt = gEngfuncs.GetEntityByIndex( getIndex() );
	if(!pSourceEnt)
	{	return;
	}

	// Get model control (for frame)
	CMDLControl *pCtrl = gModelControl.findModelControl( getIndex() );

	TEMPENTITY *pTempEntity = gEngfuncs.pEfxAPI->CL_TempEntAlloc(pSourceEnt->origin, pSourceEnt->model);
	if(!pTempEntity)
	{	return;
	}

	// Set fade
	pTempEntity->die = getLastEmit() + getStayTime();
	pTempEntity->fadeSpeed = getFadeRate();
	pTempEntity->flags = FTENT_FADEOUT;

	// shorter code...
	cl_entity_t *pEntity = &pTempEntity->entity;

	// Copy over data
	pEntity->baseline.renderamt = 255;
	pEntity->baseline.friction = -1;
	if(pCtrl)
	{	pEntity->curstate.frame = pCtrl->getFrame();
		pEntity->curstate.sequence = pCtrl->getSequenceNum();
		if(pEntity->curstate.sequence < 0)
			pEntity->curstate.sequence = 0;
		pEntity->curstate.body = pCtrl->getBodyPart();
	}
	else
	{	pEntity->curstate.frame= pSourceEnt->curstate.frame;
		pEntity->curstate.sequence = pSourceEnt->curstate.sequence;
		if(pEntity->curstate.sequence < 0)
			pEntity->curstate.sequence = 0;
		pEntity->curstate.body = pSourceEnt->curstate.body;
	}
	pEntity->curstate.rendermode = kRenderTransTexture;
	pEntity->curstate.framerate = 0;
	pEntity->angles = pAccessor->getRenderAngle();
	pEntity->curstate.origin = pAccessor->getRenderPosition();
	pEntity->origin = pAccessor->getRenderPosition();

	// HACK HACK: Inverert pitch
	pEntity->angles[PITCH] = -pEntity->angles[PITCH];

	// Straiten out legs
	pEntity->curstate.controller[0] = 127;
	pEntity->curstate.controller[1] = 127;
	pEntity->curstate.controller[2] = 127;
	pEntity->curstate.controller[3] = 127;
	pEntity->latched.prevcontroller[0] = pEntity->curstate.controller[0];
	pEntity->latched.prevcontroller[1] = pEntity->curstate.controller[1];
	pEntity->latched.prevcontroller[2] = pEntity->curstate.controller[2];
	pEntity->latched.prevcontroller[3] = pEntity->curstate.controller[3];
}

/*
* Model Blur Manager
*/

// Add Blur
CModelBlur *CModelBlurManager::addBlur( int idx, float flEmitRate, float flStayTime, float flFadeRate )
{	// Create effect
	CModelBlur newblur;
	newblur.setIndex(idx);
	newblur.setEmitRate(flEmitRate);
	newblur.setStayTime(flStayTime);
	newblur.setFadeRate(flFadeRate);
	// Make bone accessor and store
	newblur.setBoneAccessor(gBoneManager.addAccessor(idx));
	// Add to list
	getModelBlurList()->push_front(newblur);
	return (&(*getModelBlurList()->begin()));
}

// Remove Blur
void CModelBlurManager::removeBlur( int idx )
{	std::list<CModelBlur>::iterator iterRemove;
	ForEachIn(iterRemove, (*getModelBlurList()))
	{	if(iterRemove->getIndex() == idx)
		{	// Remove bone accessor
			gBoneManager.removeAccessor(iterRemove->getBoneAccessor());
			// Remove blur effect from list
			getModelBlurList()->erase(iterRemove);
			return;
		}
	}
}

// Check for idx, and if matching create blur
void CModelBlurManager::Think( int idx, float flTime )
{	std::list<CModelBlur>::iterator iterCurrent;
	ForEachIn(iterCurrent, (*getModelBlurList()))
	{	if(iterCurrent->Check(idx))
		{	iterCurrent->Think(flTime);
		}
	}
}