Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1556 lines
45 KiB

//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
#include "mathlib/mathlib.h"
#include "bone_setup_PS3.h"
#include "bone_utils_PS3.h"
//--------------------------------------------------------------------------------------------------------------------
//
// local data for a bone job
//
//--------------------------------------------------------------------------------------------------------------------
#define CPSPATH_FALSE 0
#define CPSPATH_CALCANIM1 1
#define CPSPATH_CALCANIM1_SCALE1MINUSS0 2
#define CPSPATH_CALCANIM1_SCALES0 3
#define CPSPATH_CALCANIM2_S0 4
#define CPSPATH_CALCANIM2_S1 5
#define CPSPATH_CALCANIM3 6
#define CPSPATH_CALCANIM4 7
ALIGN16 byte g_ls_Stack[ (LS_FLOATSTACK_SIZE * sizeof(float)) + (LS_INTSTACK_SIZE * sizeof(int)) ];
byte *g_ls_StackPtr;
byte *g_ls_StackPtr_MAX;
#if defined(__SPU__)
BoneVector *g_posInit;
BoneQuaternion *g_qInit;
ikcontextikrule_t_PS3 *g_addDep_IKRules;
int g_addDep_numIKRules;
#else
BoneVector g_posInit[ MAXSTUDIOBONES_PS3 ]; // 2k
BoneQuaternion g_qInit[ MAXSTUDIOBONES_PS3 ]; // 2k
ikcontextikrule_t_PS3 g_addDep_IKRules[ MAX_IKRULES ] ALIGN16;
int g_addDep_numIKRules;
#endif
//static int g_accumPoseCount;
#if !defined(__SPU__)
#include <string.h>
#include "tier0/vprof.h"
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
extern IVJobs * g_pVJobs;
CBoneJobs g_BoneJobs;
CBoneJobs* g_pBoneJobs = &g_BoneJobs;
job_accumpose::JobDescriptor_t g_AccumPoseJobDescriptor ALIGN128;
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CBoneJobs::Init( void )
{
m_bEnabled = false;
m_boneJobCount = 0;
m_boneJobData.EnsureCapacity( 96 );
// requires a SPURS instance, so register with VJobs
if( g_pVJobs )
{
g_pVJobs->Register( this );
}
}
void CBoneJobs::Shutdown()
{
g_pVJobs->Unregister( this );
}
void CBoneJobs::OnVjobsInit()
{
m_bEnabled = true;
g_AccumPoseJobDescriptor.header = *m_pRoot->m_pJobAccumPose;
g_AccumPoseJobDescriptor.header.useInOutBuffer = 1;
g_AccumPoseJobDescriptor.header.sizeStack = (12*1024)/8;
g_AccumPoseJobDescriptor.header.sizeInOrInOut = 0;
}
void CBoneJobs::OnVjobsShutdown()
{
m_bEnabled = false;
}
void CBoneJobs::StartFrame( int maxBoneJobs )
{
m_boneJobData.EnsureCapacity( maxBoneJobs );
}
void CBoneJobs::EndFrame( void )
{
m_boneJobData.RemoveAll();
}
void CBoneJobs::ResetBoneJobs( void )
{
m_boneJobCount = 0;
m_boneJobNextSPURSPort = 0;
}
int CBoneJobs::AddBoneJob( void )
{
return m_boneJobCount++;
}
int CBoneJobs::GetNumBoneJobs( void )
{
return m_boneJobCount;
}
PS3BoneJobData *CBoneJobs::GetJobData( int job )
{
return &m_boneJobData[ job ];
}
int CBoneJobs::GetNextFreeSPURSPort( void )
{
m_boneJobNextSPURSPort = (m_boneJobNextSPURSPort + 1) % VJobsRoot::MAXPORTS_ANIM;
return m_boneJobNextSPURSPort;
}
//-----------------------------------------------------------------------------
// Contains support for running BoneJobs on SPU
//
// each bonejob contains a number of AccumulatePose calls that were 'discovered'
// in the 1st pass on PPU - this pass filled the bonejob packet with data for all
// AccumulatePose calls that take place on C_BaseAnimating
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: calculate a pose for a single sequence
//-----------------------------------------------------------------------------
void InitPose_PS3(
const CStudioHdr *pStudioHdr,
BoneVector pos[],
BoneQuaternion q[],
int boneMask
)
{
// const fltx4 zeroQ = Four_Origin;
SNPROF_ANIM("InitPose_PS3");
if ( mstudiolinearbone_t *pLinearBones = pStudioHdr->pLinearBones() )
{
int numBones = pStudioHdr->numbones();
AssertFatal( sizeof(BoneQuaternion) == sizeof(Quaternion) );
memcpy( q, (((byte *)pLinearBones) + pLinearBones->quatindex), sizeof( Quaternion ) * numBones );
// want to align pos entries to 16B
// memcpy( pos, (((byte *)pLinearBones) + pLinearBones->posindex), sizeof( Vector ) * numBones );
Vector *pSrcBones = (Vector *)(((byte *)pLinearBones) + pLinearBones->posindex);
for( int i = 0; i < pStudioHdr->numbones(); i++ )
{
pos[i] = pSrcBones[i];
}
}
else
{
for( int i = 0; i < pStudioHdr->numbones(); i++ )
{
if( pStudioHdr->boneFlags( i ) & boneMask )
{
const mstudiobone_t *pbone = pStudioHdr->pBone( i );
pos[i] = pbone->pos;
q[i] = pbone->quat;
}
/* // unnecessary to initialize unused bones since they are ignored downstream.
else
{
pos[i].Zero();
// q[i] = zeroQ;
StoreAlignedSIMD(q[i].Base(), zeroQ);
}
*/
}
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
inline bool PoseIsAllZeros_PS3(
const CStudioHdr *pStudioHdr,
int sequence,
mstudioseqdesc_t &seqdesc,
int i0,
int i1
)
{
int baseanim;
// remove "zero" positional blends
baseanim = pStudioHdr->iRelativeAnim( sequence, seqdesc.anim(i0 ,i1 ) );
mstudioanimdesc_t &anim = ((CStudioHdr *)pStudioHdr)->pAnimdesc( baseanim );
return (anim.flags & STUDIO_ALLZEROS) != 0;
}
//-----------------------------------------------------------------------------
// fill animdata_SPU struct
//-----------------------------------------------------------------------------
static void SetAnimData_AnimDesc( animData_SPU *pAnim, accumposeentry_SPU *pPoseEntry, mstudioanimdesc_t &animdesc, int animIndex )
{
SNPROF_ANIM("SetAnimData_AnimDesc");
int iFrame;
float s;
float flStall;
pAnim->pEA_animdesc = &animdesc;
float fFrame = pPoseEntry->cycle * (animdesc.numframes - 1);
iFrame = (int)fFrame;
s = (fFrame - iFrame);
int iLocalFrame = iFrame;
pAnim->pEA_animdesc_pFrameanim = NULL;
pAnim->pEA_animdesc_panim = NULL;
if( animdesc.flags & STUDIO_FRAMEANIM )
{
const mstudio_frame_anim_t *pFrameanim = (mstudio_frame_anim_t *)animdesc.pAnim( &iLocalFrame, flStall );
pAnim->animdesc_iLocalFrame = iLocalFrame;
pAnim->pEA_animdesc_pFrameanim = (void *)pFrameanim;
}
else
{
pAnim->pEA_animdesc_panim = (void *)animdesc.pAnim( &iLocalFrame, flStall );
pAnim->animdesc_iLocalFrame = iLocalFrame;
}
pAnim->pEA_animdesc_ikrule = NULL;
pAnim->pEA_animdesc_ikrulezeroframe = NULL;
mstudioikrule_t *pIKRule = animdesc.pIKRule( 0 );
if( pIKRule )
{
pAnim->pEA_animdesc_ikrule = pIKRule;
}
else
{
mstudioikrulezeroframe_t *pZeroFrameRule = animdesc.pIKRuleZeroFrame( 0 );
pAnim->pEA_animdesc_ikrulezeroframe = pZeroFrameRule;
}
pAnim->flStall = flStall;
}
//-----------------------------------------------------------------------------
// Fill PoseEntry anim data
//-----------------------------------------------------------------------------
bool CBoneSetup_PS3::SetAnimData( accumposeentry_SPU *pPoseEntry, const CStudioHdr *pStudioHdr, mstudioseqdesc_t &seqdesc, int sequence, int x, int y, int animIndex, float weight )
{
SNPROF_ANIM("CBoneSetup_PS3::SetAnimData");
animData_SPU *pAnim = &pPoseEntry->anims[ animIndex ];
pAnim->seqdesc_anim = seqdesc.anim( x, y );
pAnim->seqdesc_weight = weight;
virtualmodel_t *pVModel = pStudioHdr->GetVirtualModel();
if( pVModel )
{
int baseanimation = pStudioHdr->iRelativeAnim( sequence, pAnim->seqdesc_anim );
mstudioanimdesc_t &animdesc = ((CStudioHdr *)pStudioHdr)->pAnimdesc( baseanimation );
if( animdesc.numlocalhierarchy )
{
// don't take SPU path
m_errorFlags = BONEJOB_ERROR_LOCALHIER;
// TODO: follow this path out quickly
return false;
}
SetAnimData_AnimDesc( pAnim, pPoseEntry, animdesc, animIndex );
pAnim->pEA_animgroup_masterbone = pVModel->pAnimGroup( baseanimation )->masterBone.Base();
const studiohdr_t *pAnimStudioHdr;
pAnimStudioHdr = ((CStudioHdr *)pStudioHdr)->pAnimStudioHdr( baseanimation );
pAnim->animstudiohdr_numbones = pAnimStudioHdr->numbones;
mstudiolinearbone_t *pLinearBones = pAnimStudioHdr->pLinearBones();
pAnim->pEA_anim_linearBones = pLinearBones;
pAnim->pEA_anim_bones_pos = &pAnimStudioHdr->pBone(0)->pos;
pAnim->pEA_anim_bones_flags = &pAnimStudioHdr->pBone(0)->flags;
}
else
{
mstudioanimdesc_t &animdesc = ((CStudioHdr *)pStudioHdr)->pAnimdesc( pAnim->seqdesc_anim );
if( animdesc.numlocalhierarchy )
{
// don't take SPU path
m_errorFlags = BONEJOB_ERROR_LOCALHIER;
// TODO: follow this path out quickly
return false;
}
SetAnimData_AnimDesc( pAnim, pPoseEntry, animdesc, animIndex );
pAnim->animstudiohdr_numbones = pStudioHdr->GetRenderHdr()->numbones;
}
return true;
}
//-----------------------------------------------------------------------------
// CalcPoseSingle PPU pass - fill PoseEntry
// Get this working first before moving more to SPU
//-----------------------------------------------------------------------------
bool CBoneSetup_PS3::CalcPoseSingle(
accumposeentry_SPU *pPoseEntry,
const CStudioHdr *pStudioHdr,
mstudioseqdesc_t &seqdesc,
int sequence,
float cycle,
const float poseParameter[],
float flTime )
{
SNPROF_ANIM( "CBoneSetup_PS3::CalcPoseSingle" );
ConVarRef anim_3wayblend( "anim_3wayblend" );
bool bResult = true;
float s0, s1;
int i0, i1;
s0 = 0.0f; s1 = 0.0f;
i0 = Studio_LocalPoseParameter( pStudioHdr, poseParameter, seqdesc, sequence, 0, s0 );
i1 = Studio_LocalPoseParameter( pStudioHdr, poseParameter, seqdesc, sequence, 1, s1 );
//pPoseEntry->cps = Studio_CPS( pStudioHdr, seqdesc, sequence, poseParameter );
if( seqdesc.flags & STUDIO_REALTIME )
{
float cps = Studio_CPS( pStudioHdr, seqdesc, sequence, poseParameter );
cycle = flTime * cps;
cycle = cycle - (int)cycle;
}
else if( seqdesc.flags & STUDIO_CYCLEPOSE )
{
int iPose = pStudioHdr->GetSharedPoseParameter( sequence, seqdesc.cycleposeindex );
if( iPose != -1 )
{
/*
const mstudioposeparamdesc_t &Pose = pStudioHdr->pPoseParameter( iPose );
cycle = poseParameter[ iPose ] * (Pose.end - Pose.start) + Pose.start;
*/
cycle = poseParameter[ iPose ];
}
else
{
cycle = 0.0f;
}
}
else if( cycle < 0.0f || cycle >= 1.0f )
{
if( seqdesc.flags & STUDIO_LOOPING )
{
cycle = cycle - (int)cycle;
if( cycle < 0 ) cycle += 1.0f;
}
else
{
cycle = clamp( cycle, 0.0f, 1.0f );
}
}
pPoseEntry->cyclePoseSingle = cycle;
pPoseEntry->i0 = i0;
pPoseEntry->i1 = i1;
pPoseEntry->s0 = s0;
pPoseEntry->s1 = s1;
pPoseEntry->animIndices[0] = -1;
pPoseEntry->animIndices[1] = -1;
pPoseEntry->animIndices[2] = -1;
pPoseEntry->animIndices[3] = -1;
pPoseEntry->anims[0].seqdesc_weight = 0.0f;
pPoseEntry->anims[1].seqdesc_weight = 0.0f;
pPoseEntry->anims[2].seqdesc_weight = 0.0f;
pPoseEntry->anims[3].seqdesc_weight = 0.0f;
pPoseEntry->anims[0].animstudiohdr_numbones = 0;
pPoseEntry->anims[1].animstudiohdr_numbones = 0;
pPoseEntry->anims[2].animstudiohdr_numbones = 0;
pPoseEntry->anims[3].animstudiohdr_numbones = 0;
if( s0 < 0.001f )
{
if( s1 < 0.001f )
{
if( PoseIsAllZeros_PS3( pStudioHdr, sequence, seqdesc, i0, i1 ) )
{
pPoseEntry->cpsPath = CPSPATH_FALSE;
bResult = false;
}
else
{
pPoseEntry->cpsPath = CPSPATH_CALCANIM1;
pPoseEntry->animIndices[0] = 0;
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0, i1, 0, 1.0f );
}
}
else if( s1 > 0.999f )
{
pPoseEntry->cpsPath = CPSPATH_CALCANIM1;
pPoseEntry->animIndices[0] = 2;
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0, i1+1, 2, 1.0f );
}
else
{
pPoseEntry->cpsPath = CPSPATH_CALCANIM2_S1;
pPoseEntry->animIndices[0] = 0;
pPoseEntry->animIndices[1] = 2;
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0, i1, 0, 1.0f - s1 );
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0, i1+1, 2, s1 );
}
}
else if( s0 > 0.999f )
{
if( s1 < 0.001f )
{
if( PoseIsAllZeros_PS3( pStudioHdr, sequence, seqdesc, i0+1, i1 ) )
{
pPoseEntry->cpsPath = CPSPATH_FALSE;
bResult = false;
}
else
{
pPoseEntry->cpsPath = CPSPATH_CALCANIM1;
pPoseEntry->animIndices[0] = 1;
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0+1, i1, 1, 1.0f );
}
}
else if( s1 > 0.999f )
{
pPoseEntry->cpsPath = CPSPATH_CALCANIM1;
pPoseEntry->animIndices[0] = 3;
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0+1, i1+1, 3, 1.0f );
}
else
{
pPoseEntry->cpsPath = CPSPATH_CALCANIM2_S1;
pPoseEntry->animIndices[0] = 1;
pPoseEntry->animIndices[1] = 3;
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0+1, i1, 1, 1.0f - s1 );
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0+1, i1+1, 3, s1 );
}
}
else
{
if( s1 < 0.001f )
{
pPoseEntry->animIndices[0] = 0;
pPoseEntry->animIndices[1] = 1;
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0, i1, 0, 1.0f - s0 );
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0+1, i1, 1, s0 );
if( PoseIsAllZeros_PS3( pStudioHdr, sequence, seqdesc, i0+1, i1 ) )
{
pPoseEntry->cpsPath = CPSPATH_CALCANIM1_SCALE1MINUSS0;
}
else if( PoseIsAllZeros_PS3( pStudioHdr, sequence, seqdesc, i0, i1 ) )
{
pPoseEntry->cpsPath = CPSPATH_CALCANIM1_SCALES0;
}
else
{
pPoseEntry->cpsPath = CPSPATH_CALCANIM2_S0;
}
}
else if( s1 > 0.999f )
{
pPoseEntry->cpsPath = CPSPATH_CALCANIM2_S0;
pPoseEntry->animIndices[0] = 2;
pPoseEntry->animIndices[1] = 3;
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0, i1+1, 2, 1.0f - s0 );
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0+1, i1+1, 3, s0 );
}
else if( !anim_3wayblend.GetBool() )
{
pPoseEntry->cpsPath = CPSPATH_CALCANIM4;
pPoseEntry->animIndices[0] = 0;
pPoseEntry->animIndices[1] = 1;
pPoseEntry->animIndices[2] = 2;
pPoseEntry->animIndices[3] = 3;
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0, i1, 0, (1.0f - s0) * (1.0f - s1) );
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0+1, i1, 1, (s0) * (1.0f - s1) );
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0, i1+1, 2, (1.0f - s0) * (s1) );
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0+1, i1+1, 3, (s0) * (s1) );
}
else
{
pPoseEntry->cpsPath = CPSPATH_CALCANIM3;
pPoseEntry->animIndices[0] = 0;
pPoseEntry->animIndices[1] = 1;
pPoseEntry->animIndices[2] = 2;
pPoseEntry->animIndices[3] = 3;
// weights get fixed up later
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0, i1, 0, 0.0f );
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0+1, i1, 1, 0.0f );
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0, i1+1, 2, 0.0f );
SetAnimData( pPoseEntry, pStudioHdr, seqdesc, sequence, i0+1, i1+1, 3, 0.0f );
}
}
if( pPoseEntry->animIndices[0] == -1 )
{
// ik may use the zeroth entry - why?
virtualmodel_t *pVModel = pStudioHdr->GetVirtualModel();
if( pVModel )
{
int baseanimation = pStudioHdr->iRelativeAnim( sequence, seqdesc.anim( i0, i1 ) );
mstudioanimdesc_t &animdesc = ((CStudioHdr *)pStudioHdr)->pAnimdesc( baseanimation );
pPoseEntry->anims[ 0 ].pEA_animdesc = &animdesc;
}
else
{
mstudioanimdesc_t &animdesc = ((CStudioHdr *)pStudioHdr)->pAnimdesc( seqdesc.anim( i0, i1 ) );
pPoseEntry->anims[ 0 ].pEA_animdesc = &animdesc;
}
}
// Real IK weights
// 0 : (1.0f - s0) * (1.0f - s1);
// 1 : (s0) * (1.0f - s1);
// 2 : (1.0f - s0) * (s1);
// 3 : (s0) * (s1);
return bResult;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void AddSequenceLocks_PS3( accumposeentry_SPU* pPoseEntry, const CStudioHdr* pStudioHdr, mstudioseqdesc_t &seqdesc )
{
pPoseEntry->pEA_seqdesc_iklocks = NULL;
if( pStudioHdr->numikchains() == 0)
{
return;
}
if( seqdesc.numiklocks == 0 )
{
return;
}
pPoseEntry->pEA_seqdesc_iklocks = seqdesc.pIKLock( 0 );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void AddAutoLocks_PS3( bonejob_SPU *pBonejob, const CStudioHdr* pStudioHdr )
{
SNPROF_ANIM("AddAutoLocks_PS3");
if( pStudioHdr->GetNumIKAutoplayLocks() == 0 )
{
return;
}
AssertFatal( pStudioHdr->GetNumIKAutoplayLocks() < MAX_IKLOCKS );
for( int i = 0; i < pStudioHdr->GetNumIKAutoplayLocks(); i++ )
{
const mstudioiklock_t &lock = ((CStudioHdr *)pStudioHdr)->pIKAutoplayLock( i );
pBonejob->pEA_IKAutoplayLocks[ i ] = (void *)&lock;
}
}
//-----------------------------------------------------------------------------
// Add an AccumulatePose call to the bonejob
//-----------------------------------------------------------------------------
void CBoneSetup_PS3::AccumulatePose_AddToBoneJob( bonejob_SPU* pSPUJob,
int sequence,
float cycle,
float flWeight,
CIKContext *pIKContext,
int pqStackLevel )
{
SNPROF_ANIM( "CBoneSetup_PS3::AccumulatePose_AddToBoneJob" );
if( pSPUJob->numTotalPoses >= MAX_ACCUMPOSECALLS )
{
m_errorFlags = BONEJOB_ERROR_EXCEEDEDMAXCALLS;
return;
}
if( ( pqStackLevel+1 ) >= MAX_PQSTACKLEVEL )
{
// pq stack depth exceeded, early out of job, run from scratch on PPU
m_errorFlags = BONEJOB_ERROR_EXCEEDEDPQSTACK;
return;
}
flWeight = clamp( flWeight, 0.0f, 1.0f );
if( sequence < 0 )
{
// just skip, no error flags?
return;
}
if( sequence >= m_pStudioHdr->GetNumSeq() )
{
sequence = 0;
}
//-------------------------------------------------------------------------------------
// get stack entry
accumposeentry_SPU *pPoseEntry = &pSPUJob->accumPoseEntry[ pSPUJob->numTotalPoses++ ];
//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
// copy call params and grab common data and ptrs for SPU path
mstudioseqdesc_t &seqdesc = ((CStudioHdr *)m_pStudioHdr)->pSeqdesc( sequence );
pPoseEntry->pEA_seqdesc = &seqdesc;
pPoseEntry->iSeq = sequence;
pPoseEntry->cycle = cycle;
pPoseEntry->weight = flWeight;
pPoseEntry->pqStackLevel = pqStackLevel;
pPoseEntry->seqdesc_numiklocks = seqdesc.numiklocks;
pPoseEntry->seqdesc_numikrules = seqdesc.numikrules;
pPoseEntry->seqdesc_flags = seqdesc.flags;
virtualmodel_t *pVModel = m_pStudioHdr->GetVirtualModel();
const virtualgroup_t *pSeqGroup = NULL;
pPoseEntry->pEA_seqgroup_boneMap = NULL;
pPoseEntry->pEA_seqgroup_masterBone = NULL;
if( pVModel )
{
const studiohdr_t *pSeqStudioHdr;
pSeqGroup = pVModel->pSeqGroup( sequence );
if( pSeqGroup )
{
pPoseEntry->pEA_seqgroup_boneMap = (void *)pSeqGroup->boneMap.Base();
pPoseEntry->pEA_seqgroup_masterBone = (void *)pSeqGroup->masterBone.Base();
}
pSeqStudioHdr = ((CStudioHdr *)m_pStudioHdr)->pSeqStudioHdr( sequence );
mstudiolinearbone_t *pLinearBones = pSeqStudioHdr->pLinearBones();
pPoseEntry->pEA_seq_linearBones = pLinearBones;
if( pLinearBones )
{
pPoseEntry->pEA_seq_linearbones_pos = (void *)(((byte *)pLinearBones) + pLinearBones->posindex);
pPoseEntry->pEA_seq_linearbones_quat = (void *)(((byte *)pLinearBones) + pLinearBones->quatindex);
}
pPoseEntry->pEA_seq_bones_pos = &pSeqStudioHdr->pBone(0)->pos;
}
pPoseEntry->pEA_seqdesc_boneWeight = (void *)seqdesc.pBoneweight( 0 );
//-------------------------------------------------------------------------------------
if( seqdesc.numiklocks )
{
AddSequenceLocks_PS3( pPoseEntry, m_pStudioHdr, seqdesc );
}
// potentially recurse
if( CalcPoseSingle( pPoseEntry, m_pStudioHdr, seqdesc, sequence, cycle, m_flPoseParameter, pSPUJob->currentTime ) )
{
pPoseEntry->numLocalLayers = AddLocalLayers( pSPUJob, seqdesc, sequence, cycle, 1.0f, pIKContext, pqStackLevel+1 );
}
pPoseEntry->numSequenceLayers = AddSequenceLayers( pSPUJob, seqdesc, sequence, cycle, flWeight, pIKContext, pqStackLevel+1 );
// update bonejob max bones
for( int lp = 0; lp < MAX_BLENDANIMS; lp++ )
{
pSPUJob->maxBones = MAX( pPoseEntry->anims[lp].animstudiohdr_numbones, pSPUJob->maxBones );
}
}
//-----------------------------------------------------------------------------
// Purpose: calculate a pose for a single sequence
// adds autolayers, runs local ik rukes
//-----------------------------------------------------------------------------
int CBoneSetup_PS3::AddSequenceLayers(
bonejob_SPU *pSPUJob,
mstudioseqdesc_t &seqdesc,
int sequence,
float cycle,
float flWeight,
CIKContext *pIKContext,
int pqStackLevel
)
{
SNPROF_ANIM("CBoneSetup_PS3::AddSequenceLayers");
int ret = 0;
for (int i = 0; i < seqdesc.numautolayers; i++)
{
mstudioautolayer_t *pLayer = seqdesc.pAutolayer( i );
if (pLayer->flags & STUDIO_AL_LOCAL)
continue;
float layerCycle = cycle;
float layerWeight = flWeight;
if (pLayer->start != pLayer->end)
{
float s = 1.0f;
float index;
if (!(pLayer->flags & STUDIO_AL_POSE))
{
index = cycle;
}
else
{
int iSequence = m_pStudioHdr->iRelativeSeq( sequence, pLayer->iSequence );
int iPose = m_pStudioHdr->GetSharedPoseParameter( iSequence, pLayer->iPose );
if (iPose != -1)
{
const mstudioposeparamdesc_t &Pose = ((CStudioHdr *)m_pStudioHdr)->pPoseParameter( iPose );
index = m_flPoseParameter[ iPose ] * (Pose.end - Pose.start) + Pose.start;
}
else
{
index = 0;
}
}
if (index < pLayer->start)
continue;
if (index >= pLayer->end)
continue;
if (index < pLayer->peak && pLayer->start != pLayer->peak)
{
s = (index - pLayer->start) / (pLayer->peak - pLayer->start);
}
else if (index > pLayer->tail && pLayer->end != pLayer->tail)
{
s = (pLayer->end - index) / (pLayer->end - pLayer->tail);
}
if (pLayer->flags & STUDIO_AL_SPLINE)
{
s = SimpleSpline( s );
}
if ((pLayer->flags & STUDIO_AL_XFADE) && (index > pLayer->tail))
{
layerWeight = ( s * flWeight ) / ( 1.0f - flWeight + s * flWeight );
}
else if (pLayer->flags & STUDIO_AL_NOBLEND)
{
layerWeight = s;
}
else
{
layerWeight = flWeight * s;
}
if (!(pLayer->flags & STUDIO_AL_POSE))
{
layerCycle = (cycle - pLayer->start) / (pLayer->end - pLayer->start);
}
}
ret++;
int iSequence = m_pStudioHdr->iRelativeSeq( sequence, pLayer->iSequence );
AccumulatePose_AddToBoneJob( pSPUJob, iSequence, layerCycle, layerWeight, pIKContext, pqStackLevel );
}
return ret;
}
//-----------------------------------------------------------------------------
// Purpose: calculate a pose for a single sequence
// adds autolayers, runs local ik rukes
//-----------------------------------------------------------------------------
int CBoneSetup_PS3::AddLocalLayers(
bonejob_SPU *pSPUJob,
mstudioseqdesc_t &seqdesc,
int sequence,
float cycle,
float flWeight,
CIKContext *pIKContext,
int pqStackLevel
)
{
SNPROF_ANIM("CBoneSetup_PS3::AddLocalLayers");
int ret = 0;
if (!(seqdesc.flags & STUDIO_LOCAL))
{
return ret;
}
for (int i = 0; i < seqdesc.numautolayers; i++)
{
mstudioautolayer_t *pLayer = seqdesc.pAutolayer( i );
if (!(pLayer->flags & STUDIO_AL_LOCAL))
continue;
float layerCycle = cycle;
float layerWeight = flWeight;
if (pLayer->start != pLayer->end)
{
float s = 1.0f;
if (cycle < pLayer->start)
continue;
if (cycle >= pLayer->end)
continue;
if (cycle < pLayer->peak && pLayer->start != pLayer->peak)
{
s = (cycle - pLayer->start) / (pLayer->peak - pLayer->start);
}
else if (cycle > pLayer->tail && pLayer->end != pLayer->tail)
{
s = (pLayer->end - cycle) / (pLayer->end - pLayer->tail);
}
if (pLayer->flags & STUDIO_AL_SPLINE)
{
s = SimpleSpline( s );
}
if ((pLayer->flags & STUDIO_AL_XFADE) && (cycle > pLayer->tail))
{
layerWeight = ( s * flWeight ) / ( 1.0f - flWeight + s * flWeight );
}
else if (pLayer->flags & STUDIO_AL_NOBLEND)
{
layerWeight = s;
}
else
{
layerWeight = flWeight * s;
}
layerCycle = (cycle - pLayer->start) / (pLayer->end - pLayer->start);
}
ret++;
int iSequence = m_pStudioHdr->iRelativeSeq( sequence, pLayer->iSequence );
AccumulatePose_AddToBoneJob( pSPUJob, iSequence, layerCycle, layerWeight, pIKContext, pqStackLevel );
}
return ret;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
IBoneSetup_PS3::IBoneSetup_PS3( const CStudioHdr *pStudioHdr, int boneMask, const float poseParameter[], bonejob_SPU *pBoneJobSPU )
{
m_pBoneSetup = new CBoneSetup_PS3( pStudioHdr, boneMask, poseParameter, pBoneJobSPU );
}
IBoneSetup_PS3::~IBoneSetup_PS3( void )
{
if ( m_pBoneSetup )
{
delete m_pBoneSetup;
}
}
void IBoneSetup_PS3::InitPose_PS3( BoneVector pos[], BoneQuaternion q[] )
{
::InitPose_PS3( m_pBoneSetup->m_pStudioHdr, pos, q, m_pBoneSetup->m_boneMask );
}
void IBoneSetup_PS3::CalcAutoplaySequences_AddPoseCalls( float flRealTime )
{
m_pBoneSetup->CalcAutoplaySequences_AddPoseCalls( flRealTime );
}
void IBoneSetup_PS3::AccumulatePose_AddToBoneJob( bonejob_SPU* pBonejobSPU, int sequence, float cycle, float flWeight, CIKContext *pIKContext, int pqStackLevel )
{
m_pBoneSetup->AccumulatePose_AddToBoneJob( pBonejobSPU, sequence, cycle, flWeight, pIKContext, pqStackLevel );
}
CStudioHdr *IBoneSetup_PS3::GetStudioHdr()
{
return (CStudioHdr *)m_pBoneSetup->m_pStudioHdr;
}
void IBoneSetup_PS3::ResetErrorFlags()
{
m_pBoneSetup->m_errorFlags = 0;
}
int IBoneSetup_PS3::ErrorFlags()
{
return m_pBoneSetup->m_errorFlags;
}
bonejob_SPU *IBoneSetup_PS3::GetBoneJobSPU()
{
return m_pBoneSetup->m_pBoneJobSPU;
}
int IBoneSetup_PS3::RunAccumulatePoseJobs_PPU( bonejob_SPU *pBonejobSPU )
{
return m_pBoneSetup->RunAccumulatePoseJobs_PPU( pBonejobSPU );
}
int IBoneSetup_PS3::RunAccumulatePoseJobs_SPU( bonejob_SPU *pBoneJobSPU, job_accumpose::JobDescriptor_t *pJobDescriptor )
{
return m_pBoneSetup->RunAccumulatePoseJobs_SPU( pBoneJobSPU, pJobDescriptor );
}
CBoneSetup_PS3::CBoneSetup_PS3( const CStudioHdr *pStudioHdr, int boneMask, const float poseParameter[], bonejob_SPU *pBoneJobSPU )
{
m_pStudioHdr = pStudioHdr;
m_boneMask = boneMask;
m_flPoseParameter = poseParameter;
m_pBoneJobSPU = pBoneJobSPU;
m_errorFlags = 0;
}
//-----------------------------------------------------------------------------
// Purpose: run all animations that automatically play and are driven off of poseParameters
// This version adds AccumulatePose calls to the current bonejob
//-----------------------------------------------------------------------------
void CBoneSetup_PS3::CalcAutoplaySequences_AddPoseCalls( float flRealTime )
{
SNPROF_ANIM( "CBoneSetup_PS3::CalcAutoplaySequences_AddPoseCalls" );
int i;
AddAutoLocks_PS3( m_pBoneJobSPU, m_pStudioHdr );
unsigned short *pList = NULL;
int count = m_pStudioHdr->GetAutoplayList( &pList );
for( i = 0; i < count; i++ )
{
int sequenceIndex = pList[i];
mstudioseqdesc_t &seqdesc = ((CStudioHdr *)m_pStudioHdr)->pSeqdesc( sequenceIndex );
if( seqdesc.flags & STUDIO_AUTOPLAY )
{
float cycle = 0.0f;
float cps = Studio_CPS( m_pStudioHdr, seqdesc, sequenceIndex, m_flPoseParameter );
cycle = flRealTime * cps;
cycle = cycle - (int)cycle;
// AccumulatePose( pos, q, sequenceIndex, cycle, 1.0, flRealTime, pIKContext );
// null ik context since dependencies are added but not used
// still need autoplaylocks added/solved
AccumulatePose_AddToBoneJob( m_pBoneJobSPU, sequenceIndex, cycle, 1.0f, NULL, 0 );
}
}
}
void MsgJobData( bonejob_SPU *pBoneJob )
{
int lp;
Msg("**********************************************************\n");
Msg(" BoneJob Data Start\n");
Msg("**********************************************************\n");
Msg("numikAutoplayLocks: %d\n", pBoneJob->numikAutoplayLocks);
for(lp = 0; lp< pBoneJob->numikAutoplayLocks; lp++)
{
Msg("pEA_IKAutoplayLocks[%d] = 0x%x\n", lp, (unsigned int)pBoneJob->pEA_IKAutoplayLocks[lp]);
}
Msg("numTotalPoses: %d\n", pBoneJob->numTotalPoses );
for(lp = 0; lp< pBoneJob->numTotalPoses; lp++)
{
accumposeentry_SPU *pPoseEntry = &pBoneJob->accumPoseEntry[lp];
Msg("PoseEntry[%d]\n",lp);
Msg("--------------\n");
Msg("pEA_seqdesc = 0x%x\n", (unsigned int)pPoseEntry->pEA_seqdesc);
Msg("pEA_seqgroup_boneMap = 0x%x\n", (unsigned int)pPoseEntry->pEA_seqgroup_boneMap);
Msg("pEA_seqgroup_masterBone = 0x%x\n", (unsigned int)pPoseEntry->pEA_seqgroup_masterBone);
Msg("pEA_seqdesc_boneWeight = 0x%x\n", (unsigned int)pPoseEntry->pEA_seqdesc_boneWeight);
Msg("pEA_seqdesc_iklocks = 0x%x\n", (unsigned int)pPoseEntry->pEA_seqdesc_iklocks);
Msg("pEA_seq_linearBones = 0x%x\n", (unsigned int)pPoseEntry->pEA_seq_linearBones);
Msg("pEA_seq_linearbones_pos = 0x%x\n", (unsigned int)pPoseEntry->pEA_seq_linearbones_pos);
Msg("pEA_seq_linearbones_quat = 0x%x\n", (unsigned int)pPoseEntry->pEA_seq_linearbones_quat);
Msg("pEA_seq_bones_pos = 0x%x\n", (unsigned int)pPoseEntry->pEA_seq_bones_pos);
switch( pPoseEntry->cpsPath )
{
case CPSPATH_FALSE:
break;
case CPSPATH_CALCANIM1:
case CPSPATH_CALCANIM1_SCALE1MINUSS0:
case CPSPATH_CALCANIM1_SCALES0:
break;
case CPSPATH_CALCANIM2_S0:
case CPSPATH_CALCANIM2_S1:
break;
case CPSPATH_CALCANIM3:
case CPSPATH_CALCANIM4:
break;
default:
break;
}
}
Msg("**********************************************************\n");
Msg(" BoneJob Data End\n");
Msg("**********************************************************\n");
}
//--------------------------------------------------------------------------------------------------------------------
// Entry point for running bone jobs, spu jobs pushed from here
//
//--------------------------------------------------------------------------------------------------------------------
int CBoneSetup_PS3::RunAccumulatePoseJobs_SPU( bonejob_SPU *pBoneJob, job_accumpose::JobDescriptor_t *pJobDescriptor )
{
SNPROF_ANIM("CBoneSetup_PS3::RunAccumulatePoseJobs_SPU");
ConVarRef cl_PS3_SPU_bones_debug( "cl_PS3_SPU_bones_debug" );
ConVarRef cl_PS3_SPU_bones_minbonecount( "cl_PS3_SPU_bones_minbonecount" );
int numBones = pBoneJob->numBones;
// don't push jobs with less than minbonecount bones to SPU, just perform the job inline on PPU, need to find a sweet spot for minbonecount
if( numBones < cl_PS3_SPU_bones_minbonecount.GetInt() )
{
return RunAccumulatePoseJobs_PPU( pBoneJob );
}
BoneVector *pos = (BoneVector *)pBoneJob->pEA_pos;
BoneQuaternion *q = (BoneQuaternion *)pBoneJob->pEA_q;
if( cl_PS3_SPU_bones_debug.GetInt() == 2 )
{
memcpy( g_posInit, pos, sizeof(BoneVector) * numBones );
memcpy( g_qInit, q, sizeof(BoneQuaternion) * numBones );
}
// initialise header
pJobDescriptor->header = g_AccumPoseJobDescriptor.header;
pJobDescriptor->header.useInOutBuffer = 1;
pJobDescriptor->header.sizeStack = (16*1024)/8;
pJobDescriptor->header.sizeInOrInOut = 0;
pJobDescriptor->header.sizeDmaList = 0;
// add dma's
AddInputDma( pJobDescriptor, sizeof(bonejob_SPU), pBoneJob );
AddInputDma( pJobDescriptor, sizeof(BoneVector) * pBoneJob->numBones, pBoneJob->pEA_pos );
AddInputDma( pJobDescriptor, sizeof(BoneQuaternion) * pBoneJob->numBones, pBoneJob->pEA_q );
pJobDescriptor->header.sizeInOrInOut += (sizeof(ikcontextikrule_t) * MAX_IKRULES) + (sizeof(int) * 4);
int jobPort = g_pBoneJobs->GetNextFreeSPURSPort();
// kick off job
//Msg("push job port %d, numbones %d\n", jobPort, pBoneJob->numBones );
CELL_VERIFY( g_pBoneJobs->m_pRoot->m_queuePortAnim[ jobPort ].pushJob( &pJobDescriptor->header, sizeof(*pJobDescriptor), 0, CELL_SPURS_JOBQUEUE_FLAG_SYNC_JOB ) );
if( cl_PS3_SPU_bones_debug.GetInt() )
{
//Msg("_DEBUG_ACCUMPOSE sync job %d\n", jobPort);
CELL_VERIFY( g_pBoneJobs->m_pRoot->m_queuePortAnim[ jobPort ].sync( 0 ) );
if( cl_PS3_SPU_bones_debug.GetInt() > 1 )
{
// reset pos, q
memcpy( pos, g_posInit, sizeof(BoneVector) * numBones );
memcpy( q, g_qInit, sizeof(BoneQuaternion) * numBones );
RunAccumulatePoseJobs_PPU( pBoneJob );
}
}
return jobPort;
}
//--------------------------------------------------------------------------------------------------------------------
// Entry point for running bone jobs
// This is the PPU version
//
//--------------------------------------------------------------------------------------------------------------------
int CBoneSetup_PS3::RunAccumulatePoseJobs_PPU( bonejob_SPU *pBoneJob )
{
SNPROF_ANIM("CBoneSetup_PS3::RunAccumulatePoseJobs_PPU");
InitLSStack();
BoneVector *pos = (BoneVector *)pBoneJob->pEA_pos;
BoneQuaternion *q = (BoneQuaternion *)pBoneJob->pEA_q;
g_addDep_numIKRules = 0;
// pos and q already contain result of initial ::init, which all subsequent calls of ::init take a copy of
// don't write over until the end when it should contain the final pos, q data
C_AccumulatePose_SPU cAccumPose( pBoneJob );
int numBones = pBoneJob->numBones;
// backup
memcpy( g_posInit, pos, sizeof(BoneVector) * numBones );
memcpy( g_qInit, q, sizeof(BoneQuaternion) * numBones );
// into pq stack which we work on
BoneVector *pos0 = (BoneVector *)PushLSStack( sizeof(BoneVector) * numBones );
BoneQuaternion *q0 = (BoneQuaternion *)PushLSStack( sizeof(BoneQuaternion) * numBones );
memcpy( pos0, pos, sizeof(BoneVector) * numBones );
memcpy( q0, q, sizeof(BoneQuaternion) * numBones );
cAccumPose.ResetCount();
cAccumPose.SetIKContext( pBoneJob->pEA_IKContext );
while( cAccumPose.GetCount() < pBoneJob->numPoses_PreAutoSeq )
{
cAccumPose.AccumulatePose( pos0, q0 );
}
CIKContext_PS3 auto_ik;
auto_ik.Init( pBoneJob, pBoneJob->autoikAngles, pBoneJob->autoikOrigin, pBoneJob->currentTime, pBoneJob->autoikFramecount, pBoneJob->boneMask );
auto_ik.AddAutoplayLocks( pBoneJob, pos0, q0 );
while( cAccumPose.GetCount() < pBoneJob->numTotalPoses )
{
cAccumPose.AccumulatePose( pos0, q0 );
}
auto_ik.SolveAutoplayLocks( pBoneJob, pos0, q0 );
// write results to pos, q
memcpy( pos, pos0, sizeof( BoneVector ) * numBones );
memcpy( q, q0, sizeof( BoneQuaternion ) * numBones );
// write AddDependencies() potential IK rules
if( g_addDep_numIKRules )
{
memcpy( pBoneJob->pEA_addDep_numIKRules, &g_addDep_numIKRules, sizeof(int) );
memcpy( pBoneJob->pEA_addDep_IKRules, g_addDep_IKRules, g_addDep_numIKRules * sizeof(ikcontextikrule_t_PS3) );
}
PopLSStack( sizeof(BoneQuaternion) * numBones );
PopLSStack( sizeof(BoneVector) * numBones );
TermLSStack();
return VJobsRoot::MAXPORTS_ANIM; // => can only be a ppu job
}
#endif // #if !defined(__SPU__)
//--------------------------------------------------------------------------------------------------------------------
//
// Below this point needs to go to SPU, above this point PPU only (prep pass for SPU)
//
//--------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: turn a 2x2 blend into a 3 way triangle blend
// Returns: returns the animation indices and barycentric coordinates of a triangle
// the triangle is a right triangle, and the diagonal is between elements [0] and [2]
//-----------------------------------------------------------------------------
void Calc3WayBlendIndices_SPU( accumposeentry_SPU *pPoseEntry, int i0, int i1, float s0, float s1, int *pAnimIndices, float *pWeight )
{
// Figure out which bi-section direction we are using to make triangles.
bool bEven = ( ( ( i0 + i1 ) & 0x1 ) == 0 );
// diagonal is between elements 1 & 3
// TL to BR
if ( bEven )
{
if ( s0 > s1 )
{
// B
pAnimIndices[0] = pPoseEntry->animIndices[0];//0;
pAnimIndices[1] = pPoseEntry->animIndices[1];//1;
pAnimIndices[2] = pPoseEntry->animIndices[3];//3;
pWeight[0] = (1.0f - s0);
pWeight[1] = s0 - s1;
}
else
{
// C
pAnimIndices[0] = pPoseEntry->animIndices[3];//3;
pAnimIndices[1] = pPoseEntry->animIndices[2];//2;
pAnimIndices[2] = pPoseEntry->animIndices[0];//0;
pWeight[0] = s0;
pWeight[1] = s1 - s0;
}
}
// BL to TR
else
{
float flTotal = s0 + s1;
if( flTotal > 1.0f )
{
// D
pAnimIndices[0] = pPoseEntry->animIndices[1];//1;
pAnimIndices[1] = pPoseEntry->animIndices[3];//3;
pAnimIndices[2] = pPoseEntry->animIndices[2];//2;
pWeight[0] = (1.0f - s1);
pWeight[1] = s0 - 1.0f + s1;
}
else
{
// A
pAnimIndices[0] = pPoseEntry->animIndices[2];//2;
pAnimIndices[1] = pPoseEntry->animIndices[0];//0;
pAnimIndices[2] = pPoseEntry->animIndices[1];//1;
pWeight[0] = s1;
pWeight[1] = 1.0f - s0 - s1;
}
}
// clamp the diagonal
if( pWeight[1] < 0.001f )
pWeight[1] = 0.0f;
pWeight[2] = 1.0f - pWeight[0] - pWeight[1];
Assert( pWeight[0] >= 0.0f && pWeight[0] <= 1.0f );
Assert( pWeight[1] >= 0.0f && pWeight[1] <= 1.0f );
Assert( pWeight[2] >= 0.0f && pWeight[2] <= 1.0f );
// fix up pose entry weights so that IK rules are blended correctly (assume they all come in as zero for the 3 way blend case)
pPoseEntry->anims[ pAnimIndices[0] ].seqdesc_weight = pWeight[0];
pPoseEntry->anims[ pAnimIndices[1] ].seqdesc_weight = pWeight[1];
pPoseEntry->anims[ pAnimIndices[2] ].seqdesc_weight = pWeight[2];
}
void C_AccumulatePose_SPU::AddLocalLayers( accumposeentry_SPU *pAccPoseEntry, BoneVector pos[], BoneQuaternion q[] )
{
for( int lp = 0; lp < pAccPoseEntry->numLocalLayers; lp++ )
{
AccumulatePose( pos, q );
}
}
void C_AccumulatePose_SPU::AddSequenceLayers( accumposeentry_SPU *pAccPoseEntry, BoneVector pos[], BoneQuaternion q[] )
{
for( int lp = 0; lp < pAccPoseEntry->numSequenceLayers; lp++ )
{
AccumulatePose( pos, q );
}
}
//-----------------------------------------------------------------------------
// Purpose: calculate a pose for a single sequence
// SPU pass
//-----------------------------------------------------------------------------
bool C_AccumulatePose_SPU::CalcPoseSingle(
const bonejob_SPU *pBonejob,
accumposeentry_SPU *pPoseEntry,
BoneVector *pos,
BoneQuaternion *q,
int *boneMap,
float *boneWeight,
int sequence,
const float poseParameter[],
int boneMask,
float flTime
)
{
SNPROF_ANIM("C_AccumulatePose_SPU::CalcPoseSingle");
bool bResult = true;
BoneVector *pos2 = (BoneVector *)PushLSStack( sizeof(BoneVector) * pBonejob->numBones );
BoneQuaternion *q2 = (BoneQuaternion *)PushLSStack( sizeof(BoneQuaternion) * pBonejob->numBones );
BoneVector *pos3 = (BoneVector *)PushLSStack( sizeof(BoneVector) * pBonejob->numBones );
BoneQuaternion *q3 = (BoneQuaternion *)PushLSStack( sizeof(BoneQuaternion) * pBonejob->numBones );
float s0 = pPoseEntry->s0;
float s1 = pPoseEntry->s1;
int i0 = pPoseEntry->i0;
int i1 = pPoseEntry->i1;
float cycle = pPoseEntry->cyclePoseSingle;
switch( pPoseEntry->cpsPath )
{
case CPSPATH_FALSE:
bResult = false;
break;
case CPSPATH_CALCANIM1:
CalcAnimation_PS3( pBonejob, pPoseEntry, pos, q, boneMap, boneWeight, pPoseEntry->animIndices[0], cycle, boneMask );
break;
case CPSPATH_CALCANIM1_SCALE1MINUSS0:
CalcAnimation_PS3( pBonejob, pPoseEntry, pos, q, boneMap, boneWeight, pPoseEntry->animIndices[0], cycle, boneMask );
ScaleBones_PS3( pBonejob, pPoseEntry, q, pos, boneMap, boneWeight, 1.0f - s0, boneMask );
break;
case CPSPATH_CALCANIM1_SCALES0:
CalcAnimation_PS3( pBonejob, pPoseEntry, pos, q, boneMap, boneWeight, pPoseEntry->animIndices[0], cycle, boneMask );
ScaleBones_PS3( pBonejob, pPoseEntry, q, pos, boneMap, boneWeight, s0, boneMask );
break;
case CPSPATH_CALCANIM2_S0:
CalcAnimation_PS3( pBonejob, pPoseEntry, pos, q, boneMap, boneWeight, pPoseEntry->animIndices[0], cycle, boneMask );
CalcAnimation_PS3( pBonejob, pPoseEntry, pos2, q2, boneMap, boneWeight, pPoseEntry->animIndices[1], cycle, boneMask );
BlendBones_PS3( pBonejob, pPoseEntry, q, pos, boneMap, boneWeight, q2, pos2, s0, boneMask );
break;
case CPSPATH_CALCANIM2_S1:
CalcAnimation_PS3( pBonejob, pPoseEntry, pos, q, boneMap, boneWeight, pPoseEntry->animIndices[0], cycle, boneMask );
CalcAnimation_PS3( pBonejob, pPoseEntry, pos2, q2, boneMap, boneWeight, pPoseEntry->animIndices[1], cycle, boneMask );
BlendBones_PS3( pBonejob, pPoseEntry, q, pos, boneMap, boneWeight, q2, pos2, s1, boneMask );
break;
case CPSPATH_CALCANIM3:
int iAnimIndices[3];
float weight[3];
Calc3WayBlendIndices_SPU( pPoseEntry, i0, i1, s0, s1, iAnimIndices, weight );
if( weight[1] < 0.001f )
{
// on diagonal
CalcAnimation_PS3( pBonejob, pPoseEntry, pos, q, boneMap, boneWeight, iAnimIndices[0], cycle, boneMask );
CalcAnimation_PS3( pBonejob, pPoseEntry, pos2, q2, boneMap, boneWeight, iAnimIndices[2], cycle, boneMask );
BlendBones_PS3( pBonejob, pPoseEntry, q, pos, boneMap, boneWeight, q2, pos2, weight[2] / (weight[0] + weight[2]), boneMask );
}
else
{
CalcAnimation_PS3( pBonejob, pPoseEntry, pos, q, boneMap, boneWeight, iAnimIndices[0], cycle, boneMask );
CalcAnimation_PS3( pBonejob, pPoseEntry, pos2, q2, boneMap, boneWeight, iAnimIndices[1], cycle, boneMask );
BlendBones_PS3( pBonejob, pPoseEntry, q, pos, boneMap, boneWeight, q2, pos2, weight[1] / (weight[0] + weight[1]), boneMask );
CalcAnimation_PS3( pBonejob, pPoseEntry, pos3, q3, boneMap, boneWeight, iAnimIndices[2], cycle, boneMask );
BlendBones_PS3( pBonejob, pPoseEntry, q, pos, boneMap, boneWeight, q3, pos3, weight[2], boneMask );
}
break;
case CPSPATH_CALCANIM4:
CalcAnimation_PS3( pBonejob, pPoseEntry, pos, q, boneMap, boneWeight, pPoseEntry->animIndices[0], cycle, boneMask );
CalcAnimation_PS3( pBonejob, pPoseEntry, pos2, q2, boneMap, boneWeight, pPoseEntry->animIndices[1], cycle, boneMask );
BlendBones_PS3( pBonejob, pPoseEntry, q, pos, boneMap, boneWeight, q2, pos2, s0, boneMask );
CalcAnimation_PS3( pBonejob, pPoseEntry, pos2, q2, boneMap, boneWeight, pPoseEntry->animIndices[2], cycle, boneMask );
CalcAnimation_PS3( pBonejob, pPoseEntry, pos3, q3, boneMap, boneWeight, pPoseEntry->animIndices[3], cycle, boneMask );
BlendBones_PS3( pBonejob, pPoseEntry, q2, pos2, boneMap, boneWeight, q3, pos3, s0, boneMask );
BlendBones_PS3( pBonejob, pPoseEntry, q, pos, boneMap, boneWeight, q2, pos2, s1, boneMask );
break;
default:
bResult = false;
break;
}
PopLSStack( sizeof(BoneQuaternion) * pBonejob->numBones );
PopLSStack( sizeof(BoneVector) * pBonejob->numBones );
PopLSStack( sizeof(BoneQuaternion) * pBonejob->numBones );
PopLSStack( sizeof(BoneVector) * pBonejob->numBones );
return bResult;
}
//-----------------------------------------------------------------------------
// SPU/bonejob version of AccumulatePose
// Assumes bonejob calls to this happen in the correct order (recursion has happened during the 1st/prep pass on PPU)
// individual AccumulatePose call data is stored in bonejob->accumPoseEntry
//-----------------------------------------------------------------------------
void C_AccumulatePose_SPU::AccumulatePose( BoneVector pos[], BoneQuaternion q[] )
{
SNPROF_ANIM("C_AccumulatePose_SPU::AccumulatePose");
accumposeentry_SPU *pPoseEntry = &m_pBoneJob->accumPoseEntry[ m_iCount++ ];
int boneMask = m_pBoneJob->boneMask;
int numBones = m_pBoneJob->numBones;
float time = m_pBoneJob->currentTime;
float *pPoseParam = m_pBoneJob->poseparam;
float weight = pPoseEntry->weight;
int sequence = pPoseEntry->iSeq;
void *pIKContext = GetIKContext();
CIKContext_PS3 seq_ik;
if( pPoseEntry->seqdesc_numiklocks )
{
//IKOFF
seq_ik.Init( m_pBoneJob, vec3_angle, vec3_origin, 0.0f, 0, boneMask );
//IKOFF
seq_ik.AddSequenceLocks( m_pBoneJob, pPoseEntry, pos, q );
}
{
BoneVector *pos2 = (BoneVector *)PushLSStack( sizeof(BoneVector) * m_pBoneJob->maxBones );
BoneQuaternion *q2 = (BoneQuaternion *)PushLSStack( sizeof(BoneQuaternion) * m_pBoneJob->maxBones );
int *pBoneMap = (int *)PushLSStack( sizeof(int) * m_pBoneJob->maxBones );
float *pBoneWeight = (float *)PushLSStack( sizeof(float) * m_pBoneJob->maxBones );
// used in calcposesingle (calcanim/calcvirtualanim) & SlerpBones
// needs to be stack based, as AddLocalLayers may recurse AccumulatePose...
GetBoneMapBoneWeight_SPU( m_pBoneJob, pPoseEntry, pBoneMap, pBoneWeight );
if( pPoseEntry->seqdesc_flags & STUDIO_LOCAL )
{
// ::init
memcpy( pos2, g_posInit, sizeof( BoneVector ) * numBones );
memcpy( q2, g_qInit, sizeof( BoneQuaternion ) * numBones );
}
if( CalcPoseSingle( m_pBoneJob, pPoseEntry, pos2, q2, pBoneMap, pBoneWeight, sequence, pPoseParam, boneMask, time ) )
{
AddLocalLayers( pPoseEntry, pos2, q2 );
SlerpBones_SPU( m_pBoneJob, pPoseEntry, q, pos, q2, pos2, pBoneMap, pBoneWeight, weight, boneMask );
}
PopLSStack( sizeof(float) * m_pBoneJob->maxBones );
PopLSStack( sizeof(int) * m_pBoneJob->maxBones );
PopLSStack( sizeof(BoneQuaternion) * m_pBoneJob->maxBones );
PopLSStack( sizeof(BoneVector) * m_pBoneJob->maxBones );
}
if( pIKContext )
{
//IKOFF
AddDependencies_SPU( m_pBoneJob, pPoseEntry, weight );
}
AddSequenceLayers( pPoseEntry, pos, q );
if( pPoseEntry->seqdesc_numiklocks )
{
//IKOFF
seq_ik.SolveSequenceLocks( m_pBoneJob, pPoseEntry, pos, q );
}
}