This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+98
View File
@@ -0,0 +1,98 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include <windows.h>
#include <STDIO.H>
int
ReadBmpFile(
char* szFile,
unsigned char** ppbPalette,
unsigned char** ppbBits,
int *pwidth,
int *pheight)
{
int rc = 0;
FILE *pfile = NULL;
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih;
RGBQUAD rgrgbPalette[256];
ULONG cbPalBytes;
ULONG cbBmpBits;
BYTE* pbBmpBits;
// Bogus parameter check
if (!(ppbPalette != NULL && ppbBits != NULL))
{ rc = -1000; goto GetOut; }
// File exists?
if ((pfile = fopen(szFile, "rb")) == NULL)
{ rc = -1; goto GetOut; }
// Read file header
if (fread(&bmfh, sizeof bmfh, 1/*count*/, pfile) != 1)
{ rc = -2; goto GetOut; }
// Bogus file header check
if (!(bmfh.bfReserved1 == 0 && bmfh.bfReserved2 == 0))
{ rc = -2000; goto GetOut; }
// Read info header
if (fread(&bmih, sizeof bmih, 1/*count*/, pfile) != 1)
{ rc = -3; goto GetOut; }
// Bogus info header check
if (!(bmih.biSize == sizeof bmih && bmih.biPlanes == 1))
{ rc = -3000; goto GetOut; }
// Bogus bit depth? Only 8-bit supported.
if (bmih.biBitCount != 8)
{ rc = -4; goto GetOut; }
// Bogus compression? Only non-compressed supported.
if (bmih.biCompression != BI_RGB)
{ rc = -5; goto GetOut; }
// Figure out how many entires are actually in the table
if (bmih.biClrUsed == 0)
{
cbPalBytes = (1 << bmih.biBitCount) * sizeof( RGBQUAD );
}
else
{
cbPalBytes = bmih.biClrUsed * sizeof( RGBQUAD );
}
// Read palette (256 entries)
if (fread(rgrgbPalette, cbPalBytes, 1/*count*/, pfile) != 1)
{ rc = -6; goto GetOut; }
// Read bitmap bits (remainder of file)
cbBmpBits = bmfh.bfSize - ftell(pfile);
pbBmpBits = (BYTE *)malloc(cbBmpBits);
if (fread(pbBmpBits, cbBmpBits, 1/*count*/, pfile) != 1)
{ rc = -7; goto GetOut; }
// Set output parameters
*ppbPalette = (BYTE *)malloc(sizeof rgrgbPalette);
memcpy(*ppbPalette, rgrgbPalette, cbPalBytes);
*ppbBits = pbBmpBits;
*pwidth = bmih.biWidth;
*pheight = bmih.biHeight;
printf("w %d h %d s %d\n",bmih.biWidth, bmih.biHeight, cbBmpBits );
GetOut:
if (pfile) fclose(pfile);
return rc;
}
+460
View File
@@ -0,0 +1,460 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ==========
//
// Function which do validation tests on UVs values at the s_source_t level
//
//=============================================================================
#include "tier1/fmtstr.h"
#include "tier1/utlmap.h"
#include "studiomdl.h"
#include "checkuv.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CCheckUVCmd::CCheckUVCmd()
{
Clear();
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CCheckUVCmd::Clear()
{
ClearCheck( CHECK_UV_ALL_FLAGS );
m_nOptGutterTexWidth = 512;
m_nOptGutterTexHeight = 512;
m_nOptGutterMin = 5;
}
//-----------------------------------------------------------------------------
// Dumps an s_soruce_t as an OBJ file
//-----------------------------------------------------------------------------
static void WriteOBJ( const char *pszFilename, const s_source_t *pSource )
{
FILE *pFile = fopen( pszFilename, "w" );
fprintf( pFile, "#\n" );
fprintf( pFile, "# s_source_t: %s\n", pSource->filename );
fprintf( pFile, "# Bone Count: %d\n", pSource->numbones );
for ( int i = 0; i < pSource->numbones; ++i )
{
if ( pSource->localBone[i].parent >= 0 )
{
fprintf( pFile, "# Bone %3d: %s Parent %3d: %s\n", i, pSource->localBone[i].name, pSource->localBone[i].parent, pSource->localBone[pSource->localBone[i].parent].name );
}
else
{
fprintf( pFile, "# Bone %3d: %s\n", i, pSource->localBone[i].name );
}
}
fprintf( pFile, "# Mesh Count: %d\n", pSource->nummeshes );
fprintf( pFile, "# Vertex Count: %d\n", pSource->numvertices );
fprintf( pFile, "# Face Count: %d\n", pSource->numfaces );
fprintf( pFile, "#\n" );
fprintf( pFile, "# positions\n" );
fprintf( pFile, "#\n" );
for ( int i = 0; i < pSource->numvertices; ++i )
{
const s_vertexinfo_t &v = pSource->vertex[i];
fprintf( pFile, "v %.4f %.4f %.4f\n", v.position.x, v.position.y, v.position.z );
}
fprintf( pFile, "#\n" );
fprintf( pFile, "# texture coordinates\n" );
fprintf( pFile, "#\n" );
for ( int i = 0; i < pSource->numvertices; ++i )
{
const s_vertexinfo_t &v = pSource->vertex[i];
fprintf( pFile, "vt %.4f %.4f\n", v.texcoord.x, v.texcoord.y );
}
fprintf( pFile, "#\n" );
fprintf( pFile, "# normals\n" );
fprintf( pFile, "#\n" );
for ( int i = 0; i < pSource->numvertices; ++i )
{
const s_vertexinfo_t &v = pSource->vertex[i];
fprintf( pFile, "vn %.4f %.4f %.4f\n", v.normal.x, v.normal.y, v.normal.z );
}
for ( int i = 0; i < pSource->nummeshes; ++i )
{
const s_mesh_t &m = pSource->mesh[i];
const s_texture_t &t = g_texture[pSource->meshindex[i]];
fprintf( pFile, "#\n" );
fprintf( pFile, "# mesh %d - %s\n", i, t.name );
fprintf( pFile, "# Face Count: %d\n", m.numfaces );
fprintf( pFile, "#\n" );
fprintf( pFile, "usemtl %s\n", t.name );
for ( int j = 0; j < m.numfaces; ++j )
{
const s_face_t &f = pSource->face[m.faceoffset + j];
fprintf( pFile, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
f.a, f.a, f.a,
f.b, f.b, f.b,
f.c, f.c, f.c );
}
}
fclose( pFile );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CCheckUVCmd::CheckUVs( const s_source_t *const *pSourceList, int nSourceCount ) const
{
if ( !DoAnyCheck() || nSourceCount <= 0 )
return true;
bool bRet = true;
for ( int i = 0; i < nSourceCount; ++i )
{
const s_source_t *pSource = pSourceList[i];
bRet &= CheckNormalized( pSource );
bRet &= CheckOverlap( pSource );
bRet &= CheckInverse( pSource );
bRet &= CheckGutter( pSource );
}
return bRet;
}
//-----------------------------------------------------------------------------
// Check that all UVs are in the [0, 1] range
//-----------------------------------------------------------------------------
bool CCheckUVCmd::CheckNormalized( const struct s_source_t *pSource ) const
{
if ( !DoCheck( CHECK_UV_FLAG_NORMALIZED ) )
return true;
CUtlRBTree< int > badVertexIndices( CDefOps< int >::LessFunc );
for ( int i = 0; i < pSource->numvertices; ++i )
{
const s_vertexinfo_t &v = pSource->vertex[i];
if (
v.texcoord.x < 0.0f || v.texcoord.x > 1.0f ||
v.texcoord.y < 0.0f || v.texcoord.y > 1.0f )
{
badVertexIndices.InsertIfNotFound( i );
}
}
if ( badVertexIndices.Count() <= 0 )
return true;
Msg( "Error! %s\n", pSource->filename );
Msg( " UVs outside of [0, 1] range\n" );
for ( int i = 0; i < pSource->nummeshes; ++i )
{
const s_mesh_t &m = pSource->mesh[i];
const s_texture_t &t = g_texture[pSource->meshindex[i]];
CUtlRBTree< int > badMeshVertexIndices( CDefOps< int >::LessFunc );
for ( int j = 0; j < m.numfaces; ++j )
{
const s_face_t &f = pSource->face[m.faceoffset + j];
if ( badVertexIndices.HasElement( f.a ) )
{
badMeshVertexIndices.InsertIfNotFound( f.a );
}
if ( badVertexIndices.HasElement( f.b ) )
{
badMeshVertexIndices.InsertIfNotFound( f.b );
}
if ( badVertexIndices.HasElement( f.c ) )
{
badMeshVertexIndices.InsertIfNotFound( f.c );
}
}
for ( auto vIt = badMeshVertexIndices.FirstInorder(); badMeshVertexIndices.IsValidIndex( vIt ); vIt = badMeshVertexIndices.NextInorder( vIt ) )
{
PrintVertex( pSource->vertex[badMeshVertexIndices.Element( vIt )], t );
}
}
return false;
}
//-----------------------------------------------------------------------------
// Check that all polygons in UV do not overlap
//-----------------------------------------------------------------------------
bool CCheckUVCmd::CheckOverlap( const struct s_source_t *pSource ) const
{
if ( !DoCheck( CHECK_UV_FLAG_OVERLAP ) )
return true;
bool bRet = true;
CUtlVector< CUtlVector< int > > faceOverlapMap;
faceOverlapMap.SetCount( pSource->numfaces );
for ( int i = 0; i < pSource->numfaces; ++i )
{
const s_face_t &fA = pSource->face[i];
const Vector2D &tAA = pSource->vertex[fA.a].texcoord;
const Vector2D &tAB = pSource->vertex[fA.b].texcoord;
const Vector2D &tAC = pSource->vertex[fA.c].texcoord;
for ( int j = i + 1; j < pSource->numfaces; ++j )
{
const s_face_t &fB = pSource->face[j];
const Vector2D tB[] = {
pSource->vertex[fB.a].texcoord,
pSource->vertex[fB.b].texcoord,
pSource->vertex[fB.c].texcoord };
for ( int k = 0; k < ARRAYSIZE( tB ); ++k )
{
const Vector vCheck = Barycentric( tB[k], tAA, tAB, tAC );
if ( vCheck.x > 0.0f && vCheck.y > 0.0f && vCheck.z > 0.0f )
{
if ( bRet )
{
Msg( "Error! %s\n", pSource->filename );
Msg( " Overlapping UV faces\n" );
bRet = false;
}
faceOverlapMap[i].AddToTail( j );
break;
}
}
}
}
for ( int i = 0; i < faceOverlapMap.Count(); ++i )
{
const CUtlVector< int > &overlapList = faceOverlapMap[i];
if ( overlapList.IsEmpty() )
continue;;
const int nFaceA = i;
const int nMeshA = FindMeshIndex( pSource, nFaceA );
PrintFace( pSource, nMeshA, nFaceA );
Msg( " Overlaps\n" );
for ( int j = 0; j < overlapList.Count(); ++j )
{
const int nFaceB = overlapList[j];
const int nMeshB = FindMeshIndex( pSource, nFaceB );
PrintFace( pSource, nMeshB, nFaceB, " " );
}
}
return bRet;
}
//-----------------------------------------------------------------------------
// Check that all polygons in UV have the correct winding, i.e. the cross
// product of edge AB x BC points the right direction
//-----------------------------------------------------------------------------
bool CCheckUVCmd::CheckInverse( const struct s_source_t *pSource ) const
{
if ( !DoCheck( CHECK_UV_FLAG_INVERSE ) )
return true;
bool bRetVal = true;
for ( int i = 0; i < pSource->nummeshes; ++i )
{
const s_mesh_t &m = pSource->mesh[i];
for ( int j = 0; j < m.numfaces; ++j )
{
const int nFaceIndex = m.faceoffset + j;
const s_face_t &f = pSource->face[nFaceIndex];
const Vector2D &tA = pSource->vertex[f.a].texcoord;
const Vector2D &tB = pSource->vertex[f.b].texcoord;
const Vector2D &tC = pSource->vertex[f.c].texcoord;
const Vector vA( tA.x, tA.y, 0.0f );
const Vector vB( tB.x, tB.y, 0.0f );
const Vector vC( tC.x, tC.y, 0.0f );
const Vector vAB = vB - vA;
const Vector vBC = vC - vB;
const Vector vUVNormal = CrossProduct( vAB, vBC );
const float flDot = DotProduct( vUVNormal, Vector( 0.0f, 0.0f, 1.0f ) );
if ( flDot < 0.0f )
{
if ( bRetVal )
{
Msg( "Error! %s\n", pSource->filename );
Msg( " Inverse UV faces\n" );
bRetVal = false;
}
PrintFace( pSource, i, nFaceIndex );
}
}
}
return bRetVal;
}
//-----------------------------------------------------------------------------
// Check that the distance between edges in UV islands is a minimum number of pixels for a given texture size
//-----------------------------------------------------------------------------
bool CCheckUVCmd::CheckGutter( const struct s_source_t *pSource ) const
{
if ( !DoCheck( CHECK_UV_FLAG_GUTTER ) )
return true;
// TODO: Implement me!
return true;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
Vector CCheckUVCmd::Barycentric( const Vector2D &vP, const Vector2D &vA, const Vector2D &vB, const Vector2D &vC )
{
const Vector2D v0 = vB - vA;
const Vector2D v1 = vC - vA;
const Vector2D v2 = vP - vA;
const float d00 = DotProduct2D( v0, v0 );
const float d01 = DotProduct2D( v0, v1 );
const float d11 = DotProduct2D( v1, v1 );
const float d20 = DotProduct2D( v2, v0 );
const float d21 = DotProduct2D( v2, v1 );
const float flDenom = d00 * d11 - d01 * d01;
const float flV = ( d11 * d20 - d01 * d21 ) / flDenom;
const float flW = ( d00 * d21 - d01 * d20 ) / flDenom;
const float flU = 1.0f - flV - flW;
return Vector( flV, flW, flU );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
Vector CCheckUVCmd::Barycentric( const Vector &vP, const Vector &vA, const Vector &vB, const Vector &vC )
{
const Vector v0 = vB - vA;
const Vector v1 = vC - vA;
const Vector v2 = vP - vA;
const float d00 = DotProduct( v0, v0 );
const float d01 = DotProduct( v0, v1 );
const float d11 = DotProduct( v1, v1 );
const float d20 = DotProduct( v2, v0 );
const float d21 = DotProduct( v2, v1 );
const float flDenom = d00 * d11 - d01 * d01;
const float flV = ( d11 * d20 - d01 * d21 ) / flDenom;
const float flW = ( d00 * d21 - d01 * d20 ) / flDenom;
const float flU = 1.0f - flV - flW;
return Vector( flV, flW, flU );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int CCheckUVCmd::FindMeshIndex( const struct s_source_t *pSource, int nFaceIndex )
{
for ( int i = 1; i < pSource->nummeshes; ++i )
{
if ( nFaceIndex <= pSource->mesh[i].faceoffset )
return i;
}
return 0;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CCheckUVCmd::PrintVertex( const s_vertexinfo_t &v, const char *pszPrefix /* = " " */ )
{
Msg( "%sP: %8.4f %8.4f %8.4f T: %8.4f %8.4f\n",
pszPrefix,
v.position.x, v.position.y, v.position.z,
v.texcoord.x, v.texcoord.y );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CCheckUVCmd::PrintVertex( const s_vertexinfo_t &v, const s_texture_t &t, const char *pszPrefix /* = " " */ )
{
Msg( "%sP: %8.4f %8.4f %8.4f T: %8.4f %8.4f M: %s\n",
pszPrefix,
v.position.x, v.position.y, v.position.z,
v.texcoord.x, v.texcoord.y,
t.name );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CCheckUVCmd::PrintFace( const s_source_t *pSource, const int nMesh, const int nFace, const char *pszPrefix /* = " " */ )
{
const s_texture_t &t = g_texture[pSource->meshindex[nMesh]];
const s_face_t &f = pSource->face[nFace];
Msg( "%sF: %4d %s\n", pszPrefix, nFace, t.name );
PrintVertex( pSource->vertex[f.a], pszPrefix );
PrintVertex( pSource->vertex[f.b], pszPrefix );
PrintVertex( pSource->vertex[f.c], pszPrefix );
}
+59
View File
@@ -0,0 +1,59 @@
//============ Copyright (c) Valve Corporation, All rights reserved. ==========
//
//=============================================================================
#pragma once
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CCheckUVCmd
{
public:
int m_nOptGutterTexWidth; // Width of texture for gutter check
int m_nOptGutterTexHeight; // Height of texture for gutter check
int m_nOptGutterMin; // Minimum number of pixels between polygon islands in UV space
enum CheckMask_t
{
CHECK_UV_FLAG_NORMALIZED = ( 1 << 0 ),
CHECK_UV_FLAG_OVERLAP = ( 1 << 1 ),
CHECK_UV_FLAG_INVERSE = ( 1 << 2 ),
CHECK_UV_FLAG_GUTTER = ( 1 << 3 ),
CHECK_UV_ALL_FLAGS = ( CHECK_UV_FLAG_NORMALIZED | CHECK_UV_FLAG_OVERLAP | CHECK_UV_FLAG_INVERSE | CHECK_UV_FLAG_GUTTER )
};
int m_nOptChecks;
CCheckUVCmd();
void Clear();
bool DoCheck( CheckMask_t eCheckMask ) const { return ( m_nOptChecks & eCheckMask ) == eCheckMask; }
bool DoAnyCheck() const { return ( m_nOptChecks & CHECK_UV_ALL_FLAGS ) != 0; }
void SetCheck( CheckMask_t eCheckMask ) { m_nOptChecks |= ( CHECK_UV_ALL_FLAGS & eCheckMask ); }
void ClearCheck( CheckMask_t eCheckMask ) { m_nOptChecks &= ( CHECK_UV_ALL_FLAGS & ~eCheckMask ); }
bool CheckUVs( const struct s_source_t *const *pSourceList, int nSourceCount ) const;
// Check that all UVs are in the [0, 1] range
bool CheckNormalized( const struct s_source_t *pSource ) const;
// Check that all polygons in UV do not overlap
bool CheckOverlap( const struct s_source_t *pSource ) const;
// Check that all polygons in UV have the correct winding, i.e. the cross
// product of edge AB x BC points the right direction
bool CheckInverse( const struct s_source_t *pSource ) const;
// Check that the distance between edges in UV islands is a minimum number of pixels for a given texture size
bool CheckGutter( const struct s_source_t *pSource ) const;
// Returns barycentric coordinates Vector( u, v, w ) for point vP with respect to triangle ( vA, vB, vC )
static Vector Barycentric( const Vector2D &vP, const Vector2D &vA, const Vector2D &vB, const Vector2D &vC );
static Vector Barycentric( const Vector &vP, const Vector &vA, const Vector &vB, const Vector &vC );
static int FindMeshIndex( const struct s_source_t *pSource, int nFaceIndex );
static void PrintVertex( const struct s_vertexinfo_t &v, const char *pszPrefix = " " );
static void PrintVertex( const struct s_vertexinfo_t &v, const struct s_texture_t &t, const char *pszPrefix = " " );
static void PrintFace( const s_source_t *pSource, const int nMesh, const int nFace, const char *pszPrefix = " " );
};
File diff suppressed because it is too large Load Diff
+28
View File
@@ -0,0 +1,28 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef COLLISIONMODEL_H
#define COLLISIONMODEL_H
#pragma once
extern void Cmd_CollisionText( void );
extern int DoCollisionModel( bool separateJoints );
// execute after simplification, before writing
extern void CollisionModel_Build( void );
// execute during writing
extern void CollisionModel_Write( long checkSum );
void CollisionModel_ExpandBBox( Vector &mins, Vector &maxs );
#endif // COLLISIONMODEL_H
File diff suppressed because it is too large Load Diff
+131
View File
@@ -0,0 +1,131 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef FILEBUFFER_H
#define FILEBUFFER_H
#ifdef _WIN32
#pragma once
#endif
#include "tier1/smartptr.h"
#include "tier2/p4helpers.h"
class CFileBuffer
{
public:
CFileBuffer( int size )
{
m_pData = new unsigned char[size];
#ifdef _DEBUG
m_pUsed = new const char *[size];
memset( m_pUsed, 0, size * sizeof( const char * ) );
#endif
m_Size = size;
m_pCurPos = m_pData;
#ifdef _DEBUG
memset( m_pData, 0xbaadf00d, size );
#endif
}
~CFileBuffer()
{
delete [] m_pData;
#ifdef _DEBUG
delete [] m_pUsed;
#endif
}
#ifdef _DEBUG
void TestWritten( int EndOfFileOffset )
{
if ( !g_quiet )
{
printf( "testing to make sure that the whole file has been written\n" );
}
int i;
for( i = 0; i < EndOfFileOffset; i++ )
{
if( !m_pUsed[i] )
{
printf( "offset %d not written, end of file invalid!\n", i );
assert( 0 );
}
}
}
#endif
void WriteToFile( const char *fileName, int size )
{
CPlainAutoPtr< CP4File > spFile( g_p4factory->AccessFile( fileName ) );
spFile->Edit();
FILE *fp = fopen( fileName, "wb" );
if( !fp )
{
MdlWarning( "Can't open \"%s\" for writing!\n", fileName );
return;
}
fwrite( m_pData, 1, size, fp );
fclose( fp );
spFile->Add();
}
void WriteAt( int offset, void *data, int size, const char *name )
{
// printf( "WriteAt: \"%s\" offset: %d end: %d size: %d\n", name, offset, offset + size - 1, size );
m_pCurPos = m_pData + offset;
#ifdef _DEBUG
int i;
const char **used = m_pUsed + offset;
bool bitched = false;
for( i = 0; i < size; i++ )
{
if( used[i] )
{
if( !bitched )
{
printf( "overwrite at %d! (overwriting \"%s\" with \"%s\")\n", i + offset, used[i], name );
assert( 0 );
bitched = true;
}
}
else
{
used[i] = name;
}
}
#endif // _DEBUG
Append( data, size );
}
int GetOffset( void )
{
return m_pCurPos - m_pData;
}
void *GetPointer( int offset )
{
return m_pData + offset;
}
private:
void Append( void *data, int size )
{
assert( m_pCurPos + size - m_pData < m_Size );
memcpy( m_pCurPos, data, size );
m_pCurPos += size;
}
CFileBuffer(); // undefined
int m_Size;
unsigned char *m_pData;
unsigned char *m_pCurPos;
#ifdef _DEBUG
const char **m_pUsed;
#endif
};
#endif // FILEBUFFER_H
+232
View File
@@ -0,0 +1,232 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include <windows.h>
#include "HardwareMatrixState.h"
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "studio.h"
#include "studiomdl.h"
CHardwareMatrixState::CHardwareMatrixState()
{
m_LRUCounter = 0;
m_NumMatrices = 0;
m_matrixState = NULL;
m_savedMatrixState = NULL;
}
void CHardwareMatrixState::Init( int numHardwareMatrices )
{
m_NumMatrices = numHardwareMatrices;
delete [] m_matrixState;
m_matrixState = new MatrixState_t[m_NumMatrices];
Assert( m_matrixState );
delete [] m_savedMatrixState;
m_savedMatrixState = new MatrixState_t[m_NumMatrices];
Assert( m_savedMatrixState );
m_LRUCounter = 0;
m_AllocatedMatrices = 0;
int i;
for( i = 0; i < m_NumMatrices; i++ )
{
m_matrixState[i].allocated = false;
}
}
bool CHardwareMatrixState::AllocateMatrix( int globalMatrixID )
{
int i;
if( IsMatrixAllocated( globalMatrixID ) )
{
return true;
}
for( i = 0; i < m_NumMatrices; i++ )
{
if( !m_matrixState[i].allocated )
{
m_matrixState[i].globalMatrixID = globalMatrixID;
m_matrixState[i].allocated = true;
m_matrixState[i].lastUsageID = m_LRUCounter++;
++m_AllocatedMatrices;
DumpState();
return true;
}
}
DumpState();
return false;
}
int CHardwareMatrixState::FindLocalLRUIndex( void )
{
int oldestLRUCounter = INT_MAX;
int i;
int oldestID = 0;
for( i = 0; i < m_NumMatrices; i++ )
{
if( !m_matrixState[i].allocated )
{
continue;
}
if( m_matrixState[i].lastUsageID < oldestLRUCounter )
{
oldestLRUCounter = m_matrixState[i].lastUsageID;
oldestID = i;
}
}
Assert( oldestLRUCounter != INT_MAX );
return oldestID;
}
void CHardwareMatrixState::DeallocateLRU( void )
{
int id;
id = FindLocalLRUIndex();
m_matrixState[id].allocated = false;
--m_AllocatedMatrices;
}
void CHardwareMatrixState::DeallocateLRU( int n )
{
int i;
for( i = 0; i < n; i++ )
{
DeallocateLRU();
}
}
bool CHardwareMatrixState::IsMatrixAllocated( int globalMatrixID ) const
{
int i;
for( i = 0; i < m_NumMatrices; i++ )
{
if( m_matrixState[i].globalMatrixID == globalMatrixID &&
m_matrixState[i].allocated )
{
return true;
}
}
return false;
}
void CHardwareMatrixState::DeallocateAll()
{
int i;
DumpState();
for( i = 0; i < m_NumMatrices; i++ )
{
m_matrixState[i].allocated = false;
m_matrixState[i].globalMatrixID = INT_MAX;
m_matrixState[i].lastUsageID = INT_MAX;
}
m_AllocatedMatrices = 0;
DumpState();
}
void CHardwareMatrixState::SaveState( void )
{
int i;
for( i = 0; i < m_NumMatrices; i++ )
{
m_savedMatrixState[i] = m_matrixState[i];
}
}
void CHardwareMatrixState::RestoreState( void )
{
int i;
for( i = 0; i < m_NumMatrices; i++ )
{
m_matrixState[i] = m_savedMatrixState[i];
}
}
int CHardwareMatrixState::AllocatedMatrixCount() const
{
return m_AllocatedMatrices;
}
int CHardwareMatrixState::FreeMatrixCount() const
{
return m_NumMatrices - m_AllocatedMatrices;
}
int CHardwareMatrixState::GetNthBoneGlobalID( int n ) const
{
int i;
int m = 0;
for( i = 0; i < m_NumMatrices; i++ )
{
if( m_matrixState[i].allocated )
{
if( n == m )
{
return m_matrixState[i].globalMatrixID;
}
m++;
}
}
Assert( 0 );
MdlError( "GetNthBoneGlobalID() Failure\n" );
return 0;
}
void CHardwareMatrixState::DumpState( void )
{
int i;
static char buf[256];
//#ifndef _DEBUG
return;
//#endif
OutputDebugString( "DumpState\n:" );
for( i = 0; i < m_NumMatrices; i++ )
{
if( m_matrixState[i].allocated )
{
sprintf( buf, "%d: allocated: %s lastUsageID: %d globalMatrixID: %d\n",
i,
m_matrixState[i].allocated ? "true " : "false",
m_matrixState[i].lastUsageID,
m_matrixState[i].globalMatrixID );
OutputDebugString( buf );
}
}
}
int CHardwareMatrixState::FindHardwareMatrix( int globalMatrixID )
{
int i;
for( i = 0; i < m_NumMatrices; i++ )
{
if( m_matrixState[i].globalMatrixID == globalMatrixID )
{
return i;
}
}
Assert( 0 );
MdlError( "barfing in FindHardwareMatrix\n" );
return 0;
}
+71
View File
@@ -0,0 +1,71 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef HARDWAREMATRIXSTATE_H
#define HARDWAREMATRIXSTATE_H
#pragma once
// This emulates the hardware matrix palette and keeps up with
// matrix usage, LRU's matrices, etc.
class CHardwareMatrixState
{
public:
CHardwareMatrixState();
void Init( int numHardwareMatrices );
// return false if there is no slot for this matrix.
bool AllocateMatrix( int globalMatrixID );
// deallocate the least recently used matrix
void DeallocateLRU( void );
void DeallocateLRU( int n );
// return true if a matrix is allocate.
bool IsMatrixAllocated( int globalMatrixID ) const;
// flush usage flags - signifies that none of the matrices are being used in the current strip
// do this when starting a new strip.
void SetAllUnused();
void DeallocateAll();
// save the complete state of the hardware matrices
void SaveState();
// restore the complete state of the hardware matrices
void RestoreState();
// Returns the number of free + unsed matrices
int AllocatedMatrixCount() const;
int FreeMatrixCount() const;
int GetNthBoneGlobalID( int n ) const;
void DumpState( void );
private:
int FindHardwareMatrix( int globalMatrixID );
int FindLocalLRUIndex( void );
// Increment and return LRU counter.
struct MatrixState_t
{
bool allocated;
int lastUsageID;
int globalMatrixID;
};
int m_LRUCounter;
int m_NumMatrices;
int m_AllocatedMatrices;
MatrixState_t *m_matrixState;
MatrixState_t *m_savedMatrixState;
};
#endif // HARDWAREMATRIXSTATE_H
+71
View File
@@ -0,0 +1,71 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include <stdlib.h>
#include <stdio.h>
#include "HardwareVertexCache.h"
CHardwareVertexCache::CHardwareVertexCache()
{
m_Fifo = NULL;
m_Size = 0;
Flush();
}
void CHardwareVertexCache::Init( int size )
{
m_Size = size;
m_Fifo = new int[size];
Flush();
}
void CHardwareVertexCache::Flush( void )
{
m_HeadIndex = 0;
m_NumEntries = 0;
}
bool CHardwareVertexCache::IsPresent( int index )
{
int i;
// printf( "testing if %d is present\n", index );
for( i = 0; i < m_NumEntries; i++ )
{
if( m_Fifo[( m_HeadIndex + i ) % m_Size] == index )
{
// printf( "yes!\n" );
return true;
}
}
// printf( "no!\n" );
// Print();
return false;
}
void CHardwareVertexCache::Insert( int index )
{
// printf( "Inserting: %d\n", index );
m_Fifo[( m_HeadIndex + m_NumEntries ) % m_Size] = index;
if( m_NumEntries == m_Size )
{
m_HeadIndex = ( m_HeadIndex + 1 ) % m_Size;
}
else
{
m_NumEntries++;
}
// Print();
}
void CHardwareVertexCache::Print( void )
{
int i;
for( i = 0; i < m_NumEntries; i++ )
{
printf( "fifo entry %d: %d\n", i, ( int )m_Fifo[( m_HeadIndex + i ) % m_Size] );
}
}
+32
View File
@@ -0,0 +1,32 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef HARDWAREVERTEXCACHE_H
#define HARDWAREVERTEXCACHE_H
#ifdef _WIN32
#pragma once
#endif
// emulate a hardware post T&L vertex fifo
class CHardwareVertexCache
{
public:
CHardwareVertexCache();
void Init( int size );
void Insert( int index );
bool IsPresent( int index );
void Flush( void );
void Print( void );
private:
int m_Size;
int *m_Fifo;
int m_HeadIndex;
int m_NumEntries;
};
#endif // HARDWAREVERTEXCACHE_H
+882
View File
@@ -0,0 +1,882 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
//
// studiomdl.c: generates a studio .mdl file from a .qc script
// models/<scriptname>.mdl.
//
#pragma warning( disable : 4244 )
#pragma warning( disable : 4237 )
#pragma warning( disable : 4305 )
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <math.h>
#include "cmdlib.h"
#include "scriplib.h"
#include "mathlib/mathlib.h"
#include "studio.h"
#include "studiomdl.h"
//#include "..\..\dlls\activity.h"
bool IsEnd( char const* pLine )
{
if (strncmp( "end", pLine, 3 ) != 0)
return false;
return (pLine[3] == '\0') || (pLine[3] == '\n');
}
int SortAndBalanceBones( int iCount, int iMaxCount, int bones[], float weights[] )
{
int i;
// collapse duplicate bone weights
for (i = 0; i < iCount-1; i++)
{
int j;
for (j = i + 1; j < iCount; j++)
{
if (bones[i] == bones[j])
{
weights[i] += weights[j];
weights[j] = 0.0;
}
}
}
// do sleazy bubble sort
int bShouldSort;
do {
bShouldSort = false;
for (i = 0; i < iCount-1; i++)
{
if (weights[i+1] > weights[i])
{
int j = bones[i+1]; bones[i+1] = bones[i]; bones[i] = j;
float w = weights[i+1]; weights[i+1] = weights[i]; weights[i] = w;
bShouldSort = true;
}
}
} while (bShouldSort);
// throw away all weights less than 1/20th
while (iCount > 1 && weights[iCount-1] < 0.05)
{
iCount--;
}
// clip to the top iMaxCount bones
if (iCount > iMaxCount)
{
iCount = iMaxCount;
}
float t = 0;
for (i = 0; i < iCount; i++)
{
t += weights[i];
}
if (t <= 0.0)
{
// missing weights?, go ahead and evenly share?
// FIXME: shouldn't this error out?
t = 1.0 / iCount;
for (i = 0; i < iCount; i++)
{
weights[i] = t;
}
}
else
{
// scale to sum to 1.0
t = 1.0 / t;
for (i = 0; i < iCount; i++)
{
weights[i] = weights[i] * t;
}
}
return iCount;
}
void Grab_Vertexlist( s_source_t *psource )
{
while (1)
{
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
{
int j;
int bone;
Vector p;
int iCount, bones[4];
float weights[4];
g_iLinecount++;
// check for end
if (IsEnd(g_szLine))
return;
int i = sscanf( g_szLine, "%d %d %f %f %f %d %d %f %d %f %d %f %d %f",
&j,
&bone,
&p[0], &p[1], &p[2],
&iCount,
&bones[0], &weights[0], &bones[1], &weights[1], &bones[2], &weights[2], &bones[3], &weights[3] );
if (i == 5)
{
if (bone < 0 || bone >= psource->numbones)
{
MdlWarning( "bogus bone index\n" );
MdlWarning( "%d %s :\n%s", g_iLinecount, g_szFilename, g_szLine );
MdlError( "Exiting due to errors\n" );
}
VectorCopy( p, g_vertex[j] );
g_bone[j].numbones = 1;
g_bone[j].bone[0] = bone;
g_bone[j].weight[0] = 1.0;
}
else if (i > 5)
{
iCount = SortAndBalanceBones( iCount, MAXSTUDIOBONEWEIGHTS, bones, weights );
VectorCopy( p, g_vertex[j] );
g_bone[j].numbones = iCount;
for (i = 0; i < iCount; i++)
{
g_bone[j].bone[i] = bones[i];
g_bone[j].weight[i] = weights[i];
}
}
else
{
MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine );
}
}
}
}
void Grab_Facelist( s_source_t *psource )
{
while (1)
{
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
{
int j;
s_tmpface_t f;
g_iLinecount++;
// check for end
if (IsEnd(g_szLine))
return;
if (sscanf( g_szLine, "%d %d %d %d",
&j,
&f.a, &f.b, &f.c) == 4)
{
g_face[j] = f;
}
else
{
MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine );
}
}
}
}
void Grab_Materiallist( s_source_t *psource )
{
while (1)
{
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
{
// char name[256];
char path[MAX_PATH];
rgb2_t a, d, s;
float g;
int j;
g_iLinecount++;
// check for end
if (IsEnd(g_szLine))
return;
if (sscanf( g_szLine, "%d %f %f %f %f %f %f %f %f %f %f %f %f %f \"%[^\"]s",
&j,
&a.r, &a.g, &a.b, &a.a,
&d.r, &d.g, &d.b, &d.a,
&s.r, &s.g, &s.b, &s.a,
&g,
path ) == 15)
{
if (path[0] == '\0')
{
psource->texmap[j] = -1;
}
else if (j < ARRAYSIZE(psource->texmap))
{
psource->texmap[j] = LookupTexture( path );
}
else
{
MdlError( "Too many materials, max %d\n", ARRAYSIZE(psource->texmap) );
}
}
}
}
}
void Grab_Texcoordlist( s_source_t *psource )
{
while (1)
{
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
{
int j;
Vector2D t;
g_iLinecount++;
// check for end
if (IsEnd(g_szLine))
return;
if (sscanf( g_szLine, "%d %f %f",
&j,
&t[0], &t[1]) == 3)
{
t[1] = 1.0 - t[1];
g_texcoord[j][0] = t[0];
g_texcoord[j][1] = t[1];
}
else
{
MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine );
}
}
}
}
void Grab_Normallist( s_source_t *psource )
{
while (1)
{
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
{
int j;
int bone;
Vector n;
g_iLinecount++;
// check for end
if (IsEnd(g_szLine))
return;
if (sscanf( g_szLine, "%d %d %f %f %f",
&j,
&bone,
&n[0], &n[1], &n[2]) == 5)
{
if (bone < 0 || bone >= psource->numbones)
{
MdlWarning( "bogus bone index\n" );
MdlWarning( "%d %s :\n%s", g_iLinecount, g_szFilename, g_szLine );
MdlError( "Exiting due to errors\n" );
}
VectorCopy( n, g_normal[j] );
}
else
{
MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine );
}
}
}
}
void Grab_Faceattriblist( s_source_t *psource )
{
while (1)
{
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
{
int j;
int smooth;
int material;
s_tmpface_t f;
unsigned short s;
g_iLinecount++;
// check for end
if (IsEnd(g_szLine))
return;
if (sscanf( g_szLine, "%d %d %d %d %d %d %d %d %d",
&j,
&material,
&smooth,
&f.ta, &f.tb, &f.tc,
&f.na, &f.nb, &f.nc) == 9)
{
f.a = g_face[j].a;
f.b = g_face[j].b;
f.c = g_face[j].c;
f.material = UseTextureAsMaterial( psource->texmap[material] );
if (f.material < 0)
{
MdlError( "face %d references NULL texture %d\n", j, material );
}
if (1)
{
s = f.b; f.b = f.c; f.c = s;
s = f.tb; f.tb = f.tc; f.tc = s;
s = f.nb; f.nb = f.nc; f.nc = s;
}
g_face[j] = f;
}
else
{
MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine );
}
}
}
}
int closestNormal( int v, int n )
{
float maxdot = -1.0;
float dot;
int r = n;
v_unify_t *cur = v_list[v];
while (cur)
{
dot = DotProduct( g_normal[cur->n], g_normal[n] );
if (dot > maxdot)
{
r = cur->n;
maxdot = dot;
}
cur = cur->next;
}
return r;
}
int AddToVlist( int v, int m, int n, int t, int firstref )
{
v_unify_t *prev = NULL;
v_unify_t *cur = v_list[v];
while (cur)
{
if (cur->m == m && cur->n == n && cur->t == t)
{
cur->refcount++;
return cur - v_listdata;
}
prev = cur;
cur = cur->next;
}
if (numvlist >= MAXSTUDIOVERTS)
{
MdlError( "Too many unified vertices\n");
}
cur = &v_listdata[numvlist++];
cur->lastref = -1;
cur->refcount = 1;
cur->firstref = firstref;
cur->v = v;
cur->m = m;
cur->n = n;
cur->t = t;
if (prev)
{
prev->next = cur;
}
else
{
v_list[v] = cur;
}
return numvlist - 1;
}
void DecrementReferenceVlist( int uv, int numverts )
{
if (uv < 0 || uv >= MAXSTUDIOVERTS)
MdlError( "decrement outside of range\n");
v_listdata[uv].refcount--;
if (v_listdata[uv].refcount == 0)
{
v_listdata[uv].lastref = numverts;
}
else if (v_listdata[uv].refcount < 0)
{
MdlError("<0 ref\n");
}
}
void UnifyIndices( s_source_t *psource )
{
int i;
static s_tmpface_t tmpface[MAXSTUDIOTRIANGLES]; // mrm processed g_face
static s_face_t uface[MAXSTUDIOTRIANGLES]; // mrm processed unified face
// clear v_list
numvlist = 0;
memset( v_list, 0, sizeof( v_list ) );
memset( v_listdata, 0, sizeof( v_listdata ) );
// create an list of all the
for (i = 0; i < g_numfaces; i++)
{
tmpface[i] = g_face[i];
uface[i].a = AddToVlist( g_face[i].a, g_face[i].material, g_face[i].na, g_face[i].ta, g_numverts );
uface[i].b = AddToVlist( g_face[i].b, g_face[i].material, g_face[i].nb, g_face[i].tb, g_numverts );
uface[i].c = AddToVlist( g_face[i].c, g_face[i].material, g_face[i].nc, g_face[i].tc, g_numverts );
// keep an original copy
g_src_uface[i] = uface[i];
}
// printf("%d : %d %d %d\n", numvlist, g_numverts, g_numnormals, g_numtexcoords );
}
void CalcModelTangentSpaces( s_source_t *pSrc );
//-----------------------------------------------------------------------------
// Builds a list of unique vertices in a source
//-----------------------------------------------------------------------------
static void BuildUniqueVertexList( s_source_t *pSource, const int *pDesiredToVList )
{
// allocate memory
pSource->vertex = (s_vertexinfo_t *)kalloc( pSource->numvertices, sizeof( s_vertexinfo_t ) );
// create arrays of unique vertexes, normals, texcoords.
for (int i = 0; i < pSource->numvertices; i++)
{
int j = pDesiredToVList[i];
s_vertexinfo_t &vertex = pSource->vertex[i];
VectorCopy( g_vertex[ v_listdata[j].v ], vertex.position );
VectorCopy( g_normal[ v_listdata[j].n ], vertex.normal );
Vector2Copy( g_texcoord[ v_listdata[j].t ], vertex.texcoord );
vertex.boneweight.numbones = g_bone[ v_listdata[j].v ].numbones;
int k;
for( k = 0; k < MAXSTUDIOBONEWEIGHTS; k++ )
{
vertex.boneweight.bone[k] = g_bone[ v_listdata[j].v ].bone[k];
vertex.boneweight.weight[k] = g_bone[ v_listdata[j].v ].weight[k];
}
// store a bunch of other info
vertex.material = v_listdata[j].m;
#if 0
pSource->vertexInfo[i].firstref = v_listdata[j].firstref;
pSource->vertexInfo[i].lastref = v_listdata[j].lastref;
#endif
// printf("%4d : %2d : %6.2f %6.2f %6.2f\n", i, psource->boneweight[i].bone[0], psource->vertex[i][0], psource->vertex[i][1], psource->vertex[i][2] );
}
}
//-----------------------------------------------------------------------------
// sort new vertices by materials, last used
//-----------------------------------------------------------------------------
static int vlistCompare( const void *elem1, const void *elem2 )
{
v_unify_t *u1 = &v_listdata[*(int *)elem1];
v_unify_t *u2 = &v_listdata[*(int *)elem2];
// sort by material
if (u1->m < u2->m)
return -1;
if (u1->m > u2->m)
return 1;
// sort by last used
if (u1->lastref < u2->lastref)
return -1;
if (u1->lastref > u2->lastref)
return 1;
return 0;
}
static void SortVerticesByMaterial( int *pDesiredToVList, int *pVListToDesired )
{
for ( int i = 0; i < numvlist; i++ )
{
pDesiredToVList[i] = i;
}
qsort( pDesiredToVList, numvlist, sizeof( int ), vlistCompare );
for ( int i = 0; i < numvlist; i++ )
{
pVListToDesired[ pDesiredToVList[i] ] = i;
}
}
//-----------------------------------------------------------------------------
// sort new faces by materials, last used
//-----------------------------------------------------------------------------
static int faceCompare( const void *elem1, const void *elem2 )
{
int i1 = *(int *)elem1;
int i2 = *(int *)elem2;
// sort by material
if (g_face[i1].material < g_face[i2].material)
return -1;
if (g_face[i1].material > g_face[i2].material)
return 1;
// sort by original usage
if (i1 < i2)
return -1;
if (i1 > i2)
return 1;
return 0;
}
static void SortFacesByMaterial( int *pDesiredToSrcFace )
{
// NOTE: Unlike SortVerticesByMaterial, srcFaceToDesired isn't needed, so we're not computing it
for ( int i = 0; i < g_numfaces; i++ )
{
pDesiredToSrcFace[i] = i;
}
qsort( pDesiredToSrcFace, g_numfaces, sizeof( int ), faceCompare );
}
//-----------------------------------------------------------------------------
// Builds mesh structures in the source
//-----------------------------------------------------------------------------
static void PointMeshesToVertexAndFaceData( s_source_t *pSource, int *pDesiredToSrcFace )
{
// First, assign all meshes to be empty
// A mesh is a set of faces + vertices that all use 1 material
for ( int m = 0; m < MAXSTUDIOSKINS; m++ )
{
pSource->mesh[m].numvertices = 0;
pSource->mesh[m].vertexoffset = pSource->numvertices;
pSource->mesh[m].numfaces = 0;
pSource->mesh[m].faceoffset = pSource->numfaces;
}
// find first and count of vertices per material
for ( int i = 0; i < pSource->numvertices; i++ )
{
int m = pSource->vertex[i].material;
pSource->mesh[m].numvertices++;
if (pSource->mesh[m].vertexoffset > i)
{
pSource->mesh[m].vertexoffset = i;
}
}
// find first and count of faces per material
for ( int i = 0; i < pSource->numfaces; i++ )
{
int m = g_face[ pDesiredToSrcFace[i] ].material;
pSource->mesh[m].numfaces++;
if (pSource->mesh[m].faceoffset > i)
{
pSource->mesh[m].faceoffset = i;
}
}
/*
for (k = 0; k < MAXSTUDIOSKINS; k++)
{
printf("%d : %d:%d %d:%d\n", k, psource->mesh[k].numvertices, psource->mesh[k].vertexoffset, psource->mesh[k].numfaces, psource->mesh[k].faceoffset );
}
*/
}
//-----------------------------------------------------------------------------
// Builds the face list in the mesh
//-----------------------------------------------------------------------------
static void BuildFaceList( s_source_t *pSource, int *pVListToDesired, int *pDesiredToSrcFace )
{
pSource->face = (s_face_t *)kalloc( pSource->numfaces, sizeof( s_face_t ));
for ( int m = 0; m < MAXSTUDIOSKINS; m++)
{
if ( !pSource->mesh[m].numfaces )
continue;
pSource->meshindex[ pSource->nummeshes++ ] = m;
for ( int i = pSource->mesh[m].faceoffset; i < pSource->mesh[m].numfaces + pSource->mesh[m].faceoffset; i++)
{
int j = pDesiredToSrcFace[i];
// NOTE: per-face vertex indices a,b,c are mesh relative (hence the subtraction),
// while g_src_uface are model relative
pSource->face[i].a = pVListToDesired[ g_src_uface[j].a ] - pSource->mesh[m].vertexoffset;
pSource->face[i].b = pVListToDesired[ g_src_uface[j].b ] - pSource->mesh[m].vertexoffset;
pSource->face[i].c = pVListToDesired[ g_src_uface[j].c ] - pSource->mesh[m].vertexoffset;
Assert( ((pSource->face[i].a & 0xF0000000) == 0) && ((pSource->face[i].b & 0xF0000000) == 0) &&
((pSource->face[i].c & 0xF0000000) == 0) );
// printf("%3d : %4d %4d %4d\n", i, pSource->face[i].a, pSource->face[i].b, pSource->face[i].c );
}
}
}
//-----------------------------------------------------------------------------
// Remaps the vertex animations based on the new vertex ordering
//-----------------------------------------------------------------------------
static void RemapVertexAnimations( s_source_t *pSource, int *pVListToDesired )
{
int nAnimationCount = pSource->m_Animations.Count();
for ( int i = 0; i < nAnimationCount; ++i )
{
s_sourceanim_t &anim = pSource->m_Animations[i];
if ( !anim.newStyleVertexAnimations )
continue;
for ( int j = 0; j < MAXSTUDIOANIMFRAMES; ++j )
{
int nVAnimCount = anim.numvanims[j];
if ( nVAnimCount == 0 )
continue;
// Copy off the initial vertex data
// Have to do it in 2 loops because it'll overwrite itself if we do it in 1
int *pTemp = (int*)_alloca( nVAnimCount * sizeof(int) );
for ( int k = 0; k < nVAnimCount; ++k )
{
pTemp[k] = anim.vanim[j][k].vertex;
}
for ( int k = 0; k < nVAnimCount; ++k )
{
// NOTE: vertex animations are model relative, not mesh relative
anim.vanim[j][k].vertex = pVListToDesired[ pTemp[k] ];
}
}
}
}
//-----------------------------------------------------------------------------
// Sorts vertices by material type, re-maps data structures that refer to those vertices
// to use the new indices
//-----------------------------------------------------------------------------
void BuildIndividualMeshes( s_source_t *pSource )
{
static int v_listsort[MAXSTUDIOVERTS]; // map desired order to vlist entry
static int v_ilistsort[MAXSTUDIOVERTS]; // map vlist entry to desired order
static int facesort[MAXSTUDIOTRIANGLES]; // map desired order to src_face entry
SortVerticesByMaterial( v_listsort, v_ilistsort );
SortFacesByMaterial( facesort );
pSource->numvertices = numvlist;
pSource->numfaces = g_numfaces;
BuildUniqueVertexList( pSource, v_listsort );
PointMeshesToVertexAndFaceData( pSource, facesort );
BuildFaceList( pSource, v_ilistsort, facesort );
RemapVertexAnimations( pSource, v_ilistsort );
CalcModelTangentSpaces( pSource );
}
void Grab_MRMFaceupdates( s_source_t *psource )
{
while (1)
{
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
{
g_iLinecount++;
// check for end
if (IsEnd(g_szLine))
return;
}
}
}
int Load_VRM ( s_source_t *psource )
{
char cmd[1024];
int option;
if (!OpenGlobalFile( psource->filename ))
{
return 0;
}
if( !g_quiet )
{
printf ("grabbing %s\n", psource->filename);
}
g_iLinecount = 0;
while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
{
g_iLinecount++;
sscanf( g_szLine, "%1023s %d", cmd, &option );
if (stricmp( cmd, "version" ) == 0)
{
if (option != 2)
{
MdlError("bad version\n");
}
}
else if (stricmp( cmd, "name" ) == 0)
{
}
else if (stricmp( cmd, "vertices" ) == 0)
{
g_numverts = option;
}
else if (stricmp( cmd, "faces" ) == 0)
{
g_numfaces = option;
}
else if (stricmp( cmd, "materials" ) == 0)
{
// doesn't matter;
}
else if (stricmp( cmd, "texcoords" ) == 0)
{
g_numtexcoords = option;
if (option == 0)
MdlError( "model has no texture coordinates\n");
}
else if (stricmp( cmd, "normals" ) == 0)
{
g_numnormals = option;
}
else if (stricmp( cmd, "tristrips" ) == 0)
{
// should be 0;
}
else if (stricmp( cmd, "vertexlist" ) == 0)
{
Grab_Vertexlist( psource );
}
else if (stricmp( cmd, "facelist" ) == 0)
{
Grab_Facelist( psource );
}
else if (stricmp( cmd, "materiallist" ) == 0)
{
Grab_Materiallist( psource );
}
else if (stricmp( cmd, "texcoordlist" ) == 0)
{
Grab_Texcoordlist( psource );
}
else if (stricmp( cmd, "normallist" ) == 0)
{
Grab_Normallist( psource );
}
else if (stricmp( cmd, "faceattriblist" ) == 0)
{
Grab_Faceattriblist( psource );
}
else if (stricmp( cmd, "MRM" ) == 0)
{
}
else if (stricmp( cmd, "MRMvertices" ) == 0)
{
}
else if (stricmp( cmd, "MRMfaces" ) == 0)
{
}
else if (stricmp( cmd, "MRMfaceupdates" ) == 0)
{
Grab_MRMFaceupdates( psource );
}
else if (stricmp( cmd, "nodes" ) == 0)
{
psource->numbones = Grab_Nodes( psource->localBone );
}
else if (stricmp( cmd, "skeleton" ) == 0)
{
Grab_Animation( psource, "BindPose" );
}
/*
else if (stricmp( cmd, "triangles" ) == 0) {
Grab_Triangles( psource );
}
*/
else
{
MdlError("unknown VRM command : %s \n", cmd );
}
}
UnifyIndices( psource );
BuildIndividualMeshes( psource );
fclose( g_fpInput );
return 1;
}
+432
View File
@@ -0,0 +1,432 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
//
// studiomdl.c: generates a studio .mdl file from a .qc script
// models/<scriptname>.mdl.
//
#pragma warning( disable : 4244 )
#pragma warning( disable : 4237 )
#pragma warning( disable : 4305 )
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <math.h>
#include "tier1/utlbuffer.h"
#include "cmdlib.h"
#include "scriplib.h"
#include "mathlib/mathlib.h"
#include "studio.h"
#include "tier1/characterset.h"
#include "studiomdl.h"
//#include "..\..\dlls\activity.h"
bool IsEnd( char const* pLine );
int SortAndBalanceBones( int iCount, int iMaxCount, int bones[], float weights[] );
int AddToVlist( int v, int m, int n, int t, int firstref );
void DecrementReferenceVlist( int uv, int numverts );
int faceCompare( const void *elem1, const void *elem2 );
void UnifyIndices( s_source_t *psource );
struct MtlInfo_t
{
CUtlString m_MtlName;
CUtlString m_TgaName;
};
static CUtlVector<MtlInfo_t> g_MtlLib;
void ParseMtlLib( CUtlBuffer &buf )
{
int nCurrentMtl = -1;
while ( buf.IsValid() )
{
buf.GetLine( g_szLine, sizeof(g_szLine) );
if ( !Q_strnicmp( g_szLine, "newmtl ", 7 ) )
{
char mtlName[1024];
if ( sscanf( g_szLine, "newmtl %s", mtlName ) == 1 )
{
nCurrentMtl = g_MtlLib.AddToTail( );
g_MtlLib[nCurrentMtl].m_MtlName = mtlName;
g_MtlLib[nCurrentMtl].m_TgaName = "debugempty";
}
continue;
}
if ( !Q_strnicmp( g_szLine, "map_Kd ", 7 ) )
{
if ( nCurrentMtl < 0 )
continue;
char tgaPath[MAX_PATH];
char tgaName[1024];
if ( sscanf( g_szLine, "map_Kd %s", tgaPath ) == 1 )
{
Q_FileBase( tgaPath, tgaName, sizeof(tgaName) );
g_MtlLib[nCurrentMtl].m_TgaName = tgaName;
}
continue;
}
}
}
const char *FindMtlEntry( const char *pTgaName )
{
int nCount = g_MtlLib.Count();
for ( int i = 0; i < nCount; ++i )
{
if ( !Q_stricmp( g_MtlLib[i].m_MtlName, pTgaName ) )
return g_MtlLib[i].m_TgaName;
}
return pTgaName;
}
static bool ParseVertex( CUtlBuffer& bufParse, characterset_t &breakSet, int &v, int &t, int &n )
{
char cmd[1024];
int nLen = bufParse.ParseToken( &breakSet, cmd, sizeof(cmd), false );
if ( nLen <= 0 )
return false;
v = atoi( cmd );
n = 0;
t = 0;
char c = *(char*)bufParse.PeekGet();
bool bHasTexCoord = IN_CHARACTERSET( breakSet, c ) != 0;
bool bHasNormal = false;
if ( bHasTexCoord )
{
// Snag the '/'
nLen = bufParse.ParseToken( &breakSet, cmd, sizeof(cmd), false );
Assert( nLen == 1 );
c = *(char*)bufParse.PeekGet();
if ( !IN_CHARACTERSET( breakSet, c ) )
{
nLen = bufParse.ParseToken( &breakSet, cmd, sizeof(cmd), false );
Assert( nLen > 0 );
t = atoi( cmd );
c = *(char*)bufParse.PeekGet();
bHasNormal = IN_CHARACTERSET( breakSet, c ) != 0;
}
else
{
bHasNormal = true;
bHasTexCoord = false;
}
if ( bHasNormal )
{
// Snag the '/'
nLen = bufParse.ParseToken( &breakSet, cmd, sizeof(cmd), false );
Assert( nLen == 1 );
nLen = bufParse.ParseToken( &breakSet, cmd, sizeof(cmd), false );
Assert( nLen > 0 );
n = atoi( cmd );
}
}
return true;
}
int Load_OBJ( s_source_t *psource )
{
char cmd[1024];
int i;
int material = -1;
g_MtlLib.RemoveAll();
if ( !OpenGlobalFile( psource->filename ) )
return 0;
char pFullPath[MAX_PATH];
if ( !GetGlobalFilePath( psource->filename, pFullPath, sizeof(pFullPath) ) )
return 0;
char pFullDir[MAX_PATH];
Q_ExtractFilePath( pFullPath, pFullDir, sizeof(pFullDir) );
if( !g_quiet )
{
printf( "grabbing %s\n", psource->filename );
}
g_iLinecount = 0;
psource->numbones = 1;
strcpy( psource->localBone[0].name, "default" );
psource->localBone[0].parent = -1;
Assert( psource->m_Animations.Count() == 0 );
s_sourceanim_t *pSourceAnim = FindOrAddSourceAnim( psource, "BindPose" );
pSourceAnim->numframes = 1;
pSourceAnim->startframe = 0;
pSourceAnim->endframe = 0;
pSourceAnim->rawanim[0] = (s_bone_t *)kalloc( 1, sizeof( s_bone_t ) );
pSourceAnim->rawanim[0][0].pos.Init();
pSourceAnim->rawanim[0][0].rot.Init();
Build_Reference( psource, "BindPose" );
characterset_t breakSet;
CharacterSetBuild( &breakSet, "/\\" );
while ( GetLineInput() )
{
Vector tmp;
if ( strncmp( g_szLine, "v ", 2 ) == 0 )
{
i = g_numverts++;
sscanf( g_szLine, "v %f %f %f", &g_vertex[i].x, &g_vertex[i].y, &g_vertex[i].z );
g_bone[i].numbones = 1;
g_bone[i].bone[0] = 0;
g_bone[i].weight[0] = 1.0;
continue;
}
if (strncmp( g_szLine, "vn ", 3 ) == 0)
{
i = g_numnormals++;
sscanf( g_szLine, "vn %f %f %f", &g_normal[i].x, &g_normal[i].y, &g_normal[i].z );
continue;
}
if (strncmp( g_szLine, "vt ", 3 ) == 0)
{
i = g_numtexcoords++;
sscanf( g_szLine, "vt %f %f", &g_texcoord[i].x, &g_texcoord[i].y );
g_texcoord[i].y = 1.0 - g_texcoord[i].y;
continue;
}
if ( !Q_strncmp( g_szLine, "mtllib ", 7 ) )
{
sscanf( g_szLine, "mtllib %s", &cmd[0] );
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
char pFullMtlLibPath[MAX_PATH];
Q_ComposeFileName( pFullDir, cmd, pFullMtlLibPath, sizeof(pFullMtlLibPath) );
if ( g_pFullFileSystem->ReadFile( pFullMtlLibPath, NULL, buf ) )
{
ParseMtlLib( buf );
}
continue;
}
if (strncmp( g_szLine, "usemtl ", 7 ) == 0)
{
sscanf( g_szLine, "usemtl %s", &cmd[0] );
const char *pTexture = FindMtlEntry( cmd );
int texture = LookupTexture( pTexture );
psource->texmap[texture] = texture; // hack, make it 1:1
material = UseTextureAsMaterial( texture );
continue;
}
if (strncmp( g_szLine, "f ", 2 ) == 0)
{
if ( material < 0 )
{
int texture = LookupTexture( "debugempty.tga" );
psource->texmap[texture] = texture;
material = UseTextureAsMaterial( texture );
}
int v0, n0, t0;
int v1, n1, t1;
int v2, n2, t2;
s_tmpface_t f;
// Are we specifying p only, p and t only, p and n only, or p and n and t?
char *pData = g_szLine + 2;
int nLen = Q_strlen( pData );
CUtlBuffer bufParse( pData, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
ParseVertex( bufParse, breakSet, v0, t0, n0 );
ParseVertex( bufParse, breakSet, v1, t1, n1 );
Assert( v0 <= g_numverts && t0 <= g_numtexcoords && n0 <= g_numnormals );
Assert( v1 <= g_numverts && t1 <= g_numtexcoords && n1 <= g_numnormals );
while ( bufParse.IsValid() )
{
if ( !ParseVertex( bufParse, breakSet, v2, t2, n2 ) )
break;
Assert( v2 <= g_numverts && t2 <= g_numtexcoords && n2 <= g_numnormals );
i = g_numfaces++;
f.material = material;
f.a = v0 - 1; f.na = (n0 > 0) ? n0 - 1 : 0, f.ta = (t0 > 0) ? t0 - 1 : 0;
f.b = v2 - 1; f.nb = (n2 > 0) ? n2 - 1 : 0, f.tb = (t2 > 0) ? t2 - 1 : 0;
f.c = v1 - 1; f.nc = (n1 > 0) ? n1 - 1 : 0, f.tc = (t1 > 0) ? t1 - 1 : 0;
g_face[i] = f;
v1 = v2; t1 = t2; n1 = n2;
}
continue;
}
}
UnifyIndices( psource );
BuildIndividualMeshes( psource );
fclose( g_fpInput );
return 1;
}
int AppendVTAtoOBJ( s_source_t *psource, char *filename, int frame )
{
char cmd[1024];
int i, j;
int material = 0;
Vector tmp;
matrix3x4_t m;
AngleMatrix( RadianEuler( 1.570796, 0, 0 ), m );
if ( !OpenGlobalFile( filename ) )
return 0;
if( !g_quiet )
{
printf ("grabbing %s\n", filename );
}
g_iLinecount = 0;
g_numverts = g_numnormals = g_numtexcoords = g_numfaces = 0;
while ( GetLineInput() )
{
Vector tmp;
if (strncmp( g_szLine, "v ", 2 ) == 0)
{
i = g_numverts++;
sscanf( g_szLine, "v %f %f %f", &tmp.x, &tmp.y, &tmp.z );
VectorTransform( tmp, m, g_vertex[i] );
// printf("%f %f %f\n", g_vertex[i].x, g_vertex[i].y, g_vertex[i].z );
g_bone[i].numbones = 1;
g_bone[i].bone[0] = 0;
g_bone[i].weight[0] = 1.0;
}
else if (strncmp( g_szLine, "vn ", 3 ) == 0)
{
i = g_numnormals++;
sscanf( g_szLine, "vn %f %f %f", &tmp.x, &tmp.y, &tmp.z );
VectorRotate( tmp, m, g_normal[i] );
}
else if (strncmp( g_szLine, "vt ", 3 ) == 0)
{
i = g_numtexcoords++;
sscanf( g_szLine, "vt %f %f", &g_texcoord[i].x, &g_texcoord[i].y );
}
else if (strncmp( g_szLine, "usemtl ", 7 ) == 0)
{
sscanf( g_szLine, "usemtl %s", &cmd[0] );
int texture = LookupTexture( cmd );
psource->texmap[texture] = texture; // hack, make it 1:1
material = UseTextureAsMaterial( texture );
}
else if (strncmp( g_szLine, "f ", 2 ) == 0)
{
int v0, n0, t0;
int v1, n1, t1;
int v2, n2, t2;
int v3, n3, t3;
s_tmpface_t f;
i = g_numfaces++;
j = sscanf( g_szLine, "f %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d", &v0, &t0, &n0, &v1, &t1, &n1, &v2, &t2, &n2, &v3, &t3, &n3 );
f.material = material;
f.a = v0 - 1; f.na = n0 - 1, f.ta = 0;
f.b = v2 - 1; f.nb = n2 - 1, f.tb = 0;
f.c = v1 - 1; f.nc = n1 - 1, f.tc = 0;
Assert( v0 <= g_numverts && v1 <= g_numverts && v2 <= g_numverts );
Assert( n0 <= g_numnormals && n1 <= g_numnormals && n2 <= g_numnormals );
g_face[i] = f;
if (j == 12)
{
i = g_numfaces++;
f.a = v0 - 1; f.na = n0 - 1, f.ta = 0;
f.b = v3 - 1; f.nb = n3 - 1, f.tb = 0;
f.c = v2 - 1; f.nc = n2 - 1, f.tc = 0;
g_face[i] = f;
}
}
}
UnifyIndices( psource );
s_sourceanim_t *pSourceAnim = FindOrAddSourceAnim( psource, "BindPose" );
if ( frame == 0 )
{
psource->numbones = 1;
strcpy( psource->localBone[0].name, "default" );
psource->localBone[0].parent = -1;
pSourceAnim->numframes = 1;
pSourceAnim->startframe = 0;
pSourceAnim->endframe = 0;
pSourceAnim->rawanim[0] = (s_bone_t *)kalloc( 1, sizeof( s_bone_t ) );
pSourceAnim->rawanim[0][0].pos.Init();
pSourceAnim->rawanim[0][0].rot = RadianEuler( 1.570796, 0.0, 0.0 );
Build_Reference( psource, "BindPose" );
BuildIndividualMeshes( psource );
}
// printf("%d %d : %d\n", g_numverts, g_numnormals, numvlist );
int t = frame;
int count = numvlist;
pSourceAnim->numvanims[t] = count;
pSourceAnim->vanim[t] = (s_vertanim_t *)kalloc( count, sizeof( s_vertanim_t ) );
for (i = 0; i < count; i++)
{
pSourceAnim->vanim[t][i].vertex = i;
pSourceAnim->vanim[t][i].pos = g_vertex[v_listdata[i].v];
pSourceAnim->vanim[t][i].normal = g_normal[v_listdata[i].n];
}
fclose( g_fpInput );
return 1;
}
File diff suppressed because it is too large Load Diff
+274
View File
@@ -0,0 +1,274 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
#include <stdlib.h>
#include <tier0/dbg.h>
#include "interface.h"
#include "istudiorender.h"
#include "studio.h"
#include "optimize.h"
#include "cmdlib.h"
#include "studiomdl.h"
#include "perfstats.h"
extern void MdlError( char const *pMsg, ... );
static StudioRenderConfig_t s_StudioRenderConfig;
class CStudioDataCache : public CBaseAppSystem<IStudioDataCache>
{
public:
bool VerifyHeaders( studiohdr_t *pStudioHdr );
vertexFileHeader_t *CacheVertexData( studiohdr_t *pStudioHdr );
};
static CStudioDataCache g_StudioDataCache;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CStudioDataCache, IStudioDataCache, STUDIO_DATA_CACHE_INTERFACE_VERSION, g_StudioDataCache );
/*
=================
VerifyHeaders
Minimal presence and header validation, no data loads
Return true if successful, false otherwise.
=================
*/
bool CStudioDataCache::VerifyHeaders( studiohdr_t *pStudioHdr )
{
// default valid
return true;
}
/*
=================
CacheVertexData
Cache model's specified dynamic data
=================
*/
vertexFileHeader_t *CStudioDataCache::CacheVertexData( studiohdr_t *pStudioHdr )
{
// minimal implementation - return persisted data
return (vertexFileHeader_t*)pStudioHdr->pVertexBase;
}
static void UpdateStudioRenderConfig( void )
{
memset( &s_StudioRenderConfig, 0, sizeof(s_StudioRenderConfig) );
s_StudioRenderConfig.bEyeMove = true;
s_StudioRenderConfig.fEyeShiftX = 0.0f;
s_StudioRenderConfig.fEyeShiftY = 0.0f;
s_StudioRenderConfig.fEyeShiftZ = 0.0f;
s_StudioRenderConfig.fEyeSize = 10.0f;
s_StudioRenderConfig.bSoftwareSkin = false;
s_StudioRenderConfig.bNoHardware = false;
s_StudioRenderConfig.bNoSoftware = false;
s_StudioRenderConfig.bTeeth = true;
s_StudioRenderConfig.drawEntities = true;
s_StudioRenderConfig.bFlex = true;
s_StudioRenderConfig.bEyes = true;
s_StudioRenderConfig.bWireframe = false;
s_StudioRenderConfig.bDrawNormals = false;
s_StudioRenderConfig.skin = 0;
s_StudioRenderConfig.maxDecalsPerModel = 0;
s_StudioRenderConfig.bWireframeDecals = false;
s_StudioRenderConfig.fullbright = false;
s_StudioRenderConfig.bSoftwareLighting = false;
s_StudioRenderConfig.bShowEnvCubemapOnly = false;
g_pStudioRender->UpdateConfig( s_StudioRenderConfig );
}
static SpewOutputFunc_t s_pSavedSpewFunc;
SpewRetval_t NullSpewOutputFunc( SpewType_t spewType, const tchar *pMsg )
{
switch( spewType )
{
case SPEW_WARNING:
return SPEW_CONTINUE;
case SPEW_MESSAGE:
case SPEW_ASSERT:
case SPEW_ERROR:
case SPEW_LOG:
Assert( s_pSavedSpewFunc );
if( s_pSavedSpewFunc )
{
return s_pSavedSpewFunc( spewType, pMsg );
}
break;
}
Assert( 0 );
return SPEW_CONTINUE;
}
void SpewPerfStats( studiohdr_t *pStudioHdr, const char *pFilename, unsigned int flags )
{
char fileName[260];
vertexFileHeader_t *pNewVvdHdr;
vertexFileHeader_t *pVvdHdr = 0;
OptimizedModel::FileHeader_t *pVtxHdr = 0;
studiohwdata_t studioHWData;
int vvdSize = 0;
const char *prefix[] = {".dx80.vtx", ".dx90.vtx", ".sw.vtx"};
s_pSavedSpewFunc = NULL;
if( !( flags & SPEWPERFSTATS_SHOWSTUDIORENDERWARNINGS ) )
{
s_pSavedSpewFunc = GetSpewOutputFunc();
SpewOutputFunc( NullSpewOutputFunc );
}
// no stats on these
if (!pStudioHdr->numbodyparts)
return;
// Need to update the render config to spew perf stats.
UpdateStudioRenderConfig();
// persist the vvd data
Q_StripExtension( pFilename, fileName, sizeof( fileName ) );
strcat( fileName, ".vvd" );
if (FileExists( fileName ))
{
vvdSize = LoadFile( fileName, (void**)&pVvdHdr );
}
else
{
MdlError( "Could not open '%s'\n", fileName );
}
// validate header
if (pVvdHdr->id != MODEL_VERTEX_FILE_ID)
{
MdlError( "Bad id for '%s' (got %d expected %d)\n", fileName, pVvdHdr->id, MODEL_VERTEX_FILE_ID);
}
if (pVvdHdr->version != MODEL_VERTEX_FILE_VERSION)
{
MdlError( "Bad version for '%s' (got %d expected %d)\n", fileName, pVvdHdr->version, MODEL_VERTEX_FILE_VERSION);
}
if (pVvdHdr->checksum != pStudioHdr->checksum)
{
MdlError( "Bad checksum for '%s' (got %d expected %d)\n", fileName, pVvdHdr->checksum, pStudioHdr->checksum);
}
if (pVvdHdr->numFixups)
{
// need to perform mesh relocation fixups
// allocate a new copy
pNewVvdHdr = (vertexFileHeader_t *)malloc( vvdSize );
if (!pNewVvdHdr)
{
MdlError( "Error allocating %d bytes for Vertex File '%s'\n", vvdSize, fileName );
}
Studio_LoadVertexes( pVvdHdr, pNewVvdHdr, 0, true );
// discard original
free( pVvdHdr );
pVvdHdr = pNewVvdHdr;
}
// iterate all ???.vtx files
for (int j=0; j<sizeof(prefix)/sizeof(prefix[0]); j++)
{
// make vtx filename
Q_StripExtension( pFilename, fileName, sizeof( fileName ) );
strcat( fileName, prefix[j] );
// persist the vtx data
if (FileExists(fileName))
{
LoadFile( fileName, (void**)&pVtxHdr );
}
else
{
MdlError( "Could not open '%s'\n", fileName );
}
// validate header
if (pVtxHdr->version != OPTIMIZED_MODEL_FILE_VERSION)
{
MdlError( "Bad version for '%s' (got %d expected %d)\n", fileName, pVtxHdr->version, OPTIMIZED_MODEL_FILE_VERSION );
}
if (pVtxHdr->checkSum != pStudioHdr->checksum)
{
MdlError( "Bad checksum for '%s' (got %d expected %d)\n", fileName, pVtxHdr->checkSum, pStudioHdr->checksum );
}
// studio render will request these through cache interface
pStudioHdr->pVertexBase = (void *)pVvdHdr;
pStudioHdr->pIndexBase = (void *)pVtxHdr;
g_pStudioRender->LoadModel( pStudioHdr, pVtxHdr, &studioHWData );
if( flags & SPEWPERFSTATS_SHOWPERF )
{
if( flags & SPEWPERFSTATS_SPREADSHEET )
{
printf( "%s,%s,%d,", fileName, prefix[j], studioHWData.m_NumLODs - studioHWData.m_RootLOD );
}
else
{
printf( "\n" );
printf( "Performance Stats: %s\n", fileName );
printf( "------------------\n" );
}
}
int i;
if( flags & SPEWPERFSTATS_SHOWPERF )
{
for( i = studioHWData.m_RootLOD; i < studioHWData.m_NumLODs; i++ )
{
DrawModelInfo_t drawModelInfo;
drawModelInfo.m_Skin = 0;
drawModelInfo.m_Body = 0;
drawModelInfo.m_HitboxSet = 0;
drawModelInfo.m_pClientEntity = 0;
drawModelInfo.m_pColorMeshes = 0;
drawModelInfo.m_pStudioHdr = pStudioHdr;
drawModelInfo.m_pHardwareData = &studioHWData;
CUtlBuffer statsOutput( 0, 0, CUtlBuffer::TEXT_BUFFER );
if( !( flags & SPEWPERFSTATS_SPREADSHEET ) )
{
printf( "LOD:%d\n", i );
}
drawModelInfo.m_Lod = i;
DrawModelResults_t results;
g_pStudioRender->GetPerfStats( &results, drawModelInfo, &statsOutput );
if( flags & SPEWPERFSTATS_SPREADSHEET )
{
printf( "%d,%d,%d,", results.m_ActualTriCount, results.m_NumBatches, results.m_NumMaterials );
}
else
{
printf( " actual tris:%d\n", ( int )results.m_ActualTriCount );
printf( " texture memory bytes: %d (only valid in a rendering app)\n", ( int )results.m_TextureMemoryBytes );
printf( ( char * )statsOutput.Base() );
}
}
if( flags & SPEWPERFSTATS_SPREADSHEET )
{
printf( "\n" );
}
}
g_pStudioRender->UnloadModel( &studioHWData );
free(pVtxHdr);
}
if (pVvdHdr)
free(pVvdHdr);
if( !( flags & SPEWPERFSTATS_SHOWSTUDIORENDERWARNINGS ) )
{
SpewOutputFunc( s_pSavedSpewFunc );
}
}
+25
View File
@@ -0,0 +1,25 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef PERFSTATS_H
#define PERFSTATS_H
#ifdef _WIN32
#pragma once
#endif
#include "studio.h"
#include "optimize.h"
enum
{
SPEWPERFSTATS_SHOWSTUDIORENDERWARNINGS = 1,
SPEWPERFSTATS_SHOWPERF = 2,
SPEWPERFSTATS_SPREADSHEET = 4,
};
void SpewPerfStats( studiohdr_t *pStudioHdr, const char *pFilename, unsigned int flags );
#endif // PERFSTATS_H
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+151
View File
@@ -0,0 +1,151 @@
//-----------------------------------------------------------------------------
// STUDIOMDL.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$Macro SRCDIR "..\.."
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc"
$Configuration
{
$Compiler
{
$AdditionalIncludeDirectories "$BASE,..\common,..\nvtristriplib,$SRCDIR\Game_Shared"
$PreprocessorDefinitions "$BASE;PROTECTED_THINGS_DISABLE"
}
$Linker
{
$AdditionalDependencies "$BASE winmm.lib"
}
}
$Project "Studiomdl"
{
$Folder "Source Files"
{
$File "$SRCDIR\public\bone_setup.cpp"
$File "..\common\cmdlib.cpp"
$File "collisionmodel.cpp"
$File "$SRCDIR\public\CollisionUtils.cpp"
$File "dmxsupport.cpp"
$File "$SRCDIR\public\filesystem_helpers.cpp"
$File "$SRCDIR\public\filesystem_init.cpp"
$File "..\common\FileSystem_Tools.cpp"
$File "HardwareMatrixState.cpp"
$File "HardwareVertexCache.cpp"
$File "$SRCDIR\public\interpolatortypes.cpp"
$File "$SRCDIR\public\mdlobjects\mdlobjects.cpp"
$File "$SRCDIR\public\movieobjects\movieobjects_compiletools.cpp"
$File "mrmsupport.cpp"
$File "objsupport.cpp"
$File "optimize.cpp"
$File "perfstats.cpp"
$File "..\common\physdll.cpp"
$File "..\common\scriplib.cpp"
$File "simplify.cpp"
$File "$SRCDIR\public\studio.cpp"
$File "$SRCDIR\common\studiobyteswap.cpp"
$File "studiomdl.cpp"
$File "UnifyLODs.cpp"
$File "v1support.cpp"
$File "write.cpp"
$File "checkuv.cpp"
}
$Folder "Header Files"
{
$File "..\common\cmdlib.h"
$File "collisionmodel.h"
$File "FileBuffer.h"
$File "..\common\FileSystem_Tools.h"
$File "HardwareMatrixState.h"
$File "HardwareVertexCache.h"
$File "..\NvTriStripLib\NvTriStrip.h"
$File "perfstats.h"
$File "..\common\physdll.h"
$File "..\common\scriplib.h"
$File "studiomdl.h"
$File "checkuv.h"
}
$Folder "Public Header Files"
{
$File "$SRCDIR\public\gametrace.h"
$File "$SRCDIR\public\filesystem.h"
$File "$SRCDIR\public\filesystem_helpers.h"
$File "$SRCDIR\public\cmodel.h"
$File "$SRCDIR\public\mathlib\amd3dx.h"
$File "$SRCDIR\public\basehandle.h"
$File "$SRCDIR\public\tier0\basetypes.h"
$File "$SRCDIR\public\bitvec.h"
$File "$SRCDIR\public\bone_accessor.h"
$File "$SRCDIR\public\bone_setup.h"
$File "$SRCDIR\public\bspflags.h"
$File "$SRCDIR\public\tier1\byteswap.h"
$File "$SRCDIR\public\tier1\characterset.h"
$File "$SRCDIR\public\CollisionUtils.h"
$File "$SRCDIR\public\tier0\commonmacros.h"
$File "$SRCDIR\public\mathlib\compressed_vector.h"
$File "$SRCDIR\public\const.h"
$File "$SRCDIR\public\vphysics\constraints.h"
$File "$SRCDIR\public\tier0\dbg.h"
$File "$SRCDIR\public\tier0\fasttimer.h"
$File "$SRCDIR\public\appframework\IAppSystem.h"
$File "$SRCDIR\public\tier0\icommandline.h"
$File "$SRCDIR\public\ihandleentity.h"
$File "$SRCDIR\public\materialsystem\imaterial.h"
$File "$SRCDIR\public\materialsystem\imaterialsystem.h"
$File "$SRCDIR\public\materialsystem\imaterialvar.h"
$File "$SRCDIR\public\tier1\interface.h"
$File "$SRCDIR\public\istudiorender.h"
$File "$SRCDIR\public\tier1\KeyValues.h"
$File "$SRCDIR\public\materialsystem\materialsystem_config.h"
$File "$SRCDIR\public\mathlib\mathlib.h"
$File "$SRCDIR\public\tier0\memdbgoff.h"
$File "$SRCDIR\public\tier0\memdbgon.h"
$File "$SRCDIR\public\phyfile.h"
$File "$SRCDIR\public\optimize.h"
$File "$SRCDIR\public\tier0\platform.h"
$File "$SRCDIR\public\tier0\protected_things.h"
$File "$SRCDIR\public\vstdlib\random.h"
$File "$SRCDIR\common\studiobyteswap.h"
$File "$SRCDIR\public\string_t.h"
$File "$SRCDIR\public\tier1\strtools.h"
$File "$SRCDIR\public\studio.h"
$File "$SRCDIR\public\tier3\tier3.h"
$File "$SRCDIR\public\tier1\utlbuffer.h"
$File "$SRCDIR\public\tier1\utldict.h"
$File "$SRCDIR\public\tier1\utllinkedlist.h"
$File "$SRCDIR\public\tier1\utlmemory.h"
$File "$SRCDIR\public\tier1\utlrbtree.h"
$File "$SRCDIR\public\tier1\utlsymbol.h"
$File "$SRCDIR\public\tier1\utlvector.h"
$File "$SRCDIR\public\vcollide.h"
$File "$SRCDIR\public\vcollide_parse.h"
$File "$SRCDIR\public\mathlib\vector.h"
$File "$SRCDIR\public\mathlib\vector2d.h"
$File "$SRCDIR\public\mathlib\vector4d.h"
$File "$SRCDIR\public\mathlib\vmatrix.h"
$File "$SRCDIR\public\vphysics_interface.h"
$File "$SRCDIR\public\mathlib\vplane.h"
$File "$SRCDIR\public\tier0\vprof.h"
$File "$SRCDIR\public\vstdlib\vstdlib.h"
}
$Folder "Link Libraries"
{
$Lib appframework
$Lib datamodel
$Lib dmserializers
$Lib mathlib
$Lib mdlobjects
$Lib movieobjects
$Lib nvtristrip
$Lib tier2
$Lib tier3
}
}
+350
View File
@@ -0,0 +1,350 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// tristrip - convert triangle list into tristrips and fans
#pragma warning( disable : 4244 )
#pragma warning( disable : 4237 )
#pragma warning( disable : 4305 )
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "cmdlib.h"
#include "lbmlib.h"
#include "scriplib.h"
#include "mathlib/mathlib.h"
#include "..\..\engine\studio.h"
#include "studiomdl.h"
int used[MAXSTUDIOTRIANGLES];
// the command list holds counts and s/t values that are valid for
// every frame
short commands[MAXSTUDIOTRIANGLES * 13];
int numcommands;
// all frames will have their vertexes rearranged and expanded
// so they are in the order expected by the command list
int allverts, alltris;
int stripverts[MAXSTUDIOTRIANGLES+2];
int striptris[MAXSTUDIOTRIANGLES+2];
int stripcount;
int neighbortri[MAXSTUDIOTRIANGLES][3];
int neighboredge[MAXSTUDIOTRIANGLES][3];
s_trianglevert_t (*triangles)[3];
s_mesh_t *pmesh;
void FindNeighbor (int starttri, int startv)
{
s_trianglevert_t m1, m2;
int j;
s_trianglevert_t *last, *check;
int k;
// used[starttri] |= (1 << startv);
last = &triangles[starttri][0];
m1 = last[(startv+1)%3];
m2 = last[(startv+0)%3];
for (j=starttri+1, check=&triangles[starttri+1][0] ; j<pmesh->numtris ; j++, check += 3)
{
if (used[j] == 7)
continue;
for (k=0 ; k<3 ; k++)
{
if (memcmp(&check[k],&m1,sizeof(m1)))
continue;
if (memcmp(&check[ (k+1)%3 ],&m2,sizeof(m2)))
continue;
neighbortri[starttri][startv] = j;
neighboredge[starttri][startv] = k;
neighbortri[j][k] = starttri;
neighboredge[j][k] = startv;
used[starttri] |= (1 << startv);
used[j] |= (1 << k);
return;
}
}
}
/*
================
StripLength
================
*/
int StripLength (int starttri, int startv)
{
int j;
int k;
used[starttri] = 2;
stripverts[0] = (startv)%3;
stripverts[1] = (startv+1)%3;
stripverts[2] = (startv+2)%3;
striptris[0] = starttri;
striptris[1] = starttri;
striptris[2] = starttri;
stripcount = 3;
while( 1 )
{
if (stripcount & 1)
{
j = neighbortri[starttri][(startv+1)%3];
k = neighboredge[starttri][(startv+1)%3];
}
else
{
j = neighbortri[starttri][(startv+2)%3];
k = neighboredge[starttri][(startv+2)%3];
}
if (j == -1 || used[j])
goto done;
stripverts[stripcount] = (k+2)%3;
striptris[stripcount] = j;
stripcount++;
used[j] = 2;
starttri = j;
startv = k;
}
done:
// clear the temp used flags
for (j=0 ; j<pmesh->numtris ; j++)
if (used[j] == 2)
used[j] = 0;
return stripcount;
}
/*
===========
FanLength
===========
*/
int FanLength (int starttri, int startv)
{
int j;
int k;
used[starttri] = 2;
stripverts[0] = (startv)%3;
stripverts[1] = (startv+1)%3;
stripverts[2] = (startv+2)%3;
striptris[0] = starttri;
striptris[1] = starttri;
striptris[2] = starttri;
stripcount = 3;
while( 1 )
{
j = neighbortri[starttri][(startv+2)%3];
k = neighboredge[starttri][(startv+2)%3];
if (j == -1 || used[j])
goto done;
stripverts[stripcount] = (k+2)%3;
striptris[stripcount] = j;
stripcount++;
used[j] = 2;
starttri = j;
startv = k;
}
done:
// clear the temp used flags
for (j=0 ; j<pmesh->numtris ; j++)
if (used[j] == 2)
used[j] = 0;
return stripcount;
}
/*
================
BuildTris
Generate a list of trifans or strips
for the model, which holds for all frames
================
*/
int numcommandnodes;
int BuildTris (s_trianglevert_t (*x)[3], s_mesh_t *y, byte **ppdata )
{
int i, j, k, m;
int startv;
int len, bestlen, besttype;
int bestverts[MAXSTUDIOTRIANGLES];
int besttris[MAXSTUDIOTRIANGLES];
int peak[MAXSTUDIOTRIANGLES];
int type;
int total = 0;
long t;
int maxlen;
triangles = x;
pmesh = y;
t = time( NULL );
for (i=0 ; i<pmesh->numtris ; i++)
{
neighbortri[i][0] = neighbortri[i][1] = neighbortri[i][2] = -1;
used[i] = 0;
peak[i] = pmesh->numtris;
}
// printf("finding neighbors\n");
for (i=0 ; i<pmesh->numtris; i++)
{
for (k = 0; k < 3; k++)
{
if (used[i] & (1 << k))
continue;
FindNeighbor( i, k );
}
// printf("%d", used[i] );
}
// printf("\n");
//
// build tristrips
//
numcommandnodes = 0;
numcommands = 0;
memset (used, 0, sizeof(used));
for (i=0 ; i<pmesh->numtris ;)
{
// pick an unused triangle and start the trifan
if (used[i])
{
i++;
continue;
}
maxlen = 9999;
bestlen = 0;
m = 0;
for (k = i; k < pmesh->numtris && bestlen < 127; k++)
{
int localpeak = 0;
if (used[k])
continue;
if (peak[k] <= bestlen)
continue;
m++;
for (type = 0 ; type < 2 ; type++)
{
for (startv =0 ; startv < 3 ; startv++)
{
if (type == 1)
len = FanLength (k, startv);
else
len = StripLength (k, startv);
if (len > 127)
{
// skip these, they are too long to encode
}
else if (len > bestlen)
{
besttype = type;
bestlen = len;
for (j=0 ; j<bestlen ; j++)
{
besttris[j] = striptris[j];
bestverts[j] = stripverts[j];
}
// printf("%d %d\n", k, bestlen );
}
if (len > localpeak)
localpeak = len;
}
}
peak[k] = localpeak;
if (localpeak == maxlen)
break;
}
total += (bestlen - 2);
// printf("%d (%d) %d\n", bestlen, pmesh->numtris - total, i );
maxlen = bestlen;
// mark the tris on the best strip as used
for (j=0 ; j<bestlen ; j++)
used[besttris[j]] = 1;
if (besttype == 1)
commands[numcommands++] = -bestlen;
else
commands[numcommands++] = bestlen;
for (j=0 ; j<bestlen ; j++)
{
s_trianglevert_t *tri;
tri = &triangles[besttris[j]][bestverts[j]];
commands[numcommands++] = tri->vertindex;
commands[numcommands++] = tri->normindex;
commands[numcommands++] = tri->s;
commands[numcommands++] = tri->t;
}
// printf("%d ", bestlen - 2 );
numcommandnodes++;
if (t != time(NULL))
{
printf("%2d%%\r", (total * 100) / pmesh->numtris );
t = time(NULL);
}
}
commands[numcommands++] = 0; // end of list marker
*ppdata = (byte *)commands;
// printf("%d %d %d\n", numcommandnodes, numcommands, pmesh->numtris );
return numcommands * sizeof( short );
}
+393
View File
@@ -0,0 +1,393 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
//
// studiomdl.c: generates a studio .mdl file from a .qc script
// sources/<scriptname>.mdl.
//
#pragma warning( disable : 4244 )
#pragma warning( disable : 4237 )
#pragma warning( disable : 4305 )
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <math.h>
#include "cmdlib.h"
#include "scriplib.h"
#include "mathlib/mathlib.h"
#include "studio.h"
#include "studiomdl.h"
// The current version of the SMD file being parsed
// Yes, I know this file is called 'v1support' and there's never actually
// been a v > 1 but now there is
// (actually, there was a while when we were using developing progressive mesh
// stuff in the middle of HL2 development, but most all that code has long since
// been deleted)
int g_smdVersion = 1;
int lookup_index( s_source_t *psource, int material, Vector& vertex, Vector& normal, Vector2D texcoord, int iCount, int bones[], float weights[] )
{
int i, j;
for (i = 0; i < numvlist; i++)
{
if (v_listdata[i].m == material
&& DotProduct( g_normal[i], normal ) > normal_blend
&& VectorCompare( g_vertex[i], vertex )
&& g_texcoord[i][0] == texcoord[0]
&& g_texcoord[i][1] == texcoord[1])
{
if (g_bone[i].numbones == iCount)
{
for (j = 0; j < iCount; j++)
{
if (g_bone[i].bone[j] != bones[j] || g_bone[i].weight[j] != weights[j])
break;
}
if (j == iCount)
{
v_listdata[i].lastref = numvlist;
return i;
}
}
}
}
if (i >= MAXSTUDIOVERTS) {
MdlError( "too many indices in source: \"%s\"\n", psource->filename);
}
VectorCopy( vertex, g_vertex[i] );
VectorCopy( normal, g_normal[i] );
Vector2Copy( texcoord, g_texcoord[i] );
g_bone[i].numbones = iCount;
for ( j = 0; j < iCount; j++)
{
g_bone[i].bone[j] = bones[j];
g_bone[i].weight[j] = weights[j];
}
v_listdata[i].v = i;
v_listdata[i].m = material;
v_listdata[i].n = i;
v_listdata[i].t = i;
v_listdata[i].firstref = numvlist;
v_listdata[i].lastref = numvlist;
numvlist = i + 1;
return i;
}
void ParseFaceData( s_source_t *psource, int material, s_face_t *pFace )
{
int index[3] = {};
int i, j;
Vector p;
Vector normal;
Vector2D t;
int iCount, bones[MAXSTUDIOSRCBONES];
float weights[MAXSTUDIOSRCBONES];
int bone;
for (j = 0; j < 3; j++)
{
memset( g_szLine, 0, sizeof( g_szLine ) );
if (!GetLineInput())
{
MdlError("%s: error on g_szLine %d: %s", g_szFilename, g_iLinecount, g_szLine );
}
iCount = 0;
i = sscanf( g_szLine, "%d %f %f %f %f %f %f %f %f %d %d %f %d %f %d %f %d %f",
&bone,
&p[0], &p[1], &p[2],
&normal[0], &normal[1], &normal[2],
&t[0], &t[1],
&iCount,
&bones[0], &weights[0], &bones[1], &weights[1], &bones[2], &weights[2], &bones[3], &weights[3] );
if (i < 9)
continue;
if (bone < 0 || bone >= psource->numbones)
{
MdlError("bogus bone index\n%d %s :\n%s", g_iLinecount, g_szFilename, g_szLine );
}
//Scale face pos
scale_vertex( p );
// continue parsing more bones.
// FIXME: don't we have a built in parser that'll do this?
if (iCount > 4)
{
int k;
int ctr = 0;
char *token;
for (k = 0; k < 18; k++)
{
while (g_szLine[ctr] == ' ')
{
ctr++;
}
token = strtok( &g_szLine[ctr], " " );
ctr += strlen( token ) + 1;
}
for (k = 4; k < iCount && k < MAXSTUDIOSRCBONES; k++)
{
while (g_szLine[ctr] == ' ')
{
ctr++;
}
token = strtok( &g_szLine[ctr], " " );
ctr += strlen( token ) + 1;
bones[k] = atoi(token);
token = strtok( &g_szLine[ctr], " " );
ctr += strlen( token ) + 1;
weights[k] = atof(token);
}
// printf("%d ", iCount );
//printf("\n");
//exit(1);
}
// adjust_vertex( p );
// scale_vertex( p );
// move vertex position to object space.
// VectorSubtract( p, psource->bonefixup[bone].worldorg, tmp );
// VectorTransform(tmp, psource->bonefixup[bone].im, p );
// move normal to object space.
// VectorCopy( normal, tmp );
// VectorTransform(tmp, psource->bonefixup[bone].im, normal );
// VectorNormalize( normal );
// invert v
t[1] = 1.0 - t[1];
if (i == 9 || iCount == 0)
{
iCount = 1;
bones[0] = bone;
weights[0] = 1.0;
}
else
{
iCount = SortAndBalanceBones( iCount, MAXSTUDIOBONEWEIGHTS, bones, weights );
}
index[j] = lookup_index( psource, material, p, normal, t, iCount, bones, weights );
}
// pFace->material = material; // BUG
pFace->a = index[0];
pFace->b = index[2];
pFace->c = index[1];
Assert( ((pFace->a & 0xF0000000) == 0) && ((pFace->b & 0xF0000000) == 0) &&
((pFace->c & 0xF0000000) == 0) );
}
void Grab_Triangles( s_source_t *psource )
{
int i;
Vector vmin, vmax;
vmin[0] = vmin[1] = vmin[2] = 99999;
vmax[0] = vmax[1] = vmax[2] = -99999;
g_numfaces = 0;
numvlist = 0;
//
// load the base triangles
//
int texture;
int material;
char texturename[MAX_PATH];
while (1)
{
if (!GetLineInput())
break;
// check for end
if (IsEnd( g_szLine ))
break;
// Look for extra junk that we may want to avoid...
int nLineLength = strlen( g_szLine );
if (nLineLength >= sizeof( texturename ))
{
MdlWarning("Unexpected data at line %d, (need a texture name) ignoring...\n", g_iLinecount );
continue;
}
// strip off trailing smag
V_strcpy_safe( texturename, g_szLine );
for (i = strlen( texturename ) - 1; i >= 0 && ! V_isgraph( texturename[i] ); i--)
{
}
texturename[i + 1] = '\0';
// funky texture overrides
for (i = 0; i < numrep; i++)
{
if (sourcetexture[i][0] == '\0')
{
V_strcpy_safe( texturename, defaulttexture[i] );
break;
}
if (stricmp( texturename, sourcetexture[i]) == 0)
{
V_strcpy_safe( texturename, defaulttexture[i] );
break;
}
}
if (texturename[0] == '\0')
{
// weird source problem, skip them
GetLineInput();
GetLineInput();
GetLineInput();
continue;
}
if (stricmp( texturename, "null.bmp") == 0 || stricmp( texturename, "null.tga") == 0 || stricmp( texturename, "debug/debugempty" ) == 0)
{
// skip all faces with the null texture on them.
GetLineInput();
GetLineInput();
GetLineInput();
continue;
}
texture = LookupTexture( texturename, ( g_smdVersion > 1 ) );
psource->texmap[texture] = texture; // hack, make it 1:1
material = UseTextureAsMaterial( texture );
s_face_t f;
ParseFaceData( psource, material, &f );
// remove degenerate triangles
if (f.a == f.b || f.b == f.c || f.a == f.c)
{
// printf("Degenerate triangle %d %d %d\n", f.a, f.b, f.c );
continue;
}
g_src_uface[g_numfaces] = f;
g_face[g_numfaces].material = material;
g_numfaces++;
}
BuildIndividualMeshes( psource );
}
int Load_SMD ( s_source_t *psource )
{
char cmd[1024];
int option;
// Reset smdVersion
g_smdVersion = 1;
if (!OpenGlobalFile( psource->filename ))
return 0;
if( !g_quiet )
{
printf ("SMD MODEL %s\n", psource->filename);
}
g_iLinecount = 0;
while (GetLineInput())
{
int numRead = sscanf( g_szLine, "%s %d", cmd, &option );
// Blank line
if ((numRead == EOF) || (numRead == 0))
continue;
if (stricmp( cmd, "version" ) == 0)
{
if (option < 1 || option > 2)
{
MdlError("bad version\n");
}
g_smdVersion = option;
}
else if (stricmp( cmd, "nodes" ) == 0)
{
psource->numbones = Grab_Nodes( psource->localBone );
}
else if (stricmp( cmd, "skeleton" ) == 0)
{
Grab_Animation( psource, "BindPose" );
}
else if (stricmp( cmd, "triangles" ) == 0)
{
Grab_Triangles( psource );
}
else if (stricmp( cmd, "vertexanimation" ) == 0)
{
Grab_Vertexanimation( psource, "BindPose" );
}
else if ((strncmp( cmd, "//", 2 ) == 0) || (strncmp( cmd, ";", 1 ) == 0) || (strncmp( cmd, "#", 1 ) == 0))
{
ProcessSourceComment( psource, cmd );
continue;
}
else
{
MdlWarning("unknown studio command \"%s\"\n", cmd );
}
}
fclose( g_fpInput );
return 1;
}
File diff suppressed because it is too large Load Diff