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.
292 lines
7.0 KiB
292 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
|
|
|