mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-10 02:39:35 +00:00
1
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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] );
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user