//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================

// studio_model.cpp
// routines for setting up to draw 3DStudio models

#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "com_model.h"
#include "studio.h"
#include "entity_state.h"
#include "cl_entity.h"
#include "dlight.h"
#include "triangleapi.h"

#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <math.h>

#include "studio_util.h"
#include "r_studioint.h"

#include "StudioModelRenderer.h"
#include "GameStudioModelRenderer.h"
//added by harSens
#include "vrml.h"
//added by Pcjoe
#include "fxscript/fxsys.h"
#include "bonerec.h"
#include "mdlblur.h"
#include "mdlcontrol.h"

// Global engine <-> studio model rendering code interface
engine_studio_api_t IEngineStudio;

// Added by Pcjoe
#define INTERPOL_AURABEND_SPEED	6
void VectorAngles( const float *forward, float *angles );
extern cvar_t *cl_interpolgait;
extern cvar_t *cl_smoothflyinganim;
extern cvar_t *cl_motionblur;
#define ANIM_GAIT_FRONT	1
#define ANIM_GAIT_BACK	2
#define ANIM_GAIT_LEFT	3
#define ANIM_GAIT_RIGHT	4
#define ANIM_GAIT_UP	5
#define ANIM_GAIT_DOWN	6
#define INTERPOL_TIME	(float)0.2
#define MOTION_BLUR_DELAY	0.05
// Bone Manager
extern CBoneManager gBoneManager;
// Blur Manager
extern CModelBlurManager gModelBlur;
// Model Control Manager
extern CModelControlManager gModelControl;

extern buddy_info_t gBuddyInfo[MAX_PLAYERS];

//added by harSens
#define TELEPORT_FADETIME 1.0
#define TELEPORT_MAXAMT 255
#define DIAMOND_ROTATIONSPEED 145
extern int g_hsprWhite;
extern int g_hsprHalo;
/////////////////////
// Implementation of CStudioModelRenderer.h

// Pcjoe: Velocty of player stored from pm_shared.c
extern "C"
{	vec3_t vecPmVelocity;
};
// stl
using namespace std;
/*
====================
Init

====================
*/
void CStudioModelRenderer::Init( void )
{
	// Set up some variables shared with engine
	m_pCvarHiModels			= IEngineStudio.GetCvar( "cl_himodels" );
	m_pCvarDeveloper		= IEngineStudio.GetCvar( "developer" );
	m_pCvarDrawEntities		= IEngineStudio.GetCvar( "r_drawentities" );

	m_pChromeSprite			= IEngineStudio.GetChromeSprite();

	IEngineStudio.GetModelCounters( &m_pStudioModelCount, &m_pModelsDrawn );

	// Get pointers to engine data structures
	m_pbonetransform		= (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetBoneTransform();
	m_plighttransform		= (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetLightTransform();
	m_paliastransform		= (float (*)[3][4])IEngineStudio.StudioGetAliasTransform();
	m_protationmatrix		= (float (*)[3][4])IEngineStudio.StudioGetRotationMatrix();

	//added by harSens
	ParseVRML("models/diamond.wrl", m_vrmlDiamond);	
	ParseVRML("models/halo.wrl", m_vrmlHalo);	
	m_flRotationDiamond = 0;
	for(int i=0;i<MAX_PLAYERS;i++)
		m_fDrawDiamond[i]=false;

	// added by Pcjoe
	//m_pInterpolGait.clear();
	ClearInterpolGates();
}

/*
====================
CStudioModelRenderer

====================
*/
CStudioModelRenderer::CStudioModelRenderer( void )
{
	m_fDoInterp			= 1;
	m_fGaitEstimation	= 1;
	m_pCurrentEntity	= NULL;
	m_pCvarHiModels		= NULL;
	m_pCvarDeveloper	= NULL;
	m_pCvarDrawEntities	= NULL;
	m_pChromeSprite		= NULL;
	m_pStudioModelCount	= NULL;
	m_pModelsDrawn		= NULL;
	m_protationmatrix	= NULL;
	m_paliastransform	= NULL;
	m_pbonetransform	= NULL;
	m_plighttransform	= NULL;
	m_pStudioHeader		= NULL;
	m_pBodyPart			= NULL;
	m_pSubModel			= NULL;
	m_pPlayerInfo		= NULL;
	m_pRenderModel		= NULL;
}

/*
====================
~CStudioModelRenderer

====================
*/
CStudioModelRenderer::~CStudioModelRenderer( void )
{
}

/*
====================
StudioCalcBoneAdj

====================
*/
void CStudioModelRenderer::StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen )
{
	int					i, j;
	float				value;
	mstudiobonecontroller_t *pbonecontroller;
	
	pbonecontroller = (mstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex);

	for (j = 0; j < m_pStudioHeader->numbonecontrollers; j++)
	{
		i = pbonecontroller[j].index;
		if (i <= 3)
		{
			// check for 360% wrapping
			if (pbonecontroller[j].type & STUDIO_RLOOP)
			{
				if (abs(pcontroller1[i] - pcontroller2[i]) > 128)
				{
					int a, b;
					a = (pcontroller1[j] + 128) % 256;
					b = (pcontroller2[j] + 128) % 256;
					value = ((a * dadt) + (b * (1 - dadt)) - 128) * (360.0/256.0) + pbonecontroller[j].start;
				}
				else 
				{
					value = ((pcontroller1[i] * dadt + (pcontroller2[i]) * (1.0 - dadt))) * (360.0/256.0) + pbonecontroller[j].start;
				}
			}
			else 
			{
				value = (pcontroller1[i] * dadt + pcontroller2[i] * (1.0 - dadt)) / 255.0;
				if (value < 0) value = 0;
				if (value > 1.0) value = 1.0;
				value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end;
			}
			// Con_DPrintf( "%d %d %f : %f\n", m_pCurrentEntity->curstate.controller[j], m_pCurrentEntity->latched.prevcontroller[j], value, dadt );
		}
		else
		{
			value = mouthopen / 64.0;
			if (value > 1.0) value = 1.0;				
			value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end;
			// Con_DPrintf("%d %f\n", mouthopen, value );
		}
		switch(pbonecontroller[j].type & STUDIO_TYPES)
		{
		case STUDIO_XR:
		case STUDIO_YR:
		case STUDIO_ZR:
			adj[j] = value * (M_PI / 180.0);
			break;
		case STUDIO_X:
		case STUDIO_Y:
		case STUDIO_Z:
			adj[j] = value;
			break;
		}
	}
}


/*
====================
StudioCalcBoneQuaterion

====================
*/
void CStudioModelRenderer::StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q )
{
	int					j, k;
	vec4_t				q1, q2;
	vec3_t				angle1, angle2;
	mstudioanimvalue_t	*panimvalue;

	for (j = 0; j < 3; j++)
	{
		if (panim->offset[j+3] == 0)
		{
			angle2[j] = angle1[j] = pbone->value[j+3]; // default;
		}
		else
		{
			panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]);
			k = frame;
			// DEBUG
			if (panimvalue->num.total < panimvalue->num.valid)
				k = 0;
			while (panimvalue->num.total <= k)
			{
				k -= panimvalue->num.total;
				panimvalue += panimvalue->num.valid + 1;
				// DEBUG
				if (panimvalue->num.total < panimvalue->num.valid)
					k = 0;
			}
			// Bah, missing blend!
			if (panimvalue->num.valid > k)
			{
				angle1[j] = panimvalue[k+1].value;

				if (panimvalue->num.valid > k + 1)
				{
					angle2[j] = panimvalue[k+2].value;
				}
				else
				{
					if (panimvalue->num.total > k + 1)
						angle2[j] = angle1[j];
					else
						angle2[j] = panimvalue[panimvalue->num.valid+2].value;
				}
			}
			else
			{
				angle1[j] = panimvalue[panimvalue->num.valid].value;
				if (panimvalue->num.total > k + 1)
				{
					angle2[j] = angle1[j];
				}
				else
				{
					angle2[j] = panimvalue[panimvalue->num.valid + 2].value;
				}
			}
			angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j+3];
			angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j+3];
		}

		if (pbone->bonecontroller[j+3] != -1)
		{
			angle1[j] += adj[pbone->bonecontroller[j+3]];
			angle2[j] += adj[pbone->bonecontroller[j+3]];
		}
	}

	if (!VectorCompare( angle1, angle2 ))
	{
		AngleQuaternion( angle1, q1 );
		AngleQuaternion( angle2, q2 );
		QuaternionSlerp( q1, q2, s, q );
	}
	else
	{
		AngleQuaternion( angle1, q );
	}
}

/*
====================
StudioCalcBonePosition

====================
*/
void CStudioModelRenderer::StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos )
{
	int					j, k;
	mstudioanimvalue_t	*panimvalue;

	for (j = 0; j < 3; j++)
	{
		pos[j] = pbone->value[j]; // default;
		if (panim->offset[j] != 0)
		{
			panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]);
			/*
			if (i == 0 && j == 0)
				Con_DPrintf("%d  %d:%d  %f\n", frame, panimvalue->num.valid, panimvalue->num.total, s );
			*/
			
			k = frame;
			// DEBUG
			if (panimvalue->num.total < panimvalue->num.valid)
				k = 0;
			// find span of values that includes the frame we want
			while (panimvalue->num.total <= k)
			{
				k -= panimvalue->num.total;
				panimvalue += panimvalue->num.valid + 1;
  				// DEBUG
				if (panimvalue->num.total < panimvalue->num.valid)
					k = 0;
			}
			// if we're inside the span
			if (panimvalue->num.valid > k)
			{
				// and there's more data in the span
				if (panimvalue->num.valid > k + 1)
				{
					pos[j] += (panimvalue[k+1].value * (1.0 - s) + s * panimvalue[k+2].value) * pbone->scale[j];
				}
				else
				{
					pos[j] += panimvalue[k+1].value * pbone->scale[j];
				}
			}
			else
			{
				// are we at the end of the repeating values section and there's another section with data?
				if (panimvalue->num.total <= k + 1)
				{
					pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0 - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j];
				}
				else
				{
					pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j];
				}
			}
		}
		if ( pbone->bonecontroller[j] != -1 && adj )
		{
			pos[j] += adj[pbone->bonecontroller[j]];
		}
	}
}

/*
====================
StudioSlerpBones

====================
*/
void CStudioModelRenderer::StudioSlerpBones( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s )
{
	int			i;
	vec4_t		q3;
	float		s1;

	if (s < 0) s = 0;
	else if (s > 1.0) s = 1.0;

	s1 = 1.0 - s;

	for (i = 0; i < m_pStudioHeader->numbones; i++)
	{
		QuaternionSlerp( q1[i], q2[i], s, q3 );
		q1[i][0] = q3[0];
		q1[i][1] = q3[1];
		q1[i][2] = q3[2];
		q1[i][3] = q3[3];
		pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s;
		pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s;
		pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s;
	}
}

/*
====================
StudioGetAnim

====================
*/
mstudioanim_t *CStudioModelRenderer::StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc )
{
	mstudioseqgroup_t	*pseqgroup;
	cache_user_t *paSequences;

	pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup;

	if (pseqdesc->seqgroup == 0)
	{
		return (mstudioanim_t *)((byte *)m_pStudioHeader + pseqgroup->data + pseqdesc->animindex);
	}

	paSequences = (cache_user_t *)m_pSubModel->submodels;

	if (paSequences == NULL)
	{
		paSequences = (cache_user_t *)IEngineStudio.Mem_Calloc( 16, sizeof( cache_user_t ) ); // UNDONE: leak!
		m_pSubModel->submodels = (dmodel_t *)paSequences;
	}

	if (!IEngineStudio.Cache_Check( (struct cache_user_s *)&(paSequences[pseqdesc->seqgroup])))
	{
		gEngfuncs.Con_DPrintf("loading %s\n", pseqgroup->name );
		IEngineStudio.LoadCacheFile( pseqgroup->name, (struct cache_user_s *)&paSequences[pseqdesc->seqgroup] );
	}
	return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex);
}

/*
====================
StudioPlayerBlend

====================
*/
void CStudioModelRenderer::StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch )
{
	// calc up/down pointing
	*pBlend = (*pPitch * 3);
	if (*pBlend < pseqdesc->blendstart[0])
	{
		*pPitch -= pseqdesc->blendstart[0] / 3.0;
		*pBlend = 0;
	}
	else if (*pBlend > pseqdesc->blendend[0])
	{
		*pPitch -= pseqdesc->blendend[0] / 3.0;
		*pBlend = 255;
	}
	else
	{
		if (pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1) // catch qc error
			*pBlend = 127;
		else
			*pBlend = 255 * (*pBlend - pseqdesc->blendstart[0]) / (pseqdesc->blendend[0] - pseqdesc->blendstart[0]);
		*pPitch = 0;
	}
}

/*
====================
StudioSetUpTransform

====================
*/
void CStudioModelRenderer::StudioSetUpTransform (int trivial_accept)
{
	int				i;
	vec3_t			angles;
	vec3_t			modelpos;

// tweek model origin	
	//for (i = 0; i < 3; i++)
	//	modelpos[i] = m_pCurrentEntity->origin[i];

	VectorCopy( m_pCurrentEntity->origin, modelpos );

// TODO: should really be stored with the entity instead of being reconstructed
// TODO: should use a look-up table
// TODO: could cache lazily, stored in the entity
	angles[ROLL] = m_pCurrentEntity->curstate.angles[ROLL];
	angles[PITCH] = m_pCurrentEntity->curstate.angles[PITCH];
	angles[YAW] = m_pCurrentEntity->curstate.angles[YAW];

	//Con_DPrintf("Angles %4.2f prev %4.2f for %i\n", angles[PITCH], m_pCurrentEntity->index);
	//Con_DPrintf("movetype %d %d\n", m_pCurrentEntity->movetype, m_pCurrentEntity->aiment );
	if (m_pCurrentEntity->curstate.movetype == MOVETYPE_STEP) 
	{
		float			f = 0;
		float			d;

		// don't do it if the goalstarttime hasn't updated in a while.

		// NOTE:  Because we need to interpolate multiplayer characters, the interpolation time limit
		//  was increased to 1.0 s., which is 2x the max lag we are accounting for.

		if ( ( m_clTime < m_pCurrentEntity->curstate.animtime + 1.0f ) &&
			 ( m_pCurrentEntity->curstate.animtime != m_pCurrentEntity->latched.prevanimtime ) )
		{
			f = (m_clTime - m_pCurrentEntity->curstate.animtime) / (m_pCurrentEntity->curstate.animtime - m_pCurrentEntity->latched.prevanimtime);
			//Con_DPrintf("%4.2f %.2f %.2f\n", f, m_pCurrentEntity->curstate.animtime, m_clTime);
		}

		if (m_fDoInterp)
		{
			// ugly hack to interpolate angle, position. current is reached 0.1 seconds after being set
			f = f - 1.0;
		}
		else
		{
			f = 0;
		}

		for (i = 0; i < 3; i++)
		{
			modelpos[i] += (m_pCurrentEntity->origin[i] - m_pCurrentEntity->latched.prevorigin[i]) * f;
		}

		// NOTE:  Because multiplayer lag can be relatively large, we don't want to cap
		//  f at 1.5 anymore.
		//if (f > -1.0 && f < 1.5) {}

//			Con_DPrintf("%.0f %.0f\n",m_pCurrentEntity->msg_angles[0][YAW], m_pCurrentEntity->msg_angles[1][YAW] );
		for (i = 0; i < 3; i++)
		{
			float ang1, ang2;

			ang1 = m_pCurrentEntity->angles[i];
			ang2 = m_pCurrentEntity->latched.prevangles[i];

			d = ang1 - ang2;
			if (d > 180)
			{
				d -= 360;
			}
			else if (d < -180)
			{	
				d += 360;
			}

			angles[i] += d * f;
		}
		//Con_DPrintf("%.3f \n", f );
	}
	else if ( m_pCurrentEntity->curstate.movetype != MOVETYPE_NONE ) 
	{
		// Pcjoe: Lock angles for melee struggles
		vec3_t vecAngles = m_pCurrentEntity->angles;
		/*modified by harSens
		std::list<model_manip_s>::iterator pOtherManip = gHUD.m_ManipModel.FindByOtherIndex(m_pCurrentEntity->index);
		std::list<model_manip_s>::iterator pPlayerManip = gHUD.m_ManipModel.FindByPlayerIndex(m_pCurrentEntity->index);
		*/
		model_manip_s *pOtherManip = gHUD.m_ManipModel.FindByOtherIndex(m_pCurrentEntity->index);
		model_manip_s *pPlayerManip = gHUD.m_ManipModel.FindByPlayerIndex(m_pCurrentEntity->index);
		if(pOtherManip!=NULL)
		{
			if((pOtherManip->iFlags & MANIP_FLAG_MSTRUGGLE) || (pOtherManip->iFlags & MANIP_FLAG_CONNECT))
			{
				if(!pOtherManip->blFixedAngles)
				{	// Get pointer to attacker
					cl_entity_t *pPlayer = gEngfuncs.GetEntityByIndex( pOtherManip->iPlayerIndex );
					
					// Set angles
					if(pPlayer)
					{	pOtherManip->blFixedAngles = !pOtherManip->blFixedAngles;
						// Reverse angles
						pOtherManip->vecAngles = pPlayer->angles;

						pOtherManip->vecAngles[YAW] += 180;
						if ( pOtherManip->vecAngles[YAW] > 180 ) 
						{	pOtherManip->vecAngles[YAW] -= 360;
						}

						pOtherManip->vecAngles[PITCH] = -pOtherManip->vecAngles[PITCH];
					}
				}
				vecAngles = pOtherManip->vecAngles;
			}
		}
		if(pPlayerManip!=NULL)
		{	if((pPlayerManip->iFlags & MANIP_FLAG_CONNECT) || (pPlayerManip->iFlags & MANIP_FLAG_MSTRUGGLE))
			{	if(pPlayerManip->blFixedAngles)
				{	vecAngles = pPlayerManip->vecAngles;
				}
			}
			if(pPlayerManip->iFlags & MANIP_FLAG_ANGLE_FIX)
			{	
				if(!pPlayerManip->blFixedAngles)
				{	pPlayerManip->blFixedAngles = !pPlayerManip->blFixedAngles;
					pPlayerManip->vecAngles = m_pCurrentEntity->angles;
				}
				vecAngles = pPlayerManip->vecAngles;
			}
			if(pPlayerManip->iFlags & MANIP_FLAG_ANGLE_FIX_ENT)
			{	if(!pPlayerManip->blFixedAngles)
				{	pPlayerManip->blFixedAngles = true;
				}
				vecAngles = pPlayerManip->vecAngles;
			}
		}
		VectorCopy( vecAngles, angles );
	}

	//Con_DPrintf("%.0f %0.f %0.f\n", modelpos[0], modelpos[1], modelpos[2] );
	//Con_DPrintf("%.0f %0.f %0.f\n", angles[0], angles[1], angles[2] );

	angles[PITCH] = -angles[PITCH];
	VectorCopy( angles, m_vecAngles ); // Added by Pcjoe
	AngleMatrix (angles, (*m_protationmatrix));

	// Edited by Pcjoe
	//added by harSens (maybe use something more generic later on?)
	if(IsDiskAttack())
	{	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(m_pCurrentEntity->curstate.rendercolor.r);
		if (pClient)
		{	modelpos = pClient->attachment[1];
		}
	}
	
	if ( !IEngineStudio.IsHardware() )
	{
		static float viewmatrix[3][4];

		VectorCopy (m_vRight, viewmatrix[0]);
		VectorCopy (m_vUp, viewmatrix[1]);
		VectorInverse (viewmatrix[1]);
		VectorCopy (m_vNormal, viewmatrix[2]);

		(*m_protationmatrix)[0][3] = modelpos[0] - m_vRenderOrigin[0];
		(*m_protationmatrix)[1][3] = modelpos[1] - m_vRenderOrigin[1];
		(*m_protationmatrix)[2][3] = modelpos[2] - m_vRenderOrigin[2];

		//added by harSens, scaling code from Laurie Cheers (scale in software mode too)
		if (m_pCurrentEntity->curstate.scale != 0)
		{	for (int i = 0; i < 3; i++)
			{	for (int j = 0; j < 3; j++)
				{	(*m_protationmatrix)[i][j] *=m_pCurrentEntity->curstate.scale;
				}
			}
		}

		ConcatTransforms (viewmatrix, (*m_protationmatrix), (*m_paliastransform));

		// do the scaling up of x and y to screen coordinates as part of the transform
		// for the unclipped case (it would mess up clipping in the clipped case).
		// Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y
		// correspondingly so the projected x and y come out right
		// FIXME: make this work for clipped case too?
		if (trivial_accept)
		{
			for (i=0 ; i<4 ; i++)
			{
				(*m_paliastransform)[0][i] *= m_fSoftwareXScale *
						(1.0 / (ZISCALE * 0x10000));
				(*m_paliastransform)[1][i] *= m_fSoftwareYScale *
						(1.0 / (ZISCALE * 0x10000));
				(*m_paliastransform)[2][i] *= 1.0 / (ZISCALE * 0x10000);

			}
		}
	}
	
	(*m_protationmatrix)[0][3] = modelpos[0];
	(*m_protationmatrix)[1][3] = modelpos[1];
	(*m_protationmatrix)[2][3] = modelpos[2];

	if ( IEngineStudio.IsHardware() )
	{	//added by harSens, scaling code from Laurie Cheers
		if (m_pCurrentEntity->curstate.scale != 0)
		{	for (int i = 0; i < 3; i++)
			{	for (int j = 0; j < 3; j++)
				{	(*m_protationmatrix)[i][j] *=m_pCurrentEntity->curstate.scale;
				}
			}
		}
	}
}


/*
====================
StudioEstimateInterpolant

====================
*/
float CStudioModelRenderer::StudioEstimateInterpolant( void )
{
	float dadt = 1.0;

	if ( m_fDoInterp && ( m_pCurrentEntity->curstate.animtime >= m_pCurrentEntity->latched.prevanimtime + 0.01 ) )
	{
		dadt = (m_clTime - m_pCurrentEntity->curstate.animtime) / 0.1;
		if (dadt > 2.0)
		{
			dadt = 2.0;
		}
	}
	return dadt;
}

/*
====================
StudioCalcRotations

====================
*/
void CStudioModelRenderer::StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f )
{
	int					i;
	int					frame;
	mstudiobone_t		*pbone;

	float				s;
	float				adj[MAXSTUDIOCONTROLLERS];
	float				dadt;

	if (f > pseqdesc->numframes - 1)
	{
		f = 0;	// bah, fix this bug with changing sequences too fast
	}
	// BUG ( somewhere else ) but this code should validate this data.
	// This could cause a crash if the frame # is negative, so we'll go ahead
	//  and clamp it here
	else if ( f < -0.01 )
	{
		f = -0.01;
	}

	frame = (int)f;

	// Con_DPrintf("%d %.4f %.4f %.4f %.4f %d\n", m_pCurrentEntity->curstate.sequence, m_clTime, m_pCurrentEntity->animtime, m_pCurrentEntity->frame, f, frame );

	// Con_DPrintf( "%f %f %f\n", m_pCurrentEntity->angles[ROLL], m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->angles[YAW] );

	// Con_DPrintf("frame %d %d\n", frame1, frame2 );


	dadt = StudioEstimateInterpolant( );
	s = (f - frame);

	// add in programtic controllers
	pbone		= (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);

	StudioCalcBoneAdj( dadt, adj, m_pCurrentEntity->curstate.controller, m_pCurrentEntity->latched.prevcontroller, m_pCurrentEntity->mouth.mouthopen );

	for (i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++) 
	{
		StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] );

		StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] );
		// if (0 && i == 0)
		//	Con_DPrintf("%d %d %d %d\n", m_pCurrentEntity->curstate.sequence, frame, j, k );
	}

	if (pseqdesc->motiontype & STUDIO_X)
	{
		pos[pseqdesc->motionbone][0] = 0.0;
	}
	if (pseqdesc->motiontype & STUDIO_Y)
	{
		pos[pseqdesc->motionbone][1] = 0.0;
	}
	if (pseqdesc->motiontype & STUDIO_Z)
	{
		pos[pseqdesc->motionbone][2] = 0.0;
	}

	s = 0 * ((1.0 - (f - (int)(f))) / (pseqdesc->numframes)) * m_pCurrentEntity->curstate.framerate;

	if (pseqdesc->motiontype & STUDIO_LX)
	{
		pos[pseqdesc->motionbone][0] += s * pseqdesc->linearmovement[0];
	}
	if (pseqdesc->motiontype & STUDIO_LY)
	{
		pos[pseqdesc->motionbone][1] += s * pseqdesc->linearmovement[1];
	}
	if (pseqdesc->motiontype & STUDIO_LZ)
	{
		pos[pseqdesc->motionbone][2] += s * pseqdesc->linearmovement[2];
	}
}

/*
====================
Studio_FxTransform

====================
*/
void CStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[3][4] )
{
	switch( ent->curstate.renderfx )
	{
	case kRenderFxDistort:
	case kRenderFxHologram:
		if ( gEngfuncs.pfnRandomLong(0,49) == 0 )
		{
			int axis = gEngfuncs.pfnRandomLong(0,1);
			if ( axis == 1 ) // Choose between x & z
				axis = 2;
			VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] );
		}
		else if ( gEngfuncs.pfnRandomLong(0,49) == 0 )
		{
			float offset;
			int axis = gEngfuncs.pfnRandomLong(0,1);
			if ( axis == 1 ) // Choose between x & z
				axis = 2;
			offset = gEngfuncs.pfnRandomFloat(-10,10);
			transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset;
		}
	break;
	case kRenderFxExplode:
		{
			float scale;

			scale = 1.0 + ( m_clTime - ent->curstate.animtime) * 10.0;
			if ( scale > 2 )	// Don't blow up more than 200%
				scale = 2;
			transform[0][1] *= scale;
			transform[1][1] *= scale;
			transform[2][1] *= scale;
		}
	break;

	}
}

/*
====================
StudioEstimateFrame

====================
*/
float CStudioModelRenderer::StudioEstimateFrame( mstudioseqdesc_t *pseqdesc )
{
	double				dfdt, f;

	if ( m_fDoInterp )
	{
		if ( m_clTime < m_pCurrentEntity->curstate.animtime )
		{
			dfdt = 0;
		}
		else
		{
			dfdt = (m_clTime - m_pCurrentEntity->curstate.animtime) * m_pCurrentEntity->curstate.framerate * pseqdesc->fps;

		}
	}
	else
	{
		dfdt = 0;
	}

	if (pseqdesc->numframes <= 1)
	{
		f = 0;
	}
	else
	{
		f = (m_pCurrentEntity->curstate.frame * (pseqdesc->numframes - 1)) / 256.0;
	}
 	
	f += dfdt;

	if (pseqdesc->flags & STUDIO_LOOPING) 
	{
		if (pseqdesc->numframes > 1)
		{
			f -= (int)(f / (pseqdesc->numframes - 1)) *  (pseqdesc->numframes - 1);
		}
		if (f < 0) 
		{
			f += (pseqdesc->numframes - 1);
		}
	}
	else 
	{
		if (f >= pseqdesc->numframes - 1.001) 
		{
			f = pseqdesc->numframes - 1.001;
		}
		if (f < 0.0) 
		{
			f = 0.0;
		}
	}
	return f;
}

// Pcjoe: Find interpol gait
/*
list<interpol_gait_s>::iterator CStudioModelRenderer::FindInterpolGait( int idx )
{	for(list<interpol_gait_s>::iterator iter = m_pInterpolGait.begin();iter!=m_pInterpolGait.end();iter++)
	{	if(iter->iIndex==idx)
		{	return iter;
		}
	}
	//return NULL;
	return m_pInterpolGait.end();
}
*/

// Pcjoe: Add interpol gait
/*
list<interpol_gait_s>::iterator CStudioModelRenderer::AddInterpolGait( void )
{	interpol_gait_s newgait;
	newgait.iIndex = m_pCurrentEntity->index;
	newgait.blRendered = false;
	newgait.blStartRecUpper = false;
	newgait.pModel = NULL;
	newgait.flPrevAnimTime = 0;
	newgait.iSequence = -1;
	newgait.iPrevSequence = 0;
	newgait.flPrevMaxSpeed = 0;
	m_pInterpolGait.push_front(newgait);
	
	ConsolePrint("Gait pushed\n");
	return m_pInterpolGait.begin();
}
*/

void CStudioModelRenderer::ClearInterpolGates()
{
	for(int i=0;i<=MAX_PLAYERS;i++)
	{
		m_InterpolGait[i].blRendered = false;
		m_InterpolGait[i].blActive = false;
	}
}


// Pcjoe: Check interpol gait
void CStudioModelRenderer::CheckInterpolGait( void )
{	int idx = m_pCurrentEntity->index;
	
	// Disabled
	if((cl_interpolgait->value == 0) && (cl_smoothflyinganim->value == 0))
	{	return;
	}

	//list<interpol_gait_s>::iterator iter = FindInterpolGait(idx);
		
	// Check if playerinfo is valid
	if(!m_pPlayerInfo)
	{	/*
		if(iter != m_pInterpolGait.end())
		{	iter->blRendered = true;
		}
		*/
		m_InterpolGait[idx].blRendered = true;		
		return;
	}

	// Get Sequence
	int iGait = m_pCurrentEntity->curstate.gaitsequence;
	int iUpperSequence = m_pCurrentEntity->curstate.sequence;
	int iSequence = iGait;
	float flFrame;

	mstudioseqdesc_t *pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence;
	flFrame = StudioEstimateFrame( pseqdesc );

	// No gait sequence, set upperbody anim so we can interpol when we start using the gait again
	if(iSequence == 0)
	{	iSequence = iUpperSequence;
	}

	
	if(m_pCurrentEntity->player)
	{	/*
		// Add a new struct
		if(iter == m_pInterpolGait.end())
		{	iter = AddInterpolGait();
		}
		// Set render flag
		iter->blRendered = true;
		*/
		if (!m_InterpolGait[idx].blActive)
		{
			m_InterpolGait[idx].iIndex = m_pCurrentEntity->index;
			m_InterpolGait[idx].blRendered = false;
			m_InterpolGait[idx].blStartRecUpper = false;
			m_InterpolGait[idx].pModel = NULL;
			m_InterpolGait[idx].flPrevAnimTime = 0;
			m_InterpolGait[idx].iSequence = -1;
			m_InterpolGait[idx].iPrevSequence = 0;
			m_InterpolGait[idx].flPrevMaxSpeed = 0;
			m_InterpolGait[idx].blActive = true;
		}
		m_InterpolGait[idx].blRendered = true;

		/* modified by harSens
		// New struct, reset values
		if(iter->iSequence == -1)
		{	iter->iSequence = iSequence;
			iter->iPrevSequence = iSequence;
		}
		
		// Changed animations, store frames + sequence
		if(iter->iSequence != iSequence)
		{	iter->iPrevSequence = iter->iSequence;
			iter->flPrevAnimTime = m_clTime;
			// Copy over bone positions and quaternions
			for(int i=0;i<m_pStudioHeader->numbones;i++)
			{	memcpy( iter->posprev[i], iter->pos[i], sizeof( iter->posprev[i] ));
				memcpy( iter->qprev[i], iter->q[i], sizeof( iter->qprev[i] ));
			}
		}
		// Set new values for current sequence + frame
		iter->iSequence = iSequence;
		*/

		if(m_InterpolGait[idx].iSequence == -1)
		{	m_InterpolGait[idx].iSequence = iSequence;
			m_InterpolGait[idx].iPrevSequence = iSequence;
		}

		if(m_InterpolGait[idx].iSequence != iSequence)
		{	m_InterpolGait[idx].iPrevSequence = m_InterpolGait[idx].iSequence;
			m_InterpolGait[idx].flPrevAnimTime = m_clTime;
			// Copy over bone positions and quaternions
			for(int i=0;i<m_pStudioHeader->numbones;i++)
			{	memcpy( m_InterpolGait[idx].posprev[i], m_InterpolGait[idx].pos[i], sizeof( m_InterpolGait[idx].posprev[i] ));
				memcpy( m_InterpolGait[idx].qprev[i], m_InterpolGait[idx].q[i], sizeof( m_InterpolGait[idx].qprev[i] ));
			}
		}
		// Set new values for current sequence + frame
		m_InterpolGait[idx].iSequence = iSequence;		
	}
}

// Pcjoe: Is flying animations
bool CStudioModelRenderer::IsFlyingAnim( int iSequence )
{	// Test for flying anims
	int iStart = GetSequenceNumber("fly_idle");
	int iEnd = iStart + ANIM_GAIT_DOWN;

	if(((iSequence >= iStart) && (iSequence <= iEnd)))
	{	return true;
	}
	return false;
}

// Pcjoe: Can we interpolate gait?
bool CStudioModelRenderer::SmoothFlying( int iSequence )
{	if(cl_smoothflyinganim->value == 0)
	{	return false;
	}

	// Must be in movetype fly
	if((m_pCurrentEntity->curstate.movetype != MOVETYPE_PLAYERFLY))
	{	return false;
	}

	// Check animations
	if(m_pPlayerInfo)
	{	if(!IsFlyingAnim(iSequence))
		{	return false;
		}
	}
	else
	{	return false;
	}

	return true;
}

//Pcjoe: Get Sequence
int CStudioModelRenderer::GetSequenceNumber( char *szAnim )
{	mstudioseqdesc_t *pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex);
	for (int i = 0; i < m_pStudioHeader->numseq; i++) 
	{	if(!stricmp(szAnim, pseqdesc->label))
		{	return i;
		}
		pseqdesc++;
	}
	return 0;
}

// Pcjoe: Get Velocity
vec3_t CStudioModelRenderer::GetVelocity( cl_entity_t *pEntity )
{	if(!pEntity)
	{	return vec3_t(0,0,0);
	}

	if(pEntity == gEngfuncs.GetLocalPlayer())
	{	return vecPmVelocity;
	}
	else
	{	return ((m_pCurrentEntity->latched.prevorigin - m_pCurrentEntity->origin) * (1/(m_clTime - m_clOldTime)));
	}
	return vec3_t(0,0,0);
}


// Pcjoe: Get Advanced Flying Anim
void CStudioModelRenderer::GetAdvFlyingAnim( float pos[][3], vec4_t *q )
{	GetAdvFlyingAnim(m_pPlayerInfo->gaitframe, pos, q);
}
#define	VIEW_FIELD_NARROW	(float)0.9
void CStudioModelRenderer::GetAdvFlyingAnim( float frame, float pos[][3], vec4_t *q )
{	static float		pos2[MAXSTUDIOBONES][3];
	static vec4_t		q2[MAXSTUDIOBONES];
	static float		pos3[MAXSTUDIOBONES][3];
	static vec4_t		q3[MAXSTUDIOBONES];
	static float		pos4[MAXSTUDIOBONES][3];
	static vec4_t		q4[MAXSTUDIOBONES];
	static float		pos5[MAXSTUDIOBONES][3];
	static vec4_t		q5[MAXSTUDIOBONES];
	mstudioseqdesc_t	*pseqdesc;
	mstudioanim_t		*panim;
	float s;
	float flZ = 0;
	float flMaxSpeed;
	float flBlend=1;
	int iIdle;

	iIdle = GetSequenceNumber("fly_idle");

	pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + iIdle;
	int iMaxFrames = pseqdesc->numframes;

	panim = StudioGetAnim( m_pRenderModel, pseqdesc );
	StudioCalcRotations( pos, q, pseqdesc, panim, frame );
	
	// Get max speed
	//list<interpol_gait_s>::iterator iter = FindInterpolGait(m_pCurrentEntity->index);
	int idx = m_pCurrentEntity->index;
	
	flMaxSpeed = m_pCurrentEntity->curstate.fuser1;
	/* modified by harSens
	if(!flMaxSpeed && iter != m_pInterpolGait.end())
	{	flMaxSpeed = iter->flPrevMaxSpeed;
	}
	else if(iter != m_pInterpolGait.end())
	{	iter->flPrevMaxSpeed = flMaxSpeed;
	}
	*/
	if(!flMaxSpeed)
	{	flMaxSpeed = m_InterpolGait[idx].flPrevMaxSpeed;
	}
	else 
	{	m_InterpolGait[idx].flPrevMaxSpeed = flMaxSpeed;
	}

	// Get interpolation from flyidle to moving anims
	vec3_t vecVel = GetVelocity(m_pCurrentEntity);
	s = Length(vecVel);
	if(s > flMaxSpeed)
		s = flMaxSpeed;
	s /= flMaxSpeed;

	// Get angles of view + velocity
	vec3_t v_forward;
	AngleVectors(m_pCurrentEntity->angles, v_forward, NULL, NULL);

	VectorNormalize(vecVel);

	vec3_t vecAngles;
	VectorAngles(vecVel, vecAngles);
	float flAngles = m_pCurrentEntity->angles.y;
	if(flAngles < 0)
		flAngles += 360;

	flAngles -= vecAngles.y;
	float flAngles2 = flAngles;
	if(flAngles < 0)
		flAngles += 360;

	int iAnim1=0, iAnim2=0;
	float flRatio = 0;

	// Get blending animations + amount

	// Front - right
	if(flAngles < 90)
	{	flRatio = flAngles / float(90);
		iAnim1 = ANIM_GAIT_FRONT;
		iAnim2 = ANIM_GAIT_RIGHT;
	}
	// right - back
	else if(flAngles < 180)
	{	flAngles -= 90;
		flRatio = flAngles / float(90);
		iAnim1 = ANIM_GAIT_RIGHT;
		iAnim2 = ANIM_GAIT_BACK;
	}
	// back - left
	else if(flAngles < 270)
	{	flAngles -= 180;
		flRatio = flAngles / float(90);
		iAnim1 = ANIM_GAIT_BACK;
		iAnim2 = ANIM_GAIT_LEFT;
	}
	// left - front
	else
	{	flAngles -= 270;
		flRatio = flAngles / float(90);
		iAnim1 = ANIM_GAIT_LEFT;
		iAnim2 = ANIM_GAIT_FRONT;
	}

	frame = frame/iMaxFrames * pseqdesc->numframes;

	// Anim 1
	pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + (iIdle+iAnim1);
	panim = StudioGetAnim( m_pRenderModel, pseqdesc );
	StudioCalcRotations( pos2, q2, pseqdesc, panim, frame/iMaxFrames * pseqdesc->numframes );

	// Anim 2
	pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + (iIdle+iAnim2);
	panim = StudioGetAnim( m_pRenderModel, pseqdesc );
	StudioCalcRotations( pos3, q3, pseqdesc, panim, frame/iMaxFrames * pseqdesc->numframes );

	// Anim 3 ( up/down )
	if(vecVel.z > 0)
	{	pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + (iIdle+ANIM_GAIT_UP);
	}
	else
	{	pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + (iIdle+ANIM_GAIT_DOWN);
	}
	panim = StudioGetAnim( m_pRenderModel, pseqdesc );
	StudioCalcRotations( pos4, q5, pseqdesc, panim, frame/iMaxFrames * pseqdesc->numframes );
	
	flZ = fabs(vecVel.z);

	// Slerp
	StudioSlerpBones( q2, pos2, q3, pos3, flRatio );	// front/back/left/right aniamtions
	StudioSlerpBones( q2, pos2, q5, pos4, flZ );		// Up/down animation
	StudioSlerpBones( q, pos, q2, pos2, s );			// Blend everything together
}

// Pcjoe: Can Interpol
bool CStudioModelRenderer::CanInterpol( void )
{	if (m_fDoInterp &&
		m_pCurrentEntity->latched.sequencetime &&
		( m_pCurrentEntity->latched.sequencetime + INTERPOL_TIME > m_clTime ) && 
		( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq ))
	{	return true;
	}
	return false;
}

// Pcjoe: Get Max/Min's of model
void CStudioModelRenderer::GetMaxMinModel( model_s *pModel, vec3_t &vecMax, vec3_t &vecMin)
{/*	mstudioseqdesc_t	*pseqdesc;
	mstudioanim_t		*panim;

	static float		pos[MAXSTUDIOBONES][3];
	static vec4_t		q[MAXSTUDIOBONES];

	m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pModel);
	int iSequence = GetSequenceNumber("idle");

	// Get bone positions and quaternions for idle anim
	pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + iSequence;
	panim = StudioGetAnim( m_pRenderModel, pseqdesc );
	StudioCalcRotations( pos, q, pseqdesc, panim, 0 );

	// Get BBoxs
	mstudiobbox_t *pBBox = (mstudiobbox_t *)((byte *)m_pStudioHeader + m_pStudioHeader->hitboxindex);

	float flMaxX = -999;
	float flMinX = -999;
	float flMaxY = -999;
	float flMinY = -999;
	float flMaxZ = -999;
	float flMinZ = -999;

	// Loop through all hitboxes
	for(int j = 0; j < m_pStudioHeader->numhitboxes; j++)
	{	// Get Max / Mins
		float maxX = pBBox[j].bbmax.x + pos[pBBox[j].bone][0];
		float minX = pBBox[j].bbmin.x + pos[pBBox[j].bone][0];
		float maxY = pBBox[j].bbmax.y + pos[pBBox[j].bone][1];
		float minY = pBBox[j].bbmin.y + pos[pBBox[j].bone][1];
		float maxZ = pBBox[j].bbmax.z + pos[pBBox[j].bone][2];
		float minZ = pBBox[j].bbmin.z + pos[pBBox[j].bone][2];

		if(flMaxX == -999 || maxX > flMaxX)
			flMaxX = maxX;
		if(flMinX == -999 || minX < flMinX)
			flMinX = minX;
		if(flMaxY == -999 || maxY > flMaxY)
			flMaxY = maxY;
		if(flMinY == -999 || minY < flMinY)
			flMinY = minY;
		if(flMaxZ == -999 || maxZ > flMaxZ)
			flMaxZ = maxZ;
		if(flMinZ == -999 || minZ < flMinZ)
			flMinZ = minZ;
	}

	// Set max / mins
	vecMax.x = flMaxX;
	vecMin.x = flMinX;
	vecMax.y = flMaxY;
	vecMin.y = flMinY;
	vecMax.z = flMaxZ;
	vecMin.z = flMinZ;*/

	m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pModel);
	if (!m_pStudioHeader)
	{	ConsolePrint("Unable to fetch model pointer!\n");
		return;
	}

	mstudioseqdesc_t    *pseqdesc;
	pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex);
	vecMin = pseqdesc[0].bbmin;
	vecMax = pseqdesc[0].bbmax;
}

/*
====================
StudioSetupBones

====================
*/
void CStudioModelRenderer::StudioSetupBones ( void )
{
	int					i;
	double				f;

	mstudiobone_t		*pbones;
	mstudioseqdesc_t	*pseqdesc;
	mstudioanim_t		*panim;

	static float		pos[MAXSTUDIOBONES][3];
	static vec4_t		q[MAXSTUDIOBONES];
	float				bonematrix[3][4];

	static float		pos2[MAXSTUDIOBONES][3];
	static vec4_t		q2[MAXSTUDIOBONES];
	static float		pos3[MAXSTUDIOBONES][3];
	static vec4_t		q3[MAXSTUDIOBONES];
	static float		pos4[MAXSTUDIOBONES][3];
	static vec4_t		q4[MAXSTUDIOBONES];
	static vec3_t		modeloffset;			//added by Pcjoe

	// Added by Pcjoe
	//list<interpol_gait_s>::iterator iter = FindInterpolGait(m_pCurrentEntity->index);
	int idx = m_pCurrentEntity->index;
	if (idx<=MAX_PLAYERS)
	{	CheckInterpolGait();
	}

	if (m_pCurrentEntity->curstate.sequence >=  m_pStudioHeader->numseq) 
	{
		m_pCurrentEntity->curstate.sequence = 0;
	}

	pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence;

	// Pcjoe: HACK HACK: Blur effect, use exact frame
	if(m_pCurrentEntity->baseline.friction < 0 )
		f = m_pCurrentEntity->curstate.frame;
	else
		f = StudioEstimateFrame( pseqdesc );

	if (m_pCurrentEntity->latched.prevframe > f)
	{
		//Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f );
	}

	// Smooth flying for upper body
	/* modified by harSens
	if((iter != m_pInterpolGait.end()) && SmoothFlying(m_pCurrentEntity->curstate.sequence))
	{	GetAdvFlyingAnim(f, pos, q);
	}
	*/
	if(idx <= MAX_PLAYERS && SmoothFlying(m_pCurrentEntity->curstate.sequence))
	{	GetAdvFlyingAnim(f, pos, q);
	}
	else
	{	panim = StudioGetAnim( m_pRenderModel, pseqdesc );
		StudioCalcRotations( pos, q, pseqdesc, panim, f );
	}

	if (pseqdesc->numblends > 1)
	{
		float				s;
		float				dadt;

		panim += m_pStudioHeader->numbones;
		StudioCalcRotations( pos2, q2, pseqdesc, panim, f );

		dadt = StudioEstimateInterpolant();
		s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0;

		StudioSlerpBones( q, pos, q2, pos2, s );

		if (pseqdesc->numblends == 4)
		{
			panim += m_pStudioHeader->numbones;
			StudioCalcRotations( pos3, q3, pseqdesc, panim, f );

			panim += m_pStudioHeader->numbones;
			StudioCalcRotations( pos4, q4, pseqdesc, panim, f );

			s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0;
			StudioSlerpBones( q3, pos3, q4, pos4, s );

			s = (m_pCurrentEntity->curstate.blending[1] * dadt + m_pCurrentEntity->latched.prevblending[1] * (1.0 - dadt)) / 255.0;
			StudioSlerpBones( q, pos, q3, pos3, s );
		}
	}

	if (CanInterpol())
	{
		// blend from last sequence
		float				s;

		// Only use special positions + quaternions when in smooth flying, we dont need them elsewise
		/* modified by harSens
		if((iter != m_pInterpolGait.end()) && (SmoothFlying(m_pCurrentEntity->curstate.sequence) || SmoothFlying(iter->iRealGaitPrev)) && iter->blStartRecUpper && iter->pModel == m_pRenderModel)
		*/
		if(idx<=MAX_PLAYERS&& (SmoothFlying(m_pCurrentEntity->curstate.sequence) || SmoothFlying(m_InterpolGait[idx].iRealGaitPrev)) && m_InterpolGait[idx].blStartRecUpper && m_InterpolGait[idx].pModel == m_pRenderModel)
		{	s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / INTERPOL_TIME;
			StudioSlerpBones( q, pos, m_InterpolGait[idx].upperqprev, m_InterpolGait[idx].upperposprev, s );
		}
		else
		{	static float		pos1b[MAXSTUDIOBONES][3];
			static vec4_t		q1b[MAXSTUDIOBONES];

			pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence;
			panim = StudioGetAnim( m_pRenderModel, pseqdesc );
			// clip prevframe
			StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe );

			if (pseqdesc->numblends > 1)
			{
				panim += m_pStudioHeader->numbones;
				StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe );

				s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0;
				StudioSlerpBones( q1b, pos1b, q2, pos2, s );

				if (pseqdesc->numblends == 4)
				{
					panim += m_pStudioHeader->numbones;
					StudioCalcRotations( pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe );

					panim += m_pStudioHeader->numbones;
					StudioCalcRotations( pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe );

					s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0;
					StudioSlerpBones( q3, pos3, q4, pos4, s );

					s = (m_pCurrentEntity->latched.prevseqblending[1]) / 255.0;
					StudioSlerpBones( q1b, pos1b, q3, pos3, s );
				}
			}

			s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / INTERPOL_TIME;
			StudioSlerpBones( q, pos, q1b, pos1b, s );
		}
	}
	else
	{
		//Con_DPrintf("prevframe = %4.2f\n", f);
		m_pCurrentEntity->latched.prevframe = f;
	}

	pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);

	bool blGaitSequence = (m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0);
	// calc gait animation
	if (blGaitSequence)
	{	
		if (m_pPlayerInfo->gaitsequence >= m_pStudioHeader->numseq) 
		{	m_pPlayerInfo->gaitsequence = 0;
		}

		// Added by Pcjoe, smooth gait anim interpolation
		bool blSmoothFlying = SmoothFlying(m_pPlayerInfo->gaitsequence);
		if(blSmoothFlying)
		{	GetAdvFlyingAnim( pos2, q2 );	// Get flying animation
		}
		else
		{	pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pPlayerInfo->gaitsequence;
			panim = StudioGetAnim( m_pRenderModel, pseqdesc );
			StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pPlayerInfo->gaitframe );
		}

		// Pcjoe: Interpolate gait animations
		//modified by harSens
		//if(iter != m_pInterpolGait.end() && (cl_interpolgait->value != 0))
		if(idx<=MAX_PLAYERS && cl_interpolgait->value != 0)
		{	// Check if we should interpolate
			if( m_fDoInterp && (m_InterpolGait[idx].flPrevAnimTime + INTERPOL_TIME > m_clTime) &&
				(m_InterpolGait[idx].iPrevSequence != m_pPlayerInfo->gaitsequence) &&
				(blSmoothFlying ? !(IsFlyingAnim(m_pPlayerInfo->gaitsequence) && IsFlyingAnim(m_InterpolGait[idx].iPrevSequence)): true) )				

			{	// Slerp
				float s = 1.0 - (m_clTime - m_InterpolGait[idx].flPrevAnimTime) / INTERPOL_TIME;
				//StudioSlerpBones( q2, pos2, iter->qprev, iter->posprev, s );
				StudioSlerpBones( q2, pos2, m_InterpolGait[idx].qprev, m_InterpolGait[idx].posprev, s );
			}
		}
		
		for (i = 0; i < m_pStudioHeader->numbones; i++)
		{	if (strcmp( pbones[i].name, "Bip01 Spine") == 0)
				break;
			memcpy( pos[i], pos2[i], sizeof( pos[i] ));
			memcpy( q[i], q2[i], sizeof( q[i] ));
		}
	}

	// Copy over bone positions and quaternions for gait interpolation
	if(idx<=MAX_PLAYERS)
	{	// Upper Body
		if(!CanInterpol())
		{	m_InterpolGait[idx].blStartRecUpper = true;
			m_InterpolGait[idx].pModel = m_pRenderModel;
			for(i=0;i<m_pStudioHeader->numbones;i++)
			{	memcpy( m_InterpolGait[idx].upperposprev[i], pos[i], sizeof( m_InterpolGait[idx].upperposprev[i] ));
				memcpy( m_InterpolGait[idx].upperqprev[i], q[i], sizeof( m_InterpolGait[idx].upperqprev[i] ));
			}
		}
		// Gait
		if(blGaitSequence)
		{	for(i=0;i<m_pStudioHeader->numbones;i++)
			{	memcpy( m_InterpolGait[idx].pos[i], pos2[i], sizeof( m_InterpolGait[idx].pos[i] ));
				memcpy( m_InterpolGait[idx].q[i], q2[i], sizeof( m_InterpolGait[idx].q[i] ));
			}
		}
		else
		{	for(i=0;i<m_pStudioHeader->numbones;i++)
			{	memcpy( m_InterpolGait[idx].pos[i], pos[i], sizeof( m_InterpolGait[idx].pos[i] ));
				memcpy( m_InterpolGait[idx].q[i], q[i], sizeof( m_InterpolGait[idx].q[i] ));
			}
		}
	}

	// Added by Pcjoe

	// Modifiy bone origins
	modeloffset = StudioManipBones( pos, q );

	// Search and add blur FX
	/*modified by harSens
	std::list<model_manip_s>::iterator pManip = gHUD.m_ManipModel.FindByPlayerAndOtherIndex(m_pCurrentEntity->index);
	*/
	model_manip_s *pManip = gHUD.m_ManipModel.FindByPlayerAndOtherIndex(m_pCurrentEntity->index);
	if(pManip!=NULL && (pManip->iFlags & MANIP_FLAG_BLURSEQ))
	{	
		if((pManip->iPlayerIndex == m_pCurrentEntity->index) && pManip->iAISeqPlayer != -1)
		{	if(pManip->iAISeqPlayer == m_pCurrentEntity->curstate.sequence)
			{	if(pManip->flAITimePlayer < m_clTime)
				{	pManip->flAITimePlayer = m_clTime + MOTION_BLUR_DELAY;				
					pManip->blPlayedAIPlayer = true;
					if(cl_motionblur->value)
						gHUD.m_MeleeFX.CreateAfterfx(3.5, m_pCurrentEntity->origin + modeloffset, m_vecAngles, m_pCurrentEntity);
				}
			}
			else if(pManip->blPlayedAIPlayer)
			{	if(pManip->iAISeqOther == -1)
					pManip->iFlags &= ~MANIP_FLAG_BLURSEQ;
				pManip->iAISeqPlayer = -1;
				pManip->flAITimePlayer = 0;
			}
		}

		if((pManip->iOtherIndex == m_pCurrentEntity->index) && pManip->iAISeqOther != -1)
		{	if(pManip->iAISeqOther == m_pCurrentEntity->curstate.sequence)
			{	if(pManip->flAITimeOther < m_clTime)
				{	pManip->flAITimeOther = m_clTime + MOTION_BLUR_DELAY;				
					pManip->blPlayedAIOther = true;
					if(cl_motionblur->value)
						gHUD.m_MeleeFX.CreateAfterfx(3.5, m_pCurrentEntity->origin + modeloffset, m_vecAngles, m_pCurrentEntity);
				}
			}
			else if(pManip->blPlayedAIOther)
			{	if(pManip->iAISeqPlayer == -1)
					pManip->iFlags &= ~MANIP_FLAG_BLURSEQ;
				pManip->iAISeqOther = -1;
				pManip->flAITimeOther = 0;
			}
		}

		if(pManip->iFlags == 0)
		{	gHUD.m_ManipModel.Remove(pManip);
		}
	}
	// Teleport FX
	else if(pManip!=NULL && (pManip->blTeleportPlayer || pManip->blTeleportOther))
	{	if(pManip->blTeleportPlayer && pManip->iPlayerIndex == m_pCurrentEntity->index)
		{	gHUD.m_MeleeFX.CreateAfterfx(0.3,pManip->vecTele, m_vecAngles,m_pCurrentEntity);
			pManip->blTeleportPlayer = false;
		}
		else
		{	gHUD.m_MeleeFX.CreateAfterfx(0.3,pManip->vecTele+modeloffset, m_vecAngles,m_pCurrentEntity);
			pManip->blTeleportOther = false;
		}
	}


	// Add offset
	(*m_protationmatrix)[0][3] += modeloffset.x;
	(*m_protationmatrix)[1][3] += modeloffset.y;
	(*m_protationmatrix)[2][3] += modeloffset.z;
	// end of add by Pcjoe

	for (i = 0; i < m_pStudioHeader->numbones; i++) 
	{
		QuaternionMatrix( q[i], bonematrix );

		bonematrix[0][3] = pos[i][0];
		bonematrix[1][3] = pos[i][1];
		bonematrix[2][3] = pos[i][2];

		if (pbones[i].parent == -1) 
		{
			if ( IEngineStudio.IsHardware() )
			{
				ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]);

				// MatrixCopy should be faster...
				//ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]);
				MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] );
			}
			else
			{
				ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]);
				ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]);
			}

			// Apply client-side effects to the transformation matrix
			StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] );			
		} 
		else 
		{
			ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]);
			ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]);
		}
	}
}

// Pcjoe: Set up model bone positions for CMDLControl
void CStudioModelRenderer::StudioSetupBonesMDLControl( CMDLControl *pCtrl )
{	int					i;
	int					iSequence;
	int					iSequenceInterpol;

	mstudiobone_t		*pbones;
	mstudioseqdesc_t	*pseqdesc;
	mstudioanim_t		*panim;

	static float		pos[MAXSTUDIOBONES][3];
	static vec4_t		q[MAXSTUDIOBONES];
	float				bonematrix[3][4];

	static float		pos2[MAXSTUDIOBONES][3];
	static vec4_t		q2[MAXSTUDIOBONES];

	// Reset controllers
	m_pCurrentEntity->curstate.controller[0] = 127;
	m_pCurrentEntity->curstate.controller[1] = 127;
	m_pCurrentEntity->curstate.controller[2] = 127;
	m_pCurrentEntity->curstate.controller[3] = 127;
	m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0];
	m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1];
	m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2];
	m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3];
	
	// Set body part
	m_pCurrentEntity->curstate.body = pCtrl->getBodyPart();

	// Cap sequence(s)
	iSequence = pCtrl->getSequenceNum();
	if (iSequence >= m_pStudioHeader->numseq) 
	{	iSequence = 0;
	}
	else if(iSequence < 0)
	{	iSequence = 0;
	}
	iSequenceInterpol = pCtrl->getInterpolSequenceNum();
	if (iSequenceInterpol >= m_pStudioHeader->numseq) 
	{	iSequenceInterpol = 0;
	}

	// Set sequence & frame on real model ( mainly for model blur effect )
	m_pCurrentEntity->curstate.sequence = iSequence;
	m_pCurrentEntity->curstate.frame = pCtrl->getFrame();

	// Get sequence
	pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + iSequence;
	
	// Get animation
	panim = StudioGetAnim( m_pRenderModel, pseqdesc );
	StudioCalcRotations( pos, q, pseqdesc, panim, pCtrl->getFrame() );

	// Interpolate
	if(iSequenceInterpol >= 0)
	{	// Get sequence interpol
		pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + iSequenceInterpol;
		
		// Get animation interpol
		panim = StudioGetAnim( m_pRenderModel, pseqdesc );
		StudioCalcRotations( pos2, q2, pseqdesc, panim, pCtrl->getInterpolFrame() );

		// SLERP
		StudioSlerpBones( q, pos, q2, pos2, pCtrl->getInterpolPercent() );
	}

	// Get rotation
	vec3_t vecAng = pCtrl->getAngle();
	m_vecAngles = vecAng;
	// Realign rotation to work correctly
	vecAng[PITCH] = -vecAng[PITCH];
	// Convert to matrix
	AngleMatrix (vecAng, (*m_protationmatrix));

	// Set position
	vec3_t vecPosition = pCtrl->getPosition();
	(*m_protationmatrix)[0][3] = vecPosition.x;
	(*m_protationmatrix)[1][3] = vecPosition.y;
	(*m_protationmatrix)[2][3] = vecPosition.z;

	// Calculate final bone transfrm matrix
	pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);
	for (i = 0; i < m_pStudioHeader->numbones; i++) 
	{
		QuaternionMatrix( q[i], bonematrix );

		bonematrix[0][3] = pos[i][0];
		bonematrix[1][3] = pos[i][1];
		bonematrix[2][3] = pos[i][2];

		if (pbones[i].parent == -1) 
		{
			if ( IEngineStudio.IsHardware() )
			{
				ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]);

				// MatrixCopy should be faster...
				//ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]);
				MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] );
			}
			else
			{
				ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]);
				ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]);
			}

			// Apply client-side effects to the transformation matrix
			StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] );		
		} 
		else 
		{
			ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]);
			ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]);
		}
	}
}

/*
====================
Pcjoe: StudioManipBones

====================
*/
void CStudioModelRenderer::SetRotationMatrixAngles( vec3_t angles )
{
	int		i;
	vec3_t	modelpos;

	VectorCopy( angles, m_vecAngles );
	m_vecAngles[PITCH] = -m_vecAngles[PITCH];
	VectorCopy( m_pCurrentEntity->origin, modelpos );
	AngleMatrix (angles, (*m_protationmatrix));

	if ( !IEngineStudio.IsHardware() )
	{
		static float viewmatrix[3][4];

		VectorCopy (m_vRight, viewmatrix[0]);
		VectorCopy (m_vUp, viewmatrix[1]);
		VectorInverse (viewmatrix[1]);
		VectorCopy (m_vNormal, viewmatrix[2]);

		(*m_protationmatrix)[0][3] = modelpos[0] - m_vRenderOrigin[0];
		(*m_protationmatrix)[1][3] = modelpos[1] - m_vRenderOrigin[1];
		(*m_protationmatrix)[2][3] = modelpos[2] - m_vRenderOrigin[2];

		//added by harSens, scaling code from Laurie Cheers (scale in software mode too)
		if (m_pCurrentEntity->curstate.scale != 0)
		{	for (int i = 0; i < 3; i++)
			{	for (int j = 0; j < 3; j++)
				{	(*m_protationmatrix)[i][j] *=m_pCurrentEntity->curstate.scale;
				}
			}
		}

		ConcatTransforms (viewmatrix, (*m_protationmatrix), (*m_paliastransform));

		// do the scaling up of x and y to screen coordinates as part of the transform
		// for the unclipped case (it would mess up clipping in the clipped case).
		// Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y
		// correspondingly so the projected x and y come out right
		// FIXME: make this work for clipped case too?
		for (i=0 ; i<4 ; i++)
		{
			(*m_paliastransform)[0][i] *= m_fSoftwareXScale *
					(1.0 / (ZISCALE * 0x10000));
			(*m_paliastransform)[1][i] *= m_fSoftwareYScale *
					(1.0 / (ZISCALE * 0x10000));
			(*m_paliastransform)[2][i] *= 1.0 / (ZISCALE * 0x10000);
		}
	}

	(*m_protationmatrix)[0][3] = modelpos[0];
	(*m_protationmatrix)[1][3] = modelpos[1];
	(*m_protationmatrix)[2][3] = modelpos[2];

	if ( IEngineStudio.IsHardware() )
	{	//added by harSens, scaling code from Laurie Cheers
		if (m_pCurrentEntity->curstate.scale != 0)
		{	for (int i = 0; i < 3; i++)
			{	for (int j = 0; j < 3; j++)
				{	(*m_protationmatrix)[i][j] *=m_pCurrentEntity->curstate.scale;
				}
			}
		}
	}
}

void CStudioModelRenderer::SetRotationMatrix( vec3_t vecDir )
{	// Set angles + modepos
	vec3_t angles;
	VectorAngles(vecDir, angles);
	angles[PITCH] = -angles[PITCH];

	// Set model rotation
	SetRotationMatrixAngles( angles );
}

vec3_t CStudioModelRenderer::GetBoneOrigin( int iNumBones, mstudiobone_t *pbones, float pos[][3], char *pName )
{	// Get bone origin
	for (int i = 0; i < iNumBones; i++) 
	{
		if(!strcmp(pName,pbones[i].name))
		{	return pos[i];
		}
	}
	return vec3_t(0,0,0);
}

vec3_t CStudioModelRenderer::GetBoneOrigin( cl_entity_t *pEntity, float pos[][3], char *pName )
{	
	if(!pEntity)
	{	return vec3_t(0,0,0);
	}
	// Get Studio Heady + bones index
	studiohdr_t *pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pEntity->model);
	mstudiobone_t *pBones = (mstudiobone_t *)((byte *)pStudioHeader + pStudioHeader->boneindex);

	// Get bone origin
	return GetBoneOrigin(pStudioHeader->numbones, pBones, pos, pName);
}

void CStudioModelRenderer::GetLocalBoneOrigins( int iNumBones, mstudiobone_t *pbones, float inpos[][3], vec4_t *q, float outpos[][3] )
{
	float		bonematrix[3][4];
	float		bonetransform[ MAXSTUDIOBONES ][ 3 ][ 4 ];

	for (int i = 0; i < iNumBones; i++) 
	{
		QuaternionMatrix( q[i], bonematrix );

		bonematrix[0][3] = inpos[i][0];
		bonematrix[1][3] = inpos[i][1];
		bonematrix[2][3] = inpos[i][2];

		if (pbones[i].parent == -1) 
		{
			if ( IEngineStudio.IsHardware() )
			{	ConcatTransforms ((*m_protationmatrix), bonematrix, bonetransform[i]);
			}
			else
			{	ConcatTransforms ((*m_paliastransform), bonematrix, bonetransform[i]);
			}
			bonetransform[i][0][3] = m_pCurrentEntity->origin[0];
			bonetransform[i][1][3] = m_pCurrentEntity->origin[1];
			bonetransform[i][2][3] = m_pCurrentEntity->origin[2];
		} 
		else 
		{	ConcatTransforms (bonetransform[pbones[i].parent], bonematrix, bonetransform[i]);
		}

		outpos[i][0] = bonetransform[i][0][3];
		outpos[i][1] = bonetransform[i][1][3];
		outpos[i][2] = bonetransform[i][2][3];
	}
}



vec3_t CStudioModelRenderer::AverageVectors ( vec3_t vec1, vec3_t vec2 )
{	int i;
	vec3_t vecAverage;
	// Average vectors
	for(i=0;i<3;i++)
	{	vecAverage.x = (vec1.x + vec2.x)/2;
		vecAverage.y = (vec1.y + vec2.y)/2;
		vecAverage.z = (vec1.z + vec2.z)/2;
	}
	return vecAverage;
}

vec3_t CStudioModelRenderer::GetThrownAttachPos( int iIndex, char *pModelName, studiohdr_t *pOtherStudio, float otherpos[][3], vec3_t &vecRotate )
{	mstudiobone_t *pbones = (mstudiobone_t *)((byte *)pOtherStudio + pOtherStudio->boneindex);

	switch(g_PlayerExtraInfo[iIndex].playerclass)
	{
	default:
		{	vec3_t				vecBoneArm;
			vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneArm = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Arm2");
			vecBoneHand = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Hand");

			// Get angle vector from arm + hand
			vecRotate = vecBoneArm - vecBoneHand;

			return vecBoneHand;
		}
	case CLASS_GOKU:
		{	vec3_t				vecBoneArm;
			vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneArm = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Arm2");
			vecBoneHand = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Hand");

			// Get angle vector from arm + hand
			vecRotate = vecBoneArm - vecBoneHand;
			vecBoneHand.z -= 2.5;

			return vecBoneHand;
		}
	case CLASS_PICCOLO:
		{	vec3_t				vecBoneArm;
			vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneArm = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Arm2");
			vecBoneHand = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Hand");

			// Get angle vector from arm + hand
			vecRotate = vecBoneArm - vecBoneHand;
			vecBoneHand.z -= 1.25;

			return vecBoneHand;
		}
	case CLASS_TRUNKS:
		{	vec3_t				vecBoneArm;
			vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneArm = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Arm2");
			vecBoneHand = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Hand");

			// Get angle vector from arm + hand
			vecRotate = vecBoneArm - vecBoneHand;
			vecBoneHand.z -= 0.25;

			return vecBoneHand;
		}
	case CLASS_VEGETA:
		{	vec3_t				vecBoneArm;
			vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneArm = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Arm2");
			vecBoneHand = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Hand");

			// Get angle vector from arm + hand
			vecRotate = vecBoneArm - vecBoneHand;
			vecBoneHand.z -= 1.5;

			return vecBoneHand;
		}
	case CLASS_KRILLIN:
		{	vec3_t				vecBoneArm;
			vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneArm = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Arm2");
			vecBoneHand = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Hand");

			// Get angle vector from arm + hand
			vecRotate = vecBoneArm - vecBoneHand;
			vecBoneHand.z -= 1.3;

			return vecBoneHand;
		}
	case CLASS_BUU:
		{	vec3_t				vecTent1;
			vec3_t				vecTent2;

			// Get tenticle bone origins
			if(!stricmp(pModelName, "models/player/evilbuu/evilbuu.mdl"))
			{	vecTent2 = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"head_tail2");
				vecTent1 = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"head_tail3");
			}
			else
			{	vecTent2 = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"-headtail 03");
				vecTent1 = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"-headtail 04");
			}

			// Get angle vector from tent - tent
			vecRotate = vecTent2 - vecTent1;
			vecTent1.z -= 2.5;

			return vecTent1;
		}
	case CLASS_FRIEZA:
		{	vec3_t				vecBoneArm;
			vec3_t				vecBoneArm2;
			vec3_t				vecBoneHand;
			vec3_t				vecHandRotation;

			// Get hand bone origins
			vecBoneArm = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 L Arm1");
			vecBoneHand = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 L Hand");
			if(!stricmp(pModelName, "models/player/frieza2/frieza2.mdl"))
			{	vecBoneHand.z -= 2.5;
			}
			else
			{	vecBoneHand.z -= 2.5;
			}

			// Get angle vector from arm + hand
			vecRotate = vecBoneArm - vecBoneHand;

			return vecBoneHand;
		}
	case CLASS_GOHAN:
		{	vec3_t				vecBoneArm;
			vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneArm = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Arm2");
			vecBoneHand = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"Bip01 R Hand");

			// Get angle vector from arm + hand
			vecRotate = vecBoneArm - vecBoneHand;
			vecBoneHand.z -= 1.3;

			return vecBoneHand;
		}
	case CLASS_CELL:
		{	vec3_t				vecTail1;
			vec3_t				vecTail2;

			// Get tenticle bone origins
			vecTail2 = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"tail5");
			vecTail1 = GetBoneOrigin(pOtherStudio->numbones, pbones, otherpos,"tail6");

			// Get angle vector from tent - tent
			vecRotate = vecTail2 - vecTail1;
			// Lower tail bone a little
			vecTail1.z -= 2.5;

			return vecTail1;
		}
	}
}

vec3_t CStudioModelRenderer::GetAttachPos( int iIndex, char *pModelName, float pos[][3] )
{	mstudiobone_t *pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);

	switch(g_PlayerExtraInfo[iIndex].playerclass)
	{
	default:
		{	vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneHand = GetBoneOrigin(m_pStudioHeader->numbones, pbones, pos,"Bip01 L Hand");

			return vecBoneHand;
		}
	case CLASS_GOKU:
		{	vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneHand = GetBoneOrigin(m_pStudioHeader->numbones, pbones, pos,"Bip01 L Hand");

			return vecBoneHand;
		}
	case CLASS_VEGETA:
		{	vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneHand = GetBoneOrigin(m_pStudioHeader->numbones, pbones, pos,"Bip01 L Hand");
			vecBoneHand.z -= 1.0;

			return vecBoneHand;
		}
	case CLASS_KRILLIN:
		{	vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneHand = GetBoneOrigin(m_pStudioHeader->numbones, pbones, pos,"Bip01 R Finger1");
			vecBoneHand.z -= 2.5;

			return vecBoneHand;
		}
	case CLASS_PICCOLO:
		{	vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneHand = GetBoneOrigin(m_pStudioHeader->numbones, pbones, pos,"Bip01 L Hand");
			vecBoneHand.z += 0.25;

			return vecBoneHand;
		}
	case CLASS_TRUNKS:
		{	vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneHand = GetBoneOrigin(m_pStudioHeader->numbones, pbones, pos,"Bip01 L Hand");
			vecBoneHand.z -= 1;

			return vecBoneHand;
		}
	case CLASS_BUU:
		{	vec3_t				vecTent;

			// Get tenticle bone origin
			if(!stricmp(pModelName, "models/player/evilbuu/evilbuu.mdl"))
			{	vecTent = GetBoneOrigin(m_pStudioHeader->numbones, pbones, pos,"head_tail3");
				vecTent.z -= 2.5;
			}
			else
			{	vecTent = GetBoneOrigin(m_pStudioHeader->numbones, pbones, pos,"-headtail 04");
				vecTent.z -= 2.5;
			}

			return vecTent;
		}
	case CLASS_FRIEZA:
		{	vec3_t				vecBoneHand;

			// Get hand bone origins
			vecBoneHand = GetBoneOrigin(m_pStudioHeader->numbones, pbones, pos,"Bip01 R Hand");
			if(!stricmp(pModelName, "models/player/frieza2/frieza2.mdl"))
			{	vecBoneHand.z += 1.5;
			}
			else
			{	vecBoneHand.z -= 2.5;
			}

			return vecBoneHand;
		}
	case CLASS_GOHAN:
		{	vec3_t				vecBoneFoot;

			// Get foot bone origins
			vecBoneFoot = GetBoneOrigin(m_pStudioHeader->numbones, pbones, pos,"Bip01 L Foot");
			vecBoneFoot.z -= 2.5;

			return vecBoneFoot;
		}
	case CLASS_CELL:
		{	vec3_t				vecTail;

			// Get tenticle bone origin
			vecTail = GetBoneOrigin(m_pStudioHeader->numbones, pbones, pos,"tail7");
			vecTail.z -= 1.0;

			return vecTail;
		}
	}
}

extern powerupfx *GetPowerUpFXEntry(int EntIndex);
bool CStudioModelRenderer::StudioManipNonPlrBones( float pos[][3], vec4_t *q )
{
	/*modified by harSens
	std::list<model_manip_s>::iterator pManip = gHUD.m_ManipModel.FindByPlayerIndex(m_pCurrentEntity->index);
	*/
	model_manip_s *pManip = gHUD.m_ManipModel.FindByPlayerIndex(m_pCurrentEntity->index);

	if(pManip!=NULL)
	{
		if(pManip->iFlags & MANIP_FLAG_AURABEND)
		{	cl_entity_t *pClientAura;
			cl_entity_t *pOwner;
			vec3_t		vecVelocity;
			vec3_t		vecRealVelocity;
			vec3_t		vecDifference;
			vec3_t		vecDisp;
			vec3_t		v_up;
			float		flFrameTime;
			bool		blChangedBody;

			// Get pointer to aura + owner of aura
			pClientAura = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index );
			if(!pClientAura)
			{	return false;
			}
			else
			{	pOwner = gEngfuncs.GetEntityByIndex( pClientAura->curstate.aiment );
				if(!pOwner)
				{	return false;
				}
			}			

			// Set frametime
			if(pManip->flLastTime)
			{	flFrameTime = m_clTime - pManip->flLastTime;
			}
			else
			{	flFrameTime = 0;
			}
			pManip->flLastTime = m_clTime;

			
			// Create light for aura
			if(!strcmp(m_pRenderModel->name,"models/aura.mdl"))
			{	if(!pManip->dl)
				{	pManip->dl = gEngfuncs.pEfxAPI->CL_AllocDlight (0);
					pManip->dl->radius = 1;
					pManip->dl->color.r = 128;
					pManip->dl->color.g = 128;
					pManip->dl->color.b = 128;
				}

				// Update light position and life
				VectorCopy (pOwner->origin, pManip->dl->origin);
				pManip->dl->die = gEngfuncs.GetClientTime() + 99999;

				// Set radius we should be at
				int setRadius = 0;
				powerupfx *pEntry = GetPowerUpFXEntry(pClientAura->curstate.aiment);
				if(pEntry && pEntry->enabled)
					setRadius = 90;
				else
					setRadius = 140;

				// Interpolate to correct radius
				if(setRadius > pManip->dl->radius)
				{	pManip->dl->radius += 256 * flFrameTime;
					if(pManip->dl->radius > setRadius)
					{	pManip->dl->radius = setRadius;
					}
				}
				else if(setRadius < pManip->dl->radius)
				{	pManip->dl->radius -= 256 * flFrameTime;
					if(pManip->dl->radius < setRadius)
					{	pManip->dl->radius = setRadius;
					}
				}
			}
			// not aura (dash then), no light
			else
			{	if(pManip->dl)
				{	pManip->dl->die = gEngfuncs.GetClientTime()+1;
					pManip->dl->decay = 512;
					pManip->dl = NULL;
				}
			}


			// Hack: Make sure the model has the swoop animation playing, 0 is idle
			if(pOwner->curstate.movetype != MOVETYPE_PLAYERSWOOP || pClientAura->curstate.sequence == 0)
			{	// HACK HACK: Getting velocity by using last recorded origin + current origin
				vecVelocity = (pClientAura->origin - pManip->vecOldOrigin).Normalize();

				// Set direction + old origin
				vecRealVelocity = vecVelocity;
				pManip->vecOldOrigin = pClientAura->origin;
			
				// Get Vector Angles
				AngleVectors(vecVelocity, NULL, NULL, v_up);

				// Not sure how this exactly works, but it seems to work well
				vecVelocity = vecVelocity - v_up;

				// Flip aura if our z velocity is negitive ( falling )
				if(pClientAura->curstate.body == 0 &&
					pOwner->curstate.movetype == MOVETYPE_WALK)
				{
					vec3_t vecNormalized = vecRealVelocity.Normalize();
					if(vecNormalized.z < 0)
					{	vecVelocity.z *= -1;
					}

					vecVelocity = vecVelocity.Normalize();
				}

				// 0 = Up, 1 = Down
				if(pClientAura->curstate.body != pManip->iBody)
				{	blChangedBody = true;
				}
				else
				{	blChangedBody = false;
				}

				vecVelocity = vecVelocity.Normalize();

				// HACK HACK: If we are in idle position, make sure to blend to the closest y value ( 1 or -1 )
				if(vecRealVelocity == vec3_t(0,0,1))
				{
					if(pManip->vecDir.y >= 0)
					{	vecVelocity = vec3_t(0,1,0);
					}
					else
					{	vecVelocity = vec3_t(0,-1,0);
					}
				}

				// First time running? Set the last velocity to the current
				if(!pManip->blAttached)
				{	pManip->vecDir = vecVelocity;
					pManip->blAttached = !pManip->blAttached;
				}

				// Interpolate, dont blend if we flipped the aura
				if(!blChangedBody)
				{	vecDifference = vecVelocity - pManip->vecDir;

					float Length = INTERPOL_AURABEND_SPEED * flFrameTime;
					if(Length > vecDifference.Length())
						Length = vecDifference.Length();

					pManip->vecDir = pManip->vecDir + vecDifference * Length;
				}
				else
				{	pManip->iBody = pClientAura->curstate.body;
					pManip->vecDir = vecVelocity;
				}

				// Fix "swirling" problem between some blends
				vecDisp = pManip->vecDir;

				vec3_t vecxy;
				vecxy.x = vecDisp.x;
				vecxy.y = vecDisp.y;
				vecxy.z = 0;
				float flz = vecDisp.z;
				if(flz < 0)
				{	flz = -flz;
				}
				if(vecxy.x < 0)
				{	vecxy.x = -vecxy.x;
				}
				if(vecxy.y < 0)
				{	vecxy.y = -vecxy.y;
				}
				float flRatio = vecxy.Length() * flz;
			
				vecDisp.z *= flRatio * vecxy.Length();
				SetRotationMatrix(vecDisp);
			}
			// Swoop
			else
			{	int iOffset = 6;
				int i;
				vec3_t angles;
				vec3_t v_forward, v_right, v_up;
				vec3_t origin;
				AngleVectors(pOwner->curstate.angles, v_forward, v_right, v_up); 

				// Get origin
				if(IEngineStudio.IsHardware())
				{	for(i=0;i<3;i++)
						origin[i] = (*m_protationmatrix)[i][3];
				}
				else
				{	for(i=0;i<3;i++)
						origin[i] = (*m_paliastransform)[i][3];
				}

				// Set angles / origin offsets
				angles[ROLL] = 0;
				switch(int(pOwner->curstate.vuser4[0]))
				{
				case SWOOP_UP:
					{	angles[PITCH] = 0;
						angles[YAW] = pOwner->curstate.angles[YAW];
						break;
					}
				case SWOOP_DOWN:
					{	angles[PITCH] = 180;
						angles[YAW] = pOwner->curstate.angles[YAW];
						origin = origin + v_up * iOffset;
						break;
					}
				case SWOOP_LEFT:
					{	angles[PITCH] = 90;
						angles[YAW] = pOwner->curstate.angles[YAW] + 90;
						origin = origin + v_right * iOffset;
						break;
					}
				case SWOOP_RIGHT:
					{	angles[PITCH] = 90;
						angles[YAW] = pOwner->curstate.angles[YAW] - 90;
						origin = origin + -v_right * iOffset;
						break;
					}
				default:
				case SWOOP_FRONT:
					{	angles[PITCH] = 90 + pOwner->curstate.angles[PITCH] * -3;
						angles[YAW] = pOwner->curstate.angles[YAW];
						break;
					}
				case SWOOP_BACK:
					{	angles[PITCH] = 90 + pOwner->curstate.angles[PITCH] * 3;
						angles[YAW] = pOwner->curstate.angles[YAW] + 180;
						break;
					}
				}

				// Set rotation on aura
				SetRotationMatrixAngles(angles);

				// Reset origin
				if(IEngineStudio.IsHardware())
				{	for(i=0;i<3;i++)
						(*m_protationmatrix)[i][3] = origin[i];
				}
				else
				{	for(i=0;i<3;i++)
						(*m_paliastransform)[i][3] = origin[i];
				}
			}

			return true;
		}
		// Set body to -1 so it will reset next time we turn it on
		else if(pManip->iFlags & MANIP_FLAG_AURABEND)
		{	if(pManip->iBody != -1)
			{	pManip->iBody = -1;
			}
		}
	}
	return false;
}

vec3_t CStudioModelRenderer::StudioManipBones( float pos[][3], vec4_t *q )
{	
	/*modified by harSens
	std::list<model_manip_s>::iterator pManip;
	*/
	model_manip_s *pManip;

	pManip = gHUD.m_ManipModel.FindByPlayerIndex(m_pCurrentEntity->index);

	if(pManip!=NULL)
	{	
		if((pManip->iFlags & MANIP_FLAG_ANGLE_FIX) || (pManip->iFlags & MANIP_FLAG_ANGLE_FIX_ENT))
		{	return vec3_t(0,0,0);
		}

		// This manip isn't used for player manipulation
		if(!pManip->iOtherIndex)
		{	return vec3_t(0,0,0);
		}

		static float		localpos[MAXSTUDIOBONES][3];
		studiohdr_t			*pStudioHeaderOther;
		mstudiobone_t		*pbones;
		mstudiobone_t		*pbonesother;
		cl_entity_t			*pOther;

		pOther = gEngfuncs.GetEntityByIndex( pManip->iOtherIndex );

		// If our entity isnt valid, dont effect the model
		if(!pOther)
		{	return vec3_t(0,0,0);
		}

		// Get bones for player
		pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);

		// Get bones for enemy
		pStudioHeaderOther = (studiohdr_t *)IEngineStudio.Mod_Extradata (pOther->model);
		pbonesother = (mstudiobone_t *)((byte *)pStudioHeaderOther + pStudioHeaderOther->boneindex);


		// "Connected", offset distance between
		if(pManip->iFlags & MANIP_FLAG_CONNECT)
		{	
			vec3_t				vecBoneOtherBip;
			vec3_t				vecBonePlayerBip;
			vec3_t				vecBoneOffset;
			vec3_t				vecForward;

			if(!pManip->blAttached)
			{	pManip->blAttached = true;
			}

			if(!pManip->blCanUseOtherPos)
			{	return vec3_t(0,0,0);
			}

			if(!pManip->blFixedAngles)
			{	return vec3_t(0,0,0);
			}

			// Get Bip bone origin
			vecBoneOtherBip = GetBoneOrigin(pStudioHeaderOther->numbones, pbonesother, pManip->otherpos,"Bip01 Spine");
			// Get bone origins for player
			GetLocalBoneOrigins( m_pStudioHeader->numbones, pbones, pos, q, localpos );
			vecBonePlayerBip = GetBoneOrigin(m_pStudioHeader->numbones, pbones, localpos,"Bip01 Spine");

			// Get angles
			AngleVectors(pManip->vecAngles, vecForward, NULL, NULL);

			// Flip the pitch
			vecForward.z = -vecForward.z;

			// Set rotation matrix for both characters
			SetRotationMatrix(-vecForward);

			// Set offset for local player
			vecBoneOffset = vecForward * pManip->iDistance;

			// Set view angles
			pManip->vecViewAngles = -vecForward;
			VectorNormalize(pManip->vecViewAngles);
		
			// Set view origins
			pManip->vecViewOriginPlayer = vecBonePlayerBip;
			pManip->vecViewOriginOther = vecBoneOtherBip;

			return vecBoneOffset;
		}
		// Grab (swing the person by left/right hand)
		if(pManip->iFlags & MANIP_FLAG_GRAB)
		{	vec3_t				vecRotate;
			vec3_t				vecThrownAttach;
			vec3_t				vecAttach;
			vec3_t				vecBoneOffset;
			vec3_t				vecBoneOtherBip;
			vec3_t				vecBonePlayerBip;

			if(!pManip->blAttached)
			{	pManip->blAttached = true;
			}

			if(!pManip->blCanUseOtherPos)
			{	return vec3_t(0,0,0);
			}
			
			// Get BIP Pos
			vecBonePlayerBip = GetBoneOrigin(pStudioHeaderOther->numbones, pbonesother, pManip->otherpos,"Bip01");

			// Get attachment point of thrown player + Rotate
			vecThrownAttach = GetThrownAttachPos( pManip->iOtherIndex, pOther->model->name, pStudioHeaderOther, pManip->otherpos, vecRotate );
			SetRotationMatrix(vecRotate);

			// Get bone origins for player
			GetLocalBoneOrigins( m_pStudioHeader->numbones, pbones, pos, q, localpos );

			// Get BIP Pos
			vecBoneOtherBip = GetBoneOrigin(m_pStudioHeader->numbones, pbones, localpos,"Bip01");

			// Get Attachment point
			vecAttach = GetAttachPos( pManip->iPlayerIndex, m_pCurrentEntity->model->name, localpos );

			// Set offset
			vecBoneOffset = (vecThrownAttach-vecAttach);

			// Set view origins
			pManip->vecViewOriginPlayer = vecBonePlayerBip;
			pManip->vecViewOriginOther = vecBoneOtherBip;

			return vecBoneOffset;
		}
		// Melee struggle ( push hands together, small offset inbetween )
		if(pManip->iFlags & MANIP_FLAG_MSTRUGGLE)
		{
			vec3_t				vecBoneOtherArmR;
			vec3_t				vecBoneOtherHandR;
			vec3_t				vecBoneOtherArmL;
			vec3_t				vecBoneOtherHandL;
			vec3_t				vecBonePlayerHandL;
			vec3_t				vecBonePlayerHandR;
			vec3_t				vecBoneArmAngle;
			vec3_t				vecBoneOtherArmAverage;
			vec3_t				vecBoneOtherHandAverage;
			vec3_t				vecBonePlayerHandAverage;
			vec3_t				vecRight;
			vec3_t				vecBoneOffset;
			vec3_t				vecBoneOtherSpine;
			vec3_t				vecBonePlayerSpine;
			vec3_t				vecBoneOtherBip;
			vec3_t				vecBonePlayerBip;

			if(!pManip->blAttached)
			{	pManip->blAttached = true;
			}

			if(!pManip->blCanUseOtherPos)
			{	return vec3_t(0,0,0);
			}

			// Get BIP Pos
			vecBonePlayerBip = GetBoneOrigin(pStudioHeaderOther->numbones, pbonesother, pManip->otherpos,"Bip01");

			// Get spine origin
			vecBoneOtherSpine = GetBoneOrigin(pStudioHeaderOther->numbones, pbonesother, pManip->otherpos,"Bip01 Spine");

			// Get hand bone origins
			vecBoneOtherArmR = GetBoneOrigin(pStudioHeaderOther->numbones, pbonesother, pManip->otherpos,"Bip01 R Arm2");
			vecBoneOtherHandR = GetBoneOrigin(pStudioHeaderOther->numbones, pbonesother, pManip->otherpos,"Bip01 R Hand");
			vecBoneOtherArmL = GetBoneOrigin(pStudioHeaderOther->numbones, pbonesother, pManip->otherpos,"Bip01 L Arm2");
			vecBoneOtherHandL = GetBoneOrigin(pStudioHeaderOther->numbones, pbonesother, pManip->otherpos,"Bip01 L Hand");

			// Get angle vector from arm + hand
			vecBoneOtherArmAverage = AverageVectors(vecBoneOtherArmR, vecBoneOtherArmL);
			vecBoneOtherHandAverage = AverageVectors(vecBoneOtherHandR, vecBoneOtherHandL);
			vecBoneArmAngle = vecBoneOtherArmAverage - vecBoneOtherHandAverage;

			// Using the angle of the arm to hand, set it as the players rotation
			SetRotationMatrix(vecBoneArmAngle);

			// Set view angles
			pManip->vecViewAngles = vecBoneArmAngle;
			pManip->vecViewAngles.z = 0;
			VectorNormalize(pManip->vecViewAngles);

			// Get bone origins for player
			GetLocalBoneOrigins( m_pStudioHeader->numbones, pbones, pos, q, localpos );

			// Get BIP Pos
			vecBoneOtherBip = GetBoneOrigin(m_pStudioHeader->numbones, pbones, localpos,"Bip01");

			// Get Hand Pos
			vecBonePlayerHandL = GetBoneOrigin(m_pStudioHeader->numbones, pbones, localpos,"Bip01 L Hand");
			vecBonePlayerHandR = GetBoneOrigin(m_pStudioHeader->numbones, pbones, localpos,"Bip01 R Hand");

			// Get spine origin
			vecBonePlayerSpine = GetBoneOrigin(m_pStudioHeader->numbones, pbones, localpos,"Bip01 Spine");

			// Get average position between hands
			vecBonePlayerHandAverage = AverageVectors(vecBonePlayerHandR, vecBonePlayerHandL);

			// Set offset
			vecBoneOffset = (vecBoneOtherHandAverage-vecBonePlayerHandAverage) - vecBoneArmAngle.Normalize()*.5;

			// Set view origins
			pManip->vecViewOriginPlayer = vecBonePlayerBip;
			pManip->vecViewOriginOther = vecBoneOtherBip;

			return vecBoneOffset;
		}
	}

	return vec3_t(0,0,0);
}

/*
====================
StudioSaveBones

====================
*/
void CStudioModelRenderer::StudioSaveBones( void )
{
	// Edited by Pcjoe: Save bone origins
	int		i, n;
	bool	blSavePlayer=false, blSaveOther=false;
	
	/*modified by harSens
	std::list<model_manip_s>::iterator pOtherManip = gHUD.m_ManipModel.FindByOtherIndex(m_pCurrentEntity->index);
	std::list<model_manip_s>::iterator pPlayerManip = gHUD.m_ManipModel.FindByPlayerIndex(m_pCurrentEntity->index);
	*/
	model_manip_s *pOtherManip = gHUD.m_ManipModel.FindByOtherIndex(m_pCurrentEntity->index);
	model_manip_s *pPlayerManip = gHUD.m_ManipModel.FindByPlayerIndex(m_pCurrentEntity->index);

	if(pPlayerManip!=NULL && (pPlayerManip->iFlags & MANIP_FLAG_RECPOS))
	{	blSavePlayer = true;
		if(!pPlayerManip->blCanUsePlayerPos)
		{	pPlayerManip->blCanUsePlayerPos = true;
		}
	}

	if(pOtherManip!=NULL && (pOtherManip->iFlags & MANIP_FLAG_RECPOS))
	{	blSaveOther = true;
		if(!pOtherManip->blCanUseOtherPos)
		{	pOtherManip->blCanUseOtherPos = true;
		}
	}

	// Pcjoe: Save bone data
	int idx=0;
	if(m_pCurrentEntity->baseline.movetype < 0)
		idx = m_pCurrentEntity->baseline.movetype;
	else
		idx = m_pCurrentEntity->index;
	CBoneAccessor *pAccessor = gBoneManager.findAccessor(idx);
	if(pAccessor)
	{	// Set temp entities studio header
		if(idx<0)
			pAccessor->setTempEntity(m_pCurrentEntity);
		// Make sure we're using the same model
		pAccessor->checkModel();
		// Update bone positional and rotational data
		pAccessor->setBoneData(m_pbonetransform);
		// Update render data ( render position + angle )
		pAccessor->setRenderData(m_protationmatrix,m_vecAngles);
		// Update attachments
		pAccessor->updateAttachments();
		// Update valid data tag if not set
		if(!pAccessor->hasValidData())
			pAccessor->setValidData(true);
	}


	mstudiobone_t		*pbones;
	pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);

	m_nCachedBones = m_pStudioHeader->numbones;

	for (i = 0; i < m_pStudioHeader->numbones; i++) 
	{
		strcpy( m_nCachedBoneNames[i], pbones[i].name );
		MatrixCopy( (*m_pbonetransform)[i], m_rgCachedBoneTransform[i] );
		MatrixCopy( (*m_plighttransform)[i], m_rgCachedLightTransform[i] );
		
		// Save bone origins
		if(blSavePlayer)
		{	for(n=0;n<3;n++)
			{	pPlayerManip->playerpos[i][n] = (*m_pbonetransform)[i][n][3];
			}
		}
		if(blSaveOther)
		{	for(n=0;n<3;n++)
			{	pOtherManip->otherpos[i][n] = (*m_pbonetransform)[i][n][3];
			}
		}
	}
}


/*
====================
StudioMergeBones

====================
*/
void CStudioModelRenderer::StudioMergeBones ( model_t *m_pSubModel )
{
	int					i, j;
	double				f;
	int					do_hunt = true;
	//added by PcJoe
	bool				blSetupBones;

	mstudiobone_t		*pbones;
	mstudioseqdesc_t	*pseqdesc;
	mstudioanim_t		*panim;

	static float		pos[MAXSTUDIOBONES][3];
	float				bonematrix[3][4];
	static vec4_t		q[MAXSTUDIOBONES];

	if (m_pCurrentEntity->curstate.sequence >=  m_pStudioHeader->numseq) 
	{
		m_pCurrentEntity->curstate.sequence = 0;
	}

	pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence;

	f = StudioEstimateFrame( pseqdesc );

	if (m_pCurrentEntity->latched.prevframe > f)
	{
		//Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f );
	}

	panim = StudioGetAnim( m_pSubModel, pseqdesc );
	StudioCalcRotations( pos, q, pseqdesc, panim, f );

	
	pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);
	
	blSetupBones = StudioManipNonPlrBones(pos, q);
	
	if(!blSetupBones)
	{
		for (i = 0; i < m_pStudioHeader->numbones; i++) 
		{
			for (j = 0; j < m_nCachedBones; j++)
			{
				if (stricmp(pbones[i].name, m_nCachedBoneNames[j]) == 0)
				{
					MatrixCopy( m_rgCachedBoneTransform[j], (*m_pbonetransform)[i] );
					MatrixCopy( m_rgCachedLightTransform[j], (*m_plighttransform)[i] );
					break;
				}
			}
			if (j >= m_nCachedBones)
			{
				QuaternionMatrix( q[i], bonematrix );

				bonematrix[0][3] = pos[i][0];
				bonematrix[1][3] = pos[i][1];
				bonematrix[2][3] = pos[i][2];

				if (pbones[i].parent == -1) 
				{	if ( IEngineStudio.IsHardware() )
					{
						ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]);

						// MatrixCopy should be faster...
						//ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]);
						MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] );
					} 
					else 
					{
						ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]);
						ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]);
					}

					// Apply client-side effects to the transformation matrix
					StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] );
				}
				else 
				{
					ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]);
					ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]);
				}
			}
		}
	}
	// Pcjoe: Rotate our bone origins
	else
	{
		for (i = 0; i < m_pStudioHeader->numbones; i++) 
		{
			QuaternionMatrix( q[i], bonematrix );

			bonematrix[0][3] = pos[i][0];
			bonematrix[1][3] = pos[i][1];
			bonematrix[2][3] = pos[i][2];

			if (pbones[i].parent == -1) 
			{	//added by harSens: rescale bones
				for (int x=0;x<3;x++)
				{	for(int y=0;y<4;y++)
					{	bonematrix[x][y] *= 0.25;
					}
				}

				if ( IEngineStudio.IsHardware() )
				{
					ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]);
					MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] );
				}
				else
				{
					ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]);
					ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]);
				}
			} 
			else 
			{
				ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]);
				ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]);
			}
		}
	}
}

/*
===================
StudioDrawModel
Pcjoe: Use data in CMDLControl class

===================
*/
int CStudioModelRenderer::StudioDrawModel( CMDLControl *pModelControl )
{
	alight_t lighting;
	vec3_t dir;

	// Copy over ent data
	cl_entity_t localentity = (*gEngfuncs.GetLocalPlayer());
	m_pCurrentEntity = &localentity;
	m_pCurrentEntity->curstate.renderfx = kRenderNormal;
	
	IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime );
	IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal );
	IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale );

	m_pRenderModel = pModelControl->getModel();
	m_pStudioHeader = pModelControl->getStudioHeader();

	IEngineStudio.SetRenderModel( m_pRenderModel );
	IEngineStudio.StudioSetHeader( m_pStudioHeader );

	StudioSetUpTransform( 0 );

	(*m_pModelsDrawn)++;
	(*m_pStudioModelCount)++; // render data cache cookie

	if (m_pStudioHeader->numbodyparts == 0)
		return 1;

	StudioSetupBonesMDLControl(pModelControl);

	lighting.ambientlight = 30;
	lighting.shadelight = 180;
	lighting.color = vec3_t(60,60,60);
	lighting.plightvec = vec3_t(10,0,0);

/*	lighting.plightvec = dir;
	IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting );*/
	IEngineStudio.StudioEntityLight( &lighting );
	IEngineStudio.StudioSetupLighting (&lighting);
	IEngineStudio.StudioSetRemapColors( 0, 0 );

	StudioRenderModel( );

	return 1;
}

/*
====================
StudioDrawModel

====================
*/
int CStudioModelRenderer::StudioDrawModel( int flags )
{
	alight_t lighting;
	vec3_t dir;
	
	m_pCurrentEntity = IEngineStudio.GetCurrentEntity();

	// Added by Pcjoe, use this index for modeblur and modelcontrol
	int idx=0;
	if(m_pCurrentEntity->baseline.movetype < 0)
		idx = m_pCurrentEntity->baseline.movetype;
	else
		idx = m_pCurrentEntity->index;
	
	IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime );
	IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal );
	IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale );

	//added by harSens: draw after fx (based on dead player drawing)
	if (m_pCurrentEntity->curstate.renderfx == kRenderFxTeleportAfterImage)
	{
		entity_state_t afterfx,temp;

		int result;
		int save_interp;

		if (m_pCurrentEntity->curstate.rendercolor.r <= 0 || m_pCurrentEntity->curstate.rendercolor.r > gEngfuncs.GetMaxClients() )
			return 0;

		// Removed by Pcjoe: First the "flFraction" message, and now drawing afterfx spamming my ocnsole -_-
//		ConsolePrint("Drawing afterfx\n");
		// get copy of player
		temp = *(IEngineStudio.GetPlayerState( m_pCurrentEntity->curstate.rendercolor.r - 1 )); //cl.frames[cl.parsecount & CL_UPDATE_MASK].playerstate[m_pCurrentEntity->curstate.renderamt-1];
		memcpy(&afterfx,&temp,sizeof(entity_state_t));

		// clear weapon, movement state
		afterfx.number = m_pCurrentEntity->curstate.rendercolor.r;
		afterfx.weaponmodel = 0;
		afterfx.gaitsequence = 0;

		afterfx.movetype = MOVETYPE_NONE;
		VectorCopy( m_pCurrentEntity->curstate.angles, afterfx.angles );
		VectorCopy( m_pCurrentEntity->curstate.origin, afterfx.origin );
		
		save_interp = m_fDoInterp;
		m_fDoInterp = 0;
		
		// draw as though it were a player
		player_info_s save_plinfo, *pInfo;
		save_plinfo = *IEngineStudio.PlayerInfo( m_pCurrentEntity->curstate.rendercolor.r-1 );
		
		result = StudioDrawPlayerModel( flags|FLAG_AFTERIMAGE, &afterfx );
		
		//memcpy(&save_plinfo,m_pPlayerInfo,sizeof(player_info_s));
		pInfo=IEngineStudio.PlayerInfo( m_pCurrentEntity->curstate.rendercolor.r-1 );
		*pInfo=save_plinfo;
		m_fDoInterp = save_interp;
		
		return result;
	}


	if (m_pCurrentEntity->curstate.renderfx == kRenderFxDeadPlayer)
	{
		entity_state_t deadplayer;

		int result;
		int save_interp;

		if (m_pCurrentEntity->curstate.renderamt <= 0 || m_pCurrentEntity->curstate.renderamt > gEngfuncs.GetMaxClients() )
			return 0;

		// get copy of player
		deadplayer = *(IEngineStudio.GetPlayerState( m_pCurrentEntity->curstate.renderamt - 1 )); //cl.frames[cl.parsecount & CL_UPDATE_MASK].playerstate[m_pCurrentEntity->curstate.renderamt-1];

		// clear weapon, movement state
		deadplayer.number = m_pCurrentEntity->curstate.renderamt;
		deadplayer.weaponmodel = 0;
		deadplayer.gaitsequence = 0;

		deadplayer.movetype = MOVETYPE_NONE;
		VectorCopy( m_pCurrentEntity->curstate.angles, deadplayer.angles );
		VectorCopy( m_pCurrentEntity->curstate.origin, deadplayer.origin );

		save_interp = m_fDoInterp;
		m_fDoInterp = 0;
		
		// draw as though it were a player
		/* modified by harSens
		result = StudioDrawPlayer( flags, &deadplayer );
		*/
		result = StudioDrawPlayerModel( flags, &deadplayer );
		
		m_fDoInterp = save_interp;
		return result;
	}

	m_pRenderModel = m_pCurrentEntity->model;
	m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel);
	IEngineStudio.StudioSetHeader( m_pStudioHeader );
	IEngineStudio.SetRenderModel( m_pRenderModel );

	StudioSetUpTransform( 0 );

	// Added by Pcjoe, get model control
	CMDLControl *pCtrl = gModelControl.findModelControl(idx);

	if (flags & STUDIO_RENDER)
	{
		// see if the bounding box lets us trivially reject, also sets
		// Force render if we have a control model
		if (!IEngineStudio.StudioCheckBBox() && !pCtrl)
			return 0;

		(*m_pModelsDrawn)++;
		(*m_pStudioModelCount)++; // render data cache cookie

		if (m_pStudioHeader->numbodyparts == 0)
			return 1;
	}

	// Edited by Pcjoe
//	if (m_pCurrentEntity->curstate.movetype == MOVETYPE_FOLLOW)
	if (m_pCurrentEntity->curstate.movetype == MOVETYPE_FOLLOW && !IsDiskAttack())
	{
		StudioMergeBones( m_pRenderModel );
	}
	else
	{
		// Pcjoe: Support for model control
		if(pCtrl)
			StudioSetupBonesMDLControl(pCtrl);
		else
            StudioSetupBones( );
	}
	StudioSaveBones( );
	// Pcjoe: Motion Blur FX
	gModelBlur.Think(idx, gEngfuncs.GetClientTime());

	if (flags & STUDIO_EVENTS)
	{
		StudioCalcAttachments( );
		IEngineStudio.StudioClientEvents( );
		// copy attachments into global entity array
		if ( m_pCurrentEntity->index > 0 )
		{
			cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index );

			memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 );
		}
	}

	if (flags & STUDIO_RENDER)
	{
		lighting.plightvec = dir;
		IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting );

		IEngineStudio.StudioEntityLight( &lighting );

		// model and frame independant
		IEngineStudio.StudioSetupLighting (&lighting);

		// get remap colors
		m_nTopColor = m_pCurrentEntity->curstate.colormap & 0xFF;
		m_nBottomColor = (m_pCurrentEntity->curstate.colormap & 0xFF00) >> 8;

		IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor );

		StudioRenderModel( );
	}

	return 1;
}

/*
====================
StudioEstimateGait

====================
*/
void CStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer )
{
	float dt;
	vec3_t est_velocity;

	dt = (m_clTime - m_clOldTime);
	if (dt < 0)
		dt = 0;
	else if (dt > 1.0)
		dt = 1;

	if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount)
	{
		m_flGaitMovement = 0;
		return;
	}

	// VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity );
	if ( m_fGaitEstimation )
	{
		VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity );
		VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin );
		m_flGaitMovement = Length( est_velocity );
		if (dt <= 0 || m_flGaitMovement / dt < 5)
		{
			m_flGaitMovement = 0;
			est_velocity[0] = 0;
			est_velocity[1] = 0;
		}
	}
	else
	{
		VectorCopy( pplayer->velocity, est_velocity );
		m_flGaitMovement = Length( est_velocity ) * dt;
	}

	if (est_velocity[1] == 0 && est_velocity[0] == 0)
	{
		float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw;
		flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360;
		if (flYawDiff > 180)
			flYawDiff -= 360;
		if (flYawDiff < -180)
			flYawDiff += 360;

		if (dt < 0.25)
			flYawDiff *= dt * 4;
		else
			flYawDiff *= dt;

		m_pPlayerInfo->gaityaw += flYawDiff;
		m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360;

		m_flGaitMovement = 0;
	}
	else
	{
		m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI);
		if (m_pPlayerInfo->gaityaw > 180)
			m_pPlayerInfo->gaityaw = 180;
		if (m_pPlayerInfo->gaityaw < -180)
			m_pPlayerInfo->gaityaw = -180;
	}

}

/*
====================
StudioProcessGait

====================
*/
void CStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer )
{
	// Added by Pcjoe
	/*modified by harSens
	std::list<model_manip_s>::iterator pManip;
	*/
	model_manip_s *pManip;

	mstudioseqdesc_t	*pseqdesc;
	float dt;
	int iBlend;
	float flYaw;	 // view direction relative to movement

	if (m_pCurrentEntity->curstate.sequence >=  m_pStudioHeader->numseq) 
	{
		m_pCurrentEntity->curstate.sequence = 0;
	}

	pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence;

	StudioPlayerBlend( pseqdesc, &iBlend, &m_pCurrentEntity->angles[PITCH] );

	m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH];
	m_pCurrentEntity->curstate.blending[0] = iBlend;
	m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0];
	m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0];

	// Con_DPrintf("%f %d\n", m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->blending[0] );

	dt = (m_clTime - m_clOldTime);
	if (dt < 0)
		dt = 0;
	else if (dt > 1.0)
		dt = 1;

	StudioEstimateGait( pplayer );

	// Pcjoe: Lock Gait
	pManip = gHUD.m_ManipModel.FindByPlayerAndOtherIndex(m_pCurrentEntity->index);
	if(pManip!=NULL && pManip->blLockGait)
	{	m_pPlayerInfo->gaityaw = m_pCurrentEntity->angles[YAW];
	}

	// Con_DPrintf("%f %f\n", m_pCurrentEntity->angles[YAW], m_pPlayerInfo->gaityaw );

	// calc side to side turning
	flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw;
	flYaw = flYaw - (int)(flYaw / 360) * 360;
	if (flYaw < -180)
		flYaw = flYaw + 360;
	if (flYaw > 180)
		flYaw = flYaw - 360;

	if (flYaw > 120)
	{
		m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180;
		m_flGaitMovement = -m_flGaitMovement;
		flYaw = flYaw - 180;
	}
	else if (flYaw < -120)
	{
		m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180;
		m_flGaitMovement = -m_flGaitMovement;
		flYaw = flYaw + 180;
	}

	// adjust torso
	m_pCurrentEntity->curstate.controller[0] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
	m_pCurrentEntity->curstate.controller[1] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
	m_pCurrentEntity->curstate.controller[2] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
	m_pCurrentEntity->curstate.controller[3] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
	m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0];
	m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1];
	m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2];
	m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3];

	m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw;
	if (m_pCurrentEntity->angles[YAW] < -0)
		m_pCurrentEntity->angles[YAW] += 360;
	m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW];

	if (pplayer->gaitsequence >= m_pStudioHeader->numseq) 
	{
		pplayer->gaitsequence = 0;
	}

	pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence;

	// calc gait frame
	if (pseqdesc->linearmovement[0] > 0)
	{
		m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes;
	}
	else
	{
		m_pPlayerInfo->gaitframe += pseqdesc->fps * dt;
	}

	// do modulo
	m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes;
	if (m_pPlayerInfo->gaitframe < 0)
		m_pPlayerInfo->gaitframe += pseqdesc->numframes;
	// Added by Pcjoe, stop non-looping animations
	if(!(pseqdesc->flags & STUDIO_LOOPING))
	{	if(m_pPlayerInfo->gaitframe >= pseqdesc->numframes - 1)
			m_pPlayerInfo->gaitframe = pseqdesc->numframes - 1;

		if(m_pPlayerInfo->gaitframe < 0)
			m_pPlayerInfo->gaitframe = 0;
	}
}

void CStudioModelRenderer::UpdateDiamond()
{	
	// calculate rotation
	m_flRotationDiamond += DIAMOND_ROTATIONSPEED * (m_clTime-m_clOldTime);
	while(m_flRotationDiamond > 360)
	{	m_flRotationDiamond -= 360;
	}
	m_fDrawDiamond[m_pCurrentEntity->index]=true;	
}

// Pcjoe: Get Diamond Origin
vec3_t CStudioModelRenderer::GetDiamondOrigin( cl_entity_t *pClient )
{	vec3_t vecOrigin;
	
	/* modified by harSens
	std::list<model_manip_s>::iterator pManip = gHUD.m_ManipModel.FindByPlayerAndOtherIndex(pClient->index);
	*/
	model_manip_s *pManip = gHUD.m_ManipModel.FindByPlayerAndOtherIndex(pClient->index);

	if(pManip!=NULL)
	{	if((pManip->iPlayerIndex == pClient->index) && pManip->blCanUsePlayerPos)
		{	vecOrigin = GetBoneOrigin( pClient, pManip->playerpos, "Bip01 Spine" );
			vecOrigin.z += 25;
			return vecOrigin;
		}
		else if((pManip->iOtherIndex == pClient->index) && pManip->blCanUseOtherPos)
		{	vecOrigin = GetBoneOrigin( pClient, pManip->otherpos, "Bip01 Spine" );
			vecOrigin.z += 25;
			return vecOrigin;
		}
	}

	vecOrigin = pClient->origin;
	vecOrigin.z += 25;
	return vecOrigin;
}

void CStudioModelRenderer::DrawHalos()
{
	for(int i = 1; i < MAX_PLAYERS; i++)
	{	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(i);
		
		// If player isn't valid
		if(!pClient)
		{	continue;
		}

		// If its not a player, dont draw a triangle
		if ( !pClient->player )
		{	continue;
		}

		if ( pClient->curstate.rendermode == kRenderTransTexture && pClient->curstate.renderfx == kRenderFxStrobeFaster )
		{
			vec3_t vecOrigin = GetDiamondOrigin(pClient);
			vecOrigin.z -= 12;
			DrawVRML(m_vrmlHalo, vecOrigin, g_hsprHalo,kRenderNormal, TRI_NONE, 0, 255, 255, 255, 255);
			cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(i);
		}
	}	
}

/*
harSens/Joe: draws the diamonds above players heads
*/
void CStudioModelRenderer::DrawDiamonds()
{	
	// Your pointer
	cl_entity_t *pPlayer = gEngfuncs.GetLocalPlayer();

	// Team check
	int iUserTeam = g_PlayerExtraInfo[pPlayer->index].teamnumber;
	if ( iUserTeam < 0 )
	{	iUserTeam = 0;
	}

	// Loop Through all players
	for(int i = 1; i < MAX_PLAYERS; i++)
	{	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(i);
		
		// client model updated recently?
		if (m_fDrawDiamond[i])
		{	m_fDrawDiamond[i]=false;
		}
		else
		{	continue;
		}
		
		// skip ourselves
		if (pClient->index == pPlayer->index)
		{	continue;
		}
		
		// If player isn't valid
		if(!pClient)
		{	continue;
		}

		// If its not a player, dont draw a triangle
		if ( !pClient->player )
		{	continue;
		}

		// Team check
		int iTeam = g_PlayerExtraInfo[i].teamnumber;
		if ( iTeam < 0 )
		{	iTeam = 0;
		}

		// Set tris over head
		vec3_t vecOrigin = GetDiamondOrigin(pClient);

		// How far is the player from us?
		Vector2D vecPlayerOrigin = Vector2D(pPlayer->origin.x,pPlayer->origin.y);
		Vector2D vecClientOrigin = Vector2D(pClient->origin.x, pClient->origin.y);

		float flDistance = (vecPlayerOrigin - vecClientOrigin).Length();
		vec3_t vecRotation = vec3_t(0,(int)m_flRotationDiamond,0);

		VRMLData vrmlDiamondScaled;			
		RotateVRML(vrmlDiamondScaled, m_vrmlDiamond, vecRotation);
		ScaleVRML(vrmlDiamondScaled, vrmlDiamondScaled, 1.25);		
		
		// If User is on your team, Draw a triangle over his head, unless its you:)
		if(iTeam == iUserTeam && !g_iUser1)
		{	// If its accually Team play, draw the green triangles
			if(gHUD.m_Teamplay)
			{	DrawVRML(vrmlDiamondScaled, vecOrigin, g_hsprWhite,kRenderNormal, TRI_NONE, 0, 0, 255, 0, 255);
			}
			// If its deathmatch, draw the red triangles
			else
			{	// Make sure players are in Dist.
				if(flDistance < 2000)
				{	DrawVRML(vrmlDiamondScaled, vecOrigin, g_hsprWhite,kRenderNormal, TRI_NONE, 0, 255, 0, 0, 255);
				}
			}
		}
		// Draw a tri over a bad guy's head if he is in radar dist
		else if(flDistance < 2000)
		{	DrawVRML(vrmlDiamondScaled, vecOrigin, g_hsprWhite,kRenderNormal, TRI_NONE, 0, 255, 0, 0, 255);
		}		

		// draw buddy diamonds
		if (gBuddyInfo[i].buddy_index)
		{
			pClient = gEngfuncs.GetEntityByIndex(gBuddyInfo[i].buddy_index);
			if (pClient)
			{
				// Set tris over head
				vecOrigin = GetDiamondOrigin(pClient);

				// How far is the player from us?
				vecPlayerOrigin = Vector2D(pPlayer->origin.x,pPlayer->origin.y);
				vecClientOrigin = Vector2D(pClient->origin.x, pClient->origin.y);

				flDistance = (vecPlayerOrigin - vecClientOrigin).Length();
				vecRotation = vec3_t(0,(int)m_flRotationDiamond,0);
		
				RotateVRML(vrmlDiamondScaled, m_vrmlDiamond, vecRotation);
				ScaleVRML(vrmlDiamondScaled, vrmlDiamondScaled, 1.25);		

				// If User is on your team, Draw a triangle over his head, unless its you:)
				if(gBuddyInfo[i].buddy_team == iUserTeam)
				{	// If its accually Team play, draw the green triangles
					if(gHUD.m_Teamplay)
					{	DrawVRML(vrmlDiamondScaled, vecOrigin, g_hsprWhite,kRenderNormal, TRI_NONE, 0, 0, 255, 0, 255);
					}
					// If its deathmatch, draw the red triangles
					else
					{	// Make sure players are in Dist.
						if(flDistance < 2000)
						{	DrawVRML(vrmlDiamondScaled, vecOrigin, g_hsprWhite,kRenderNormal, TRI_NONE, 0, 255, 0, 0, 255);
						}
					}
				}
				// Draw a tri over a bad guy's head if he is in radar dist
				else if(flDistance < 2000)
				{	DrawVRML(vrmlDiamondScaled, vecOrigin, g_hsprWhite,kRenderNormal, TRI_NONE, 0, 255, 0, 0, 255);
				}		
			}
		}
	}		
}

/*
* Pcjoe; Is Disk Attack
*/
bool CStudioModelRenderer::IsDiskAttack( void )
{	if((!strcmp(m_pRenderModel->name,"models/w_destructodisc.mdl")||!strcmp(m_pRenderModel->name,"models/w_friezadisc.mdl")) &&
	   (m_pCurrentEntity->curstate.rendercolor.r != 0))
	{	return true;
	}
	return false;
}

//added by harSens: draws the player
int CStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer )
{	m_pCurrentEntity = IEngineStudio.GetCurrentEntity();

	IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime );

	//draws diamonds above the head
	UpdateDiamond();
	
	//draw player
	StudioDrawPlayerModel(flags, pplayer);

	/*
	//draw after fx	
	cl_entity_t saveent = *m_pCurrentEntity;
	int saveint = m_fDoInterp;
	m_fDoInterp = 0;
	int iAmt = 0;
	vector<entity_state_t>::iterator iter=m_afterfx.begin();	
	while(iter!=m_afterfx.end())
	{
		entity_state_t afterfx;	
		if(iter->number == pplayer->number)
		{
			entity_state_t temp;
			memcpy(&temp,pplayer,sizeof(temp));

			m_pCurrentEntity->curstate.rendermode = iter->rendermode;
			temp.rendermode = iter->rendermode;

			iAmt = TELEPORT_MAXAMT * (TELEPORT_FADETIME+iter->msg_time-m_clTime);
			//fade test
			iAmt = 100;
			if (iAmt>0)
			{
				
				iter->renderamt = iAmt;			
				m_pCurrentEntity->curstate.renderamt = iAmt;	
				temp.renderamt = iAmt;
				m_pCurrentEntity->curstate.animtime = m_clTime;
				temp.animtime = m_clTime;
				
				temp.sequence = iter->sequence;
				temp.gaitsequence = iter->gaitsequence;
				m_pCurrentEntity->curstate.sequence = iter->sequence;
				m_pCurrentEntity->curstate.gaitsequence = iter->gaitsequence;
				temp.frame = iter->frame;
				m_pCurrentEntity->curstate.frame = iter->frame;
				for (int i=0;i<4;i++)
				{	temp.controller[i]=iter->controller[i];
					m_pCurrentEntity->curstate.controller[i]=iter->controller[i];
				}
				
				VectorCopy(iter->origin,m_pCurrentEntity->origin);
				VectorCopy(iter->angles,m_pCurrentEntity->angles);
				VectorCopy(iter->origin,temp.origin);
				VectorCopy(iter->angles,temp.angles);			
				VectorCopy(iter->origin,m_pCurrentEntity->curstate.origin);
				VectorCopy(iter->angles,m_pCurrentEntity->curstate.angles);
								
				//StudioDrawPlayerModel(flags, iter);				
				StudioDrawAfterfx(flags, &temp);				
				iter++;
			}
			else
			{	iter = m_afterfx.erase(iter);
			}
		}
		else
		{	iter++;
		}
	}		
	m_fDoInterp = saveint ;
	*m_pCurrentEntity = saveent;
	*/
	return 1;	
}

/*
====================
StudioDrawPlayer

====================
*/
/* renamed by harSens
int CStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer )
*/
int CStudioModelRenderer::StudioDrawPlayerModel(int flags, entity_state_t *pplayer )
{
	alight_t lighting;
	vec3_t dir;

	/* disabled by harSens
	m_pCurrentEntity = IEngineStudio.GetCurrentEntity();
	IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime );
	*/
	
	IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal );
	IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale );

	// Con_DPrintf("DrawPlayer %d\n", m_pCurrentEntity->blending[0] );

	// Con_DPrintf("DrawPlayer %d %d (%d)\n", m_nFrameCount, pplayer->player_index, m_pCurrentEntity->curstate.sequence );

	// Con_DPrintf("Player %.2f %.2f %.2f\n", pplayer->velocity[0], pplayer->velocity[1], pplayer->velocity[2] );

	m_nPlayerIndex = pplayer->number - 1;

	if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients())
		return 0;

	// Edited by Pcjoe
	//m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex );
	m_pRenderModel = m_pCurrentEntity->model;

	if (m_pRenderModel == NULL)
		return 0;

	// Pcjoe: Custom model lookup
	model_s *pCustomModel = gHUD.m_CustomModel.getCustomModelPlayer(m_pCurrentEntity->index);
	if(pCustomModel)
		m_pRenderModel = pCustomModel;

	m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel);
	IEngineStudio.StudioSetHeader( m_pStudioHeader );
	IEngineStudio.SetRenderModel( m_pRenderModel );

	if (pplayer->gaitsequence)
	{
		vec3_t orig_angles;
		m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex );

		VectorCopy( m_pCurrentEntity->angles, orig_angles );
	
		// Added by Pcjoe - No gait on fly anim
		if(!SmoothFlying(pplayer->gaitsequence))
		{	StudioProcessGait( pplayer );
			// Edited by Pcjoe
			if(m_pPlayerInfo->gaitsequence != pplayer->gaitsequence)
			{	m_pPlayerInfo->gaitsequence = pplayer->gaitsequence;
				m_pPlayerInfo->gaitframe = 0;
			}
		}
		else
		{	m_pCurrentEntity->curstate.controller[0] = 127;
			m_pCurrentEntity->curstate.controller[1] = 127;
			m_pCurrentEntity->curstate.controller[2] = 127;
			m_pCurrentEntity->curstate.controller[3] = 127;
			m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0];
			m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1];
			m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2];
			m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3];
		
			// Added by Pcjoe
			m_pPlayerInfo->gaitsequence = pplayer->gaitsequence;
		}
		
		m_pPlayerInfo = NULL;

		StudioSetUpTransform( 0 );
		VectorCopy( orig_angles, m_pCurrentEntity->angles );		
	}
	else
	{
		m_pCurrentEntity->curstate.controller[0] = 127;
		m_pCurrentEntity->curstate.controller[1] = 127;
		m_pCurrentEntity->curstate.controller[2] = 127;
		m_pCurrentEntity->curstate.controller[3] = 127;
		m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0];
		m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1];
		m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2];
		m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3];
		
		m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex );
		m_pPlayerInfo->gaitsequence = 0;

		StudioSetUpTransform( 0 );
	}

	if (flags & STUDIO_RENDER)
	{	
		// Edited by Pcjoe: Force render for grabs, connects, and melee struggles
		/*modified by harSens
		std::list<model_manip_s>::iterator pManip = gHUD.m_ManipModel.FindByPlayerAndOtherIndex(m_pCurrentEntity->index);
		*/
		model_manip_s *pManip = gHUD.m_ManipModel.FindByPlayerAndOtherIndex(m_pCurrentEntity->index);
		bool blForceRender = false;
		// see if the bounding box lets us trivially reject, also sets
		if (!IEngineStudio.StudioCheckBBox ())
		{	if(pManip!=NULL)
			{	if(pManip->iFlags & MANIP_FLAG_RECPOS)
				{	blForceRender = true;
				}
			}
		}
		else
		{	blForceRender = true;
		}
		// end of edit by Pcjoe

		if(!blForceRender)
		{	return 0;
		}

		(*m_pModelsDrawn)++;
		(*m_pStudioModelCount)++; // render data cache cookie

		if (m_pStudioHeader->numbodyparts == 0)
			return 1;

		// Pcjoe: Set sub body
		if(pManip!=NULL)
		{	if(pManip->iPlayerIndex == m_pCurrentEntity->index)
			{	// Set submodel
				if(pManip->iBodyPlayerSeq == m_pCurrentEntity->curstate.sequence)
				{	m_pCurrentEntity->curstate.body = pManip->iBodyPlayer;
				}
				// Disable submodel due to sequence change
				else
				{	pManip->iBodyPlayer = 0;
					pManip->iBodyPlayerSeq = 0;
				}
			}
			else
			{	// Set submodel
				if(pManip->iBodyOtherSeq == m_pCurrentEntity->curstate.sequence)
				{	m_pCurrentEntity->curstate.body = pManip->iBodyOther;
				}
				// Disable submodel due to sequence change
				else
				{	pManip->iBodyOther = 0;
					pManip->iBodyOtherSeq = 0;
				}
			}
		}
	}

	m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex );
	// Pcjoe: Support for model control
	CMDLControl *pCtrl = gModelControl.findModelControl(m_pCurrentEntity->index);
	if(pCtrl)
		StudioSetupBonesMDLControl(pCtrl);
	else
        StudioSetupBones( );
	// end of add by Pcjoe
	StudioSaveBones( );
	m_pPlayerInfo->renderframe = m_nFrameCount;
	m_pPlayerInfo = NULL;
	// Pcjoe: Motion Blur FX
	gModelBlur.Think(m_pCurrentEntity->index, gEngfuncs.GetClientTime());

	if (flags & STUDIO_EVENTS)
	{
		StudioCalcAttachments( );
		IEngineStudio.StudioClientEvents( );
		// copy attachments into global entity array
		if ( m_pCurrentEntity->index > 0 )
		{
			cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index );

			memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 );
		}
	}

	if (flags & STUDIO_RENDER)
	{	// Removed by Pcjoe
/*		if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model  )
		{
			// show highest resolution multiplayer model
			m_pCurrentEntity->curstate.body = 255;
		}

		if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) )
		{
			m_pCurrentEntity->curstate.body = 1; // force helmet
		}*/
		
		/* modified by harSens
		lighting.plightvec = dir;
		IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting );

		IEngineStudio.StudioEntityLight( &lighting );

		// model and frame independant
		IEngineStudio.StudioSetupLighting (&lighting);
		*/
	/*	vector<int> m_alLevel;
		m_alLevel.push_back(8);
		m_alLevel.push_back(64);
		m_alLevel.push_back(128);
		vector<int> m_slLevel;
		m_slLevel.push_back(16);
		m_slLevel.push_back(128);
		m_slLevel.push_back(200);*/
		if (!(flags & FLAG_AFTERIMAGE))
		{
			dir = vec3_t(0,0,0);
			lighting.plightvec = dir;
			IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting );
			if(lighting.ambientlight < 16)
				lighting.ambientlight = 16;
			if(lighting.shadelight < 32)
				lighting.shadelight = 32;
		/*	char szPrint[256];
			sprintf(szPrint,"AL: %i | SL: %i\n", lighting.ambientlight, lighting.shadelight);
			ConsolePrint(szPrint);

			int distAL=999;
			int distSL=999;
			int idxAL=0;
			int idxSL=0;

			for(size_t i = 0; i < m_slLevel.size(); ++i)
			{	if(abs(m_slLevel[i]-lighting.shadelight) < distAL)
				{	distSL = abs(m_slLevel[i]-lighting.shadelight);
					idxSL = (int)i;
				}
			}
			
			for(size_t i = 0; i < m_alLevel.size(); ++i)
			{	if(abs(m_alLevel[i]-lighting.ambientlight) < distAL)
				{	distAL = abs(m_alLevel[i]-lighting.ambientlight);
					idxAL = (int)i;
				}
			}

			lighting.shadelight = m_slLevel[idxSL];
			lighting.ambientlight = m_alLevel[idxAL];
			lighting.ambientlight = float(m_slLevel[idxSL])/200.0*128;

			lighting.ambientlight = 128;
			lighting.shadelight = 256;
			dir = vec3_t(0,0,0);
			lighting.plightvec = dir;*/
			IEngineStudio.StudioEntityLight( &lighting );

			// model and frame independant
			IEngineStudio.StudioSetupLighting (&lighting);
		}		
		
		m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex );

		// get remap colors
		m_nTopColor = m_pPlayerInfo->topcolor;
		m_nBottomColor = m_pPlayerInfo->bottomcolor;
		if (m_nTopColor < 0)
			m_nTopColor = 0;
		if (m_nTopColor > 360)
			m_nTopColor = 360;
		if (m_nBottomColor < 0)
			m_nBottomColor = 0;
		if (m_nBottomColor > 360)
			m_nBottomColor = 360;

		IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor );

		// Pcjoe: TEST!!! Changing model stuff around
/*		mstudiotexture_t	*ptexture;
		vec3_t				*pstudioverts;
		mstudiomodel_t		*m_pmodel;
		mstudiobodyparts_t	*pbodypart;


		pbodypart = (mstudiobodyparts_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bodypartindex);
		m_pmodel = (mstudiomodel_t *)((byte *)m_pStudioHeader + pbodypart->modelindex) + 0;
		ptexture = (mstudiotexture_t *)((byte *)m_pStudioHeader + m_pStudioHeader->textureindex);
		pstudioverts = (vec3_t *)((byte *)m_pStudioHeader + m_pmodel->vertindex);
		if(ptexture)
		{	char szPrint[512];
			sprintf(szPrint,"%s, %i-%i\n", ptexture[0].name, ptexture[0].width, ptexture[0].height);
			
			extern GLuint glTexTest;
			ptexture[0].index = glTexTest;
			ConsolePrint(szPrint);
		}
		char szPrint[256];
		sprintf(szPrint,"Verts - %i\n", m_pmodel->numverts);
		ConsolePrint(szPrint);*/

		StudioRenderModel( );
		m_pPlayerInfo = NULL;

		if (pplayer->weaponmodel)
		{
			cl_entity_t saveent = *m_pCurrentEntity;

			model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel );

			m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel);
			IEngineStudio.StudioSetHeader( m_pStudioHeader );

			StudioMergeBones( pweaponmodel);

			IEngineStudio.StudioSetupLighting (&lighting);

			StudioRenderModel( );

			StudioCalcAttachments( );

			*m_pCurrentEntity = saveent;
		}
	}

	return 1;
}

/* 
After fx drawing by harSens, based on StudioDrawPlayer   
int CStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer )

int CStudioModelRenderer::StudioDrawAfterfx(int flags, entity_state_t *pplayer )
{	
	alight_t lighting;
	vec3_t dir;

	
	IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal );
	IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale );

	m_nPlayerIndex = pplayer->number - 1;

	if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients())
		return 0;

	m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex );
	if (m_pRenderModel == NULL)
		return 0;

	m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel);
	IEngineStudio.StudioSetHeader( m_pStudioHeader );
	IEngineStudio.SetRenderModel( m_pRenderModel );
	
	m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex );		

	m_pCurrentEntity->curstate.controller[0] = 127;
	m_pCurrentEntity->curstate.controller[1] = 127;
	m_pCurrentEntity->curstate.controller[2] = 127;
	m_pCurrentEntity->curstate.controller[3] = 127;
	m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0];
	m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1];
	m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2];
	m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3];		
	//m_pPlayerInfo->gaitsequence = 0;	
	
	StudioSetUpTransform( 0 );	
	
	if (flags & STUDIO_RENDER)
	{	
		// Edited by Pcjoe: Force render for grabs, connects, and melee struggles
		bool blForceRender = false;
		// see if the bounding box lets us trivially reject, also sets
		if (!IEngineStudio.StudioCheckBBox ())
		{
			model_manip_s *pManip = gHUD.m_ManipModel.FindByPlayerAndOtherIndex(m_pCurrentEntity->index);
			while(pManip)
			{	
				if(pManip->iFlags & MANIP_FLAG_RECPOS)
				{	blForceRender = true;
					break;
				}
				pManip = gHUD.m_ManipModel.FindByPlayerAndOtherIndex(pManip->pNext, m_pCurrentEntity->index);
			}
		}
		else
		{	blForceRender = true;
		}

		if(!blForceRender)
		{	return 0;
		}

		(*m_pModelsDrawn)++;
		(*m_pStudioModelCount)++; // render data cache cookie

		if (m_pStudioHeader->numbodyparts == 0)
			return 1;
	}
	
	
	//lock gait frame
	int savegaitframe = m_pPlayerInfo->gaitframe;
	m_pPlayerInfo->gaitframe = 0;

	StudioSetupBones( );
	StudioSaveBones( );
	
	//restore  old gait frame
	m_pPlayerInfo->gaitframe = savegaitframe;



	m_pPlayerInfo->renderframe = m_nFrameCount;
	
	m_pPlayerInfo = NULL;

	if (flags & STUDIO_EVENTS)
	{
		StudioCalcAttachments( );
		IEngineStudio.StudioClientEvents( );
		// copy attachments into global entity array
		if ( m_pCurrentEntity->index > 0 )
		{
			cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index );

			memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 );
		}
	}

	if (flags & STUDIO_RENDER)
	{
		if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model  )
		{
			// show highest resolution multiplayer model
			m_pCurrentEntity->curstate.body = 255;
		}

		if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) )
		{
			m_pCurrentEntity->curstate.body = 1; // force helmet
		}

		lighting.plightvec = dir;
		IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting );

		IEngineStudio.StudioEntityLight( &lighting );

		// model and frame independant
		IEngineStudio.StudioSetupLighting (&lighting);

		m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex );

		// get remap colors
		m_nTopColor = m_pPlayerInfo->topcolor;
		m_nBottomColor = m_pPlayerInfo->bottomcolor;
		if (m_nTopColor < 0)
			m_nTopColor = 0;
		if (m_nTopColor > 360)
			m_nTopColor = 360;
		if (m_nBottomColor < 0)
			m_nBottomColor = 0;
		if (m_nBottomColor > 360)
			m_nBottomColor = 360;

		IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor );

		StudioRenderModel( );
		m_pPlayerInfo = NULL;

		if (pplayer->weaponmodel)
		{
			cl_entity_t saveent = *m_pCurrentEntity;

			model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel );

			m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel);
			IEngineStudio.StudioSetHeader( m_pStudioHeader );

			StudioMergeBones( pweaponmodel);

			IEngineStudio.StudioSetupLighting (&lighting);

			StudioRenderModel( );

			StudioCalcAttachments( );

			*m_pCurrentEntity = saveent;
		}
	}
	m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex );
	return 1;
}
*/
/*
====================
StudioCalcAttachments

====================
*/
void CStudioModelRenderer::StudioCalcAttachments( void )
{
	int i;
	mstudioattachment_t *pattachment;

	if ( m_pStudioHeader->numattachments > 4 )
	{
		gEngfuncs.Con_DPrintf( "Too many attachments on %s\n", m_pCurrentEntity->model->name );
		exit( -1 );
	}

	// calculate attachment points
	pattachment = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex);
	for (i = 0; i < m_pStudioHeader->numattachments; i++)
	{
		VectorTransform( pattachment[i].org, (*m_plighttransform)[pattachment[i].bone],  m_pCurrentEntity->attachment[i] );
	}
}

/*
====================
StudioRenderModel

====================
*/
void CStudioModelRenderer::StudioRenderModel( void )
{
	IEngineStudio.SetChromeOrigin();
	IEngineStudio.SetForceFaceFlags( 0 );

	if ( m_pCurrentEntity->curstate.renderfx == kRenderFxGlowShell )
	{
		m_pCurrentEntity->curstate.renderfx = kRenderFxNone;
		StudioRenderFinal( );
		
		if ( !IEngineStudio.IsHardware() )
		{
			gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd );
		}

		IEngineStudio.SetForceFaceFlags( STUDIO_NF_CHROME );

		gEngfuncs.pTriAPI->SpriteTexture( m_pChromeSprite, 0 );
		m_pCurrentEntity->curstate.renderfx = kRenderFxGlowShell;

		StudioRenderFinal( );
		if ( !IEngineStudio.IsHardware() )
		{
			gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
		}
	}
	else
	{
		StudioRenderFinal( );
	}
}

/*
====================
StudioRenderFinal_Software

====================
*/
void CStudioModelRenderer::StudioRenderFinal_Software( void )
{
	int i;

	/* modified by harSens
	// Note, rendermode set here has effect in SW
	IEngineStudio.SetupRenderer( 0 ); 
	*/
	int rendermode;
	rendermode = IEngineStudio.GetForceFaceFlags() ? kRenderTransAdd : m_pCurrentEntity->curstate.rendermode;
	IEngineStudio.SetupRenderer( rendermode );

	
	if (m_pCvarDrawEntities->value == 2)
	{
		IEngineStudio.StudioDrawBones( );
	}
	else if (m_pCvarDrawEntities->value == 3)
	{
		IEngineStudio.StudioDrawHulls( );
	}
	else
	{
		for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++)
		{
			//added by harSens
			gEngfuncs.pTriAPI->RenderMode( rendermode );

			IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel );
			IEngineStudio.StudioDrawPoints( );

			//added by harSens		
			gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
		}		
	}

	if (m_pCvarDrawEntities->value == 4)
	{
		gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd );
		IEngineStudio.StudioDrawHulls( );
		gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
	}

	if (m_pCvarDrawEntities->value == 5)
	{
		IEngineStudio.StudioDrawAbsBBox( );
	}
	
	IEngineStudio.RestoreRenderer();
}

/*
====================
StudioRenderFinal_Hardware

====================
*/
void CStudioModelRenderer::StudioRenderFinal_Hardware( void )
{
	int i;
	int rendermode;

	rendermode = IEngineStudio.GetForceFaceFlags() ? kRenderTransAdd : m_pCurrentEntity->curstate.rendermode;
	IEngineStudio.SetupRenderer( rendermode );
	
	if (m_pCvarDrawEntities->value == 2)
	{
		IEngineStudio.StudioDrawBones();
	}
	else if (m_pCvarDrawEntities->value == 3)
	{
		IEngineStudio.StudioDrawHulls();
	}
	else
	{
		for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++)
		{
			IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel );

			if (m_fDoInterp)
			{
				// interpolation messes up bounding boxes.
				m_pCurrentEntity->trivial_accept = 0; 
			}

			IEngineStudio.GL_SetRenderMode( rendermode );
			IEngineStudio.StudioDrawPoints();
			IEngineStudio.GL_StudioDrawShadow();
		}
	}

	if ( m_pCvarDrawEntities->value == 4 )
	{
		gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd );
		IEngineStudio.StudioDrawHulls( );
		gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
	}

	IEngineStudio.RestoreRenderer();
}

/*
====================
StudioRenderFinal

====================
*/
void CStudioModelRenderer::StudioRenderFinal(void)
{
	if ( IEngineStudio.IsHardware() )
	{
		StudioRenderFinal_Hardware();
	}
	else
	{
		StudioRenderFinal_Software();
	}
}

