Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 104 additions & 54 deletions src/engine/renderer/tr_model_iqm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,28 +408,57 @@ static bool LoadIQMFile( const void *buffer, unsigned filesize, const char *mod_
return true;
}

static size_t SanitizeFloatVertexArray( iqmHeader_t *header, iqmVertexArray_t *vertexarray,
const char *array_name, const char *mod_name )
{
float *input = ( float* ) IQMPtr( header, vertexarray->offset );

size_t nanCount = 0;

for ( unsigned int i = 0; i < header->num_vertexes; i++, input += vertexarray->size )
{
for ( unsigned int j = 0; j < vertexarray->size; j++ )
{
if ( !Math::IsFinite ( input[ j ] ) )
{
Log::Debug( "IQM model “%s” has NaN in %s[%d][%d].", mod_name, array_name, i, j );
input[ j ] = 0.0f;
nanCount++;
}
}
}

return nanCount;
}

template<typename T>
static void CopyVertexArray( iqmHeader_t *header, iqmVertexArray_t *vertexarray, T* dest )
{
unsigned int n = header->num_vertexes * vertexarray->size;
memcpy( dest, IQMPtr( header, vertexarray->offset ), static_cast<size_t>(n) * sizeof( T ) );
}

/*
=================
BuildTangents

Compute Tangent and Bitangent vectors from the IQM 4-float input data
=================
*/
void BuildTangents( int n, float *input, float *normals, float *tangents,
float *bitangents )
static void BuildTangents( iqmHeader_t *header, iqmVertexArray_t *vertexarray,
float *normals, float *tangents, float *bitangents )
{
int i;
vec3_t crossProd;
float *input = (float*)IQMPtr( header, vertexarray->offset );

for( i = 0; i < n; i++ ) {
for ( unsigned int i = 0; i < header->num_vertexes; i++, input += 4,
normals += 3, tangents += 3, bitangents += 3 )
{
VectorCopy( input, tangents );
CrossProduct( normals, input, crossProd );
VectorScale( crossProd, input[ 3 ], bitangents );
float sign = input[ 3 ];

input += 4;
normals += 3;
tangents += 3;
bitangents += 3;
vec3_t crossProd;
CrossProduct( normals, tangents, crossProd );
Comment thread
slipher marked this conversation as resolved.
VectorScale( crossProd, sign, bitangents );
}
}

Expand Down Expand Up @@ -625,6 +654,8 @@ bool R_LoadIQModel( model_t *mod, const void *buffer, int filesize,
IQModel->jointParents[i] = joint->parent;
}

size_t nanCount = 0;

// calculate pose transforms
framedata = ( short unsigned int* )IQMPtr( header, header->ofs_frames );
trans = poses;
Expand All @@ -635,6 +666,23 @@ bool R_LoadIQModel( model_t *mod, const void *buffer, int filesize,
quat_t rotate;
vec3_t scale;

for ( size_t k = 0; k < 10; k++ )
{
if ( !Math::IsFinite ( pose->channeloffset[ k ] ) )
{
Log::Debug( "IQM model “%s” frame %d has NaN in pose[%d]->channeloffset[%d].", mod_name, i, j, k );
pose->channeloffset[ k ] = 0.0f;
nanCount++;
}

if ( !Math::IsFinite ( pose->channelscale[ k ] ) )
{
Log::Debug( "IQM model “%s” frame %d has NaN in pose[%d]->channelscale[%d].", mod_name, i, j, k );
pose->channelscale[ k ] = 0.0f;
nanCount++;
}
}

translate[0] = pose->channeloffset[0];
if( pose->mask & 0x001)
translate[0] += *framedata++ * pose->channelscale[0];
Expand Down Expand Up @@ -685,72 +733,74 @@ bool R_LoadIQModel( model_t *mod, const void *buffer, int filesize,
// copy vertexarrays and indexes
vertexarray = static_cast<iqmVertexArray_t*>( IQMPtr( header, header->ofs_vertexarrays ) );
for(unsigned i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) {
int n;

// total number of values
n = header->num_vertexes * vertexarray->size;

switch( vertexarray->type ) {
case IQM_POSITION:
ClearBounds( IQModel->bounds[ 0 ], IQModel->bounds[ 1 ] );
memcpy( IQModel->positions,
IQMPtr( header, vertexarray->offset ),
n * sizeof(float) );
for( int j = 0; j < n; j += vertexarray->size ) {
AddPointToBounds( &IQModel->positions[ j ],
IQModel->bounds[ 0 ],
IQModel->bounds[ 1 ] );
}
IQModel->internalScale = BoundsMaxExtent( IQModel->bounds[ 0 ], IQModel->bounds[ 1 ] );
if( IQModel->internalScale > 0.0f ) {
float inverseScale = 1.0f / IQModel->internalScale;
for( int j = 0; j < n; j += vertexarray->size ) {
VectorScale( &IQModel->positions[ j ],
inverseScale,
&IQModel->positions[ j ] );

nanCount += SanitizeFloatVertexArray( header, vertexarray, "position", mod_name );
CopyVertexArray( header, vertexarray, IQModel->positions );

{
unsigned int n = header->num_vertexes * vertexarray->size;

for ( unsigned int j = 0; j < n; j += vertexarray->size )
{
AddPointToBounds( &IQModel->positions[ j ], IQModel->bounds[ 0 ], IQModel->bounds[ 1 ] );
}

IQModel->internalScale = BoundsMaxExtent( IQModel->bounds[ 0 ], IQModel->bounds[ 1 ] );

if ( IQModel->internalScale > 0.0f )
{
float inverseScale = 1.0f / IQModel->internalScale;

for ( unsigned int j = 0; j < n; j += vertexarray->size )
{
VectorScale( &IQModel->positions[ j ], inverseScale, &IQModel->positions[ j ] );
}
}
}

break;
case IQM_NORMAL:
memcpy( IQModel->normals,
IQMPtr( header, vertexarray->offset ),
n * sizeof(float) );
nanCount += SanitizeFloatVertexArray( header, vertexarray, "normal", mod_name );
CopyVertexArray( header, vertexarray, IQModel->normals );
break;
case IQM_TANGENT:
BuildTangents( header->num_vertexes,
( float* )IQMPtr( header, vertexarray->offset ),
IQModel->normals, IQModel->tangents,
IQModel->bitangents );
nanCount += SanitizeFloatVertexArray( header, vertexarray, "tangents", mod_name );
BuildTangents( header, vertexarray, IQModel->normals, IQModel->tangents, IQModel->bitangents );
break;
case IQM_TEXCOORD:
for( int j = 0; j < n; j++ ) {
IQModel->texcoords[ j ] = ((float *)IQMPtr( header, vertexarray->offset ))[ j ];
}
nanCount += SanitizeFloatVertexArray( header, vertexarray, "texcoord", mod_name );
CopyVertexArray( header, vertexarray, IQModel->texcoords );
break;
case IQM_BLENDINDEXES:
memcpy( IQModel->blendIndexes,
IQMPtr( header, vertexarray->offset ),
n * sizeof(byte) );
CopyVertexArray( header, vertexarray, IQModel->blendIndexes );
break;
case IQM_BLENDWEIGHTS:
// blendWeights[*][0] is always rewritten later.
CopyVertexArray( header, vertexarray, IQModel->blendWeights );
Comment thread
illwieckz marked this conversation as resolved.
weights = static_cast<u8vec4_t *>( IQMPtr( header, vertexarray->offset ) );
for(unsigned j = 0; j < header->num_vertexes; j++ ) {
IQModel->blendWeights[ 4 * j + 0 ] = 255 - weights[ j ][ 1 ] - weights[ j ][ 2 ] - weights[ j ][ 3 ];
IQModel->blendWeights[ 4 * j + 1 ] = weights[ j ][ 1 ];
IQModel->blendWeights[ 4 * j + 2 ] = weights[ j ][ 2 ];
IQModel->blendWeights[ 4 * j + 3 ] = weights[ j ][ 3 ];
}
break;
case IQM_COLOR:
memcpy( IQModel->colors,
IQMPtr( header, vertexarray->offset ),
n * sizeof(byte) );
CopyVertexArray( header, vertexarray, IQModel->colors );
break;
}
}

if ( !weights )
if ( nanCount )
{
Log::Warn( "IQM Model “%s” contains %d NaN.", mod_name, nanCount );
}

if ( weights )
{
for ( unsigned j = 0; j < header->num_vertexes; j++ )
{
IQModel->blendWeights[ 4 * j + 0 ] = 255 - weights[ j ][ 1 ] - weights[ j ][ 2 ] - weights[ j ][ 3 ];
}
}
else
{
for ( unsigned j = 0; j < header->num_vertexes; j++ )
{
Expand Down