Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
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.

293 lines
7.0 KiB

//++ BulliT
//Most parts written by David "Nighthawk" Flor (dflor@mach3.com) for the mod Opera (http://www.halflife.net/opera)
//Parts of code from Valve Software mdlviewer (CalcBonePosition).
#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "parsemsg.h"
#include "com_model.h"
#include "studio.h"
#include "com_weapons.h"
#include "agmodel.h"
#ifdef AG_USE_CHEATPROTECTION
void CalcBonePosition(int frame, mstudiobone_t *pbone, mstudioanim_t *panim, float *pos);
extern int g_iPure;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
AgModel::AgModel()
{
m_vMinBounds = Vector(0,0,0);
m_vMaxBounds = Vector(0,0,0);
m_iVertexCount = 0;
m_vMinBone = Vector(0,0,0);
m_vMaxBone = Vector(0,0,0);
m_iBoneCount = 0;
m_bCorrupt = false;
m_bFoundAndChecked = false;
}
AgModel::~AgModel()
{
}
void AgModel::AddVertex( const Vector &vPoint )
{
if (m_iVertexCount == 0)
{
m_vMinBounds = m_vMaxBounds = vPoint;
}
else
{
m_vMinBounds.x = min( m_vMinBounds.x, vPoint.x );
m_vMinBounds.y = min( m_vMinBounds.y, vPoint.y );
m_vMinBounds.z = min( m_vMinBounds.z, vPoint.z );
m_vMaxBounds.x = max( m_vMaxBounds.x, vPoint.x );
m_vMaxBounds.y = max( m_vMaxBounds.y, vPoint.y );
m_vMaxBounds.z = max( m_vMaxBounds.z, vPoint.z );
}
m_iVertexCount++;
}
void AgModel::AddBone( const Vector &vPoint )
{
if (m_iBoneCount == 0)
{
m_vMinBone = m_vMaxBone = vPoint;
}
else
{
m_vMinBone.x = min( m_vMinBone.x, vPoint.x );
m_vMinBone.y = min( m_vMinBone.y, vPoint.y );
m_vMinBone.z = min( m_vMinBone.z, vPoint.z );
m_vMaxBone.x = max( m_vMaxBone.x, vPoint.x );
m_vMaxBone.y = max( m_vMaxBone.y, vPoint.y );
m_vMaxBone.z = max( m_vMaxBone.z, vPoint.z );
}
m_iBoneCount++;
}
void AgModel::AddBonesToVertices( void )
{
Vector vAdjust;
if (m_iBoneCount > 0)
{
vAdjust = (m_vMaxBone - m_vMinBone);
AddVertex( vAdjust / 2 );
AddVertex( -(vAdjust / 2) );
m_vMinBone = m_vMaxBone = Vector(0,0,0);
m_iBoneCount = 0;
}
}
void AgModel::ReadModel(const char *szModelName)
{
char *pBuffer;
char *pTempBuffer;
char szFullName[ _MAX_PATH ];
float flBone[3];
strcpy( szFullName, szModelName );
pBuffer = (char*)gEngfuncs.COM_LoadFile( szFullName, 5, NULL );
if (pBuffer)
{
studiohdr_t *pHeader;
mstudiobodyparts_t *pBodyParts;
mstudiomodel_t *pModel;
long iCnt;
long iModelCnt, iModels;
long iVert, iVertCnt;
vec3_t *pVert;
mstudiobone_t *pBone;
long iBoneCnt, iBones;
mstudioseqdesc_t *pSequence;
long iSequenceCnt, iSequences;
mstudioanim_t *pAnim;
long iFrameCnt, iFrames;
pHeader = (studiohdr_t *)pBuffer;
if (10 == pHeader->version)
{
pTempBuffer = (pBuffer + pHeader->bodypartindex);
pBodyParts = (mstudiobodyparts_t *)pTempBuffer;
iModels = 0;
for (iCnt = 0; iCnt < pHeader->numbodyparts; iCnt++)
iModels += pBodyParts[iCnt].nummodels;
pTempBuffer += (pHeader->numbodyparts * sizeof(mstudiobodyparts_t));
pModel = (mstudiomodel_t *)pTempBuffer;
for (iModelCnt = 0; iModelCnt < iModels; iModelCnt++)
{
iVert = pModel[iModelCnt].numverts;
pVert = (vec3_t *)(pBuffer + pModel[iModelCnt].vertindex);
for (iVertCnt = 0; iVertCnt < iVert; iVertCnt++)
{
AddVertex( pVert[iVertCnt] );
}
}
pBone = (mstudiobone_t *)(pBuffer + pHeader->boneindex);
iBones = pHeader->numbones;
pSequence = (mstudioseqdesc_t *)(pBuffer + pHeader->seqindex);
iSequences = pHeader->numseq;
for (iSequenceCnt = 0; iSequenceCnt < iSequences; iSequenceCnt++)
{
iFrames = pSequence[iSequenceCnt].numframes;
pTempBuffer = (pBuffer + pSequence[iSequenceCnt].animindex);
pAnim = (mstudioanim_t *)pTempBuffer;
for (iBoneCnt = 0; iBoneCnt < iBones; iBoneCnt++)
{
for (iFrameCnt = 0; iFrameCnt < iFrames; iFrameCnt++)
{
CalcBonePosition( iFrameCnt, pBone + iBoneCnt,
pAnim, flBone );
AddBone( flBone );
}
}
AddBonesToVertices();
}
m_bFoundAndChecked = true;
}
else
{
m_bCorrupt = true;
}
gEngfuncs.COM_FreeFile( pBuffer );
}
}
void CalcBonePosition( int frame, mstudiobone_t *pbone, mstudioanim_t *panim, float *pos )
{
float s = 0;
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]);
k = frame;
// find span of values that includes the frame we want
while (panimvalue->num.total <= k)
{
k -= panimvalue->num.total;
panimvalue += panimvalue->num.valid + 1;
}
// 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];
}
}
}
}
}
bool AgModel::CheckModel(const char* szModelName)
{
try
{
ReadModel(szModelName);
}
catch(...)
{
m_bCorrupt = true;
}
if (m_bCorrupt)
{
char szMessage[256];
sprintf(szMessage,"Server enforces model check and %s seems to be corrupt.\n",szModelName);
AgLog(szMessage);
ConsolePrint(szMessage);
#ifdef _DEBUG
return true;
#else
return false;
#endif
}
Vector vMaxBounds = Vector(0,0,0);
Vector vBounds = m_vMaxBounds - m_vMinBounds;
if ( !strnicmp( szModelName, "/models/player", 14) )
{
if (0 < g_iPure)
vMaxBounds = Vector( 78, 30, 98 );
else
vMaxBounds = Vector( 105, 105, 105 ); //Big fucking models allowed..
}
else if ( !strnicmp( szModelName, "/models/p_", 9 ) )
vMaxBounds = Vector( 42, 21, 60 );
else if ( !strnicmp( szModelName, "/models/w_", 9 ) )
vMaxBounds = Vector( 82, 69, 76);
else if ( !strnicmp( szModelName, "/models/v_", 9 ) )
vMaxBounds = Vector( 46, 55, 120 );
else
vMaxBounds = Vector( 100, 100, 100 );
if (vBounds.x > vMaxBounds.x || vBounds.y > vMaxBounds.y || vBounds.z > vMaxBounds.z)
{
char szMessage[256];
sprintf(szMessage,"Server enforces model check and %s is not valid. Your model got these ranges: %.4f,%.4f,%.4f\n",szModelName,vBounds.x, vBounds.y, vBounds.z);
AgLog(szMessage);
sprintf(szMessage,"Server enforces model check and %s is not valid.\n",szModelName);
ConsolePrint(szMessage);
#ifdef _DEBUG
return true;
#else
return false;
#endif
}
return true;
}
bool AgModel::IsChecked()
{
return m_bFoundAndChecked;
}
#endif //AG_USE_CHEATPROTECTION
//-- Martin Webrant