1076 lines
30 KiB
C
1076 lines
30 KiB
C
|
/*
|
||
|
===========================================================================
|
||
|
Copyright (C) 2006 Hermitworks Entertainment Corp
|
||
|
|
||
|
This file is part of Space Trader source code.
|
||
|
|
||
|
Space Trader source code is free software; you can redistribute it
|
||
|
and/or modify it under the terms of the GNU General Public License as
|
||
|
published by the Free Software Foundation; either version 2 of the License,
|
||
|
or (at your option) any later version.
|
||
|
|
||
|
Space Trader source code is distributed in the hope that it will be
|
||
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with Space Trader source code; if not, write to the Free Software
|
||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
===========================================================================
|
||
|
*/
|
||
|
|
||
|
#include "tr_local.h"
|
||
|
#include "tr_x42-local.h"
|
||
|
|
||
|
ID_INLINE void* HunkAllocAligned( size_t cb, size_t a )
|
||
|
{
|
||
|
return AlignP( ri.Hunk_Alloc( cb + a, h_low ), a );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Persist flags (both for loading and saving):
|
||
|
|
||
|
bits 0-8 = section persist flags
|
||
|
*/
|
||
|
#define X42_PERSIST_NORMALS 0x00000001 //load or save a file with normals
|
||
|
#define X42_PERSIST_TANGENT_BASIS 0x00000002 //load or save a file with the tangent basis
|
||
|
#define X42_PERSIST_TEXTURE_COORDINATES 0x00000004 //load or save a file with the texture coordinates
|
||
|
#define X42_PERSIST_COLORS 0x00000008
|
||
|
|
||
|
#define X42_PERSIST_EVERYTHING 0x000000FF //load or save all file sections
|
||
|
|
||
|
#define const_cond_false (""[0])
|
||
|
|
||
|
static void fixup_persist_flags( uint *pf, const x42header_t *h )
|
||
|
{
|
||
|
if( !(h->modelFlags & X42_MF_HAS_NORMALS) )
|
||
|
*pf &= ~X42_PERSIST_NORMALS;
|
||
|
if( !(h->modelFlags & X42_MF_HAS_TANGENT_BASIS) )
|
||
|
*pf &= ~X42_PERSIST_TANGENT_BASIS;
|
||
|
if( !(h->modelFlags &X42_MF_HAS_TEXTURE_COORDINATES) )
|
||
|
*pf &= ~X42_PERSIST_TEXTURE_COORDINATES;
|
||
|
if( !(h->modelFlags & X42_MF_HAS_COLORS) )
|
||
|
*pf &= ~X42_PERSIST_COLORS;
|
||
|
}
|
||
|
|
||
|
static void x42_SetupBufferPointers( x42data_t *ret, const x42header_t *h, uint persist_flags )
|
||
|
{
|
||
|
fixup_persist_flags( &persist_flags, h );
|
||
|
|
||
|
#define advance_out( a, cb ) HunkAllocAligned( cb, a )
|
||
|
|
||
|
memcpy( &ret->header, h, sizeof( x42header_t ) );
|
||
|
|
||
|
ret->keyStream = (x42keyStreamEntry_t*)advance_out( sizeof( void* ), sizeof( x42keyStreamEntry_t )*h->keyStreamLength );
|
||
|
ret->animations = (x42animation_t*) advance_out( sizeof( void* ), sizeof( x42animation_t ) * h->numAnims );
|
||
|
|
||
|
ret->posValues = (vec3_t*) advance_out( sizeof( float ), sizeof( vec3_t ) * h->numPosValues );
|
||
|
ret->scaleValues = (vec3_t*) advance_out( sizeof( float ), sizeof( vec3_t ) * h->numScaleValues );
|
||
|
ret->rotValues = (quat_t*) advance_out( sizeof( float ), sizeof( quat_t ) * h->numRotValues );
|
||
|
|
||
|
ret->animGroups = (x42animGroup_t*) advance_out( sizeof( void* ), sizeof( x42animGroup_t ) * h->numAnimGroups );
|
||
|
ret->bones = (x42bone_t*) advance_out( sizeof( void* ), sizeof( x42bone_t ) * h->numBones );
|
||
|
ret->boneGroups = (u8*) advance_out( sizeof( void* ), sizeof( u8 ) * h->numBones );
|
||
|
|
||
|
ret->influences = (x42influence_t*) advance_out( sizeof( void* ), sizeof( x42influence_t ) * h->numInfluences );
|
||
|
ret->tags = (x42tag_t*) advance_out( sizeof( void* ), sizeof( x42tag_t ) * h->numTags );
|
||
|
|
||
|
ret->lods = (x42lodRange_t*) advance_out( sizeof( void* ), sizeof( x42lodRange_t ) * h->numLods );
|
||
|
ret->groups = (x42group_t*) advance_out( sizeof( void* ), sizeof( x42group_t ) * h->numGroups );
|
||
|
|
||
|
ret->vertPos = (x42vertAnim_t*) advance_out( sizeof( float[4] ),sizeof( x42vertAnim_t ) * h->numVerts );
|
||
|
|
||
|
if( persist_flags & X42_PERSIST_NORMALS )
|
||
|
ret->vertNorm = (x42vertNormal_t*) advance_out( sizeof( float[4] ),sizeof( x42vertNormal_t ) * h->numVerts );
|
||
|
else
|
||
|
ret->vertNorm = NULL;
|
||
|
|
||
|
if( persist_flags & X42_PERSIST_TANGENT_BASIS )
|
||
|
ret->vertTan = (x42vertTangent_t*) advance_out( sizeof( float[4] ),sizeof( x42vertTangent_t ) * h->numVerts );
|
||
|
else
|
||
|
ret->vertTan = NULL;
|
||
|
|
||
|
if( persist_flags & X42_PERSIST_TEXTURE_COORDINATES )
|
||
|
ret->vertTc = (vec2_t*) advance_out( sizeof( float ), sizeof( vec2_t ) * h->numVerts );
|
||
|
else
|
||
|
ret->vertTc = NULL;
|
||
|
|
||
|
if( persist_flags & X42_PERSIST_COLORS )
|
||
|
ret->vertCl = (rgba_t*) advance_out( sizeof( rgba_t ), sizeof( rgba_t ) * h->numVerts );
|
||
|
else
|
||
|
ret->vertCl = NULL;
|
||
|
|
||
|
ret->indices = (x42index_t*) advance_out( sizeof( x42index_t ), sizeof( x42index_t ) * h->numIndices );
|
||
|
|
||
|
ret->strings = (char*) advance_out( sizeof( char ), sizeof( char ) * h->nameBlobLen );
|
||
|
}
|
||
|
|
||
|
static bool read_packed_floats( const byte **filebuf, size_t filesize,
|
||
|
size_t *inPos, const vec2_t *bounds, uint components, float *dest,
|
||
|
uint elements, size_t elemStride )
|
||
|
{
|
||
|
uint i;
|
||
|
float scale[4], bias[4];
|
||
|
size_t cbElem;
|
||
|
|
||
|
if( !elements )
|
||
|
return true;
|
||
|
|
||
|
for( i = 0; i < components; i++ )
|
||
|
{
|
||
|
bias[i] = bounds[i][0];
|
||
|
scale[i] = (bounds[i][1] - bounds[i][0]) / 65530.0F;
|
||
|
}
|
||
|
|
||
|
cbElem = sizeof( u16 ) * components;
|
||
|
|
||
|
if( *inPos + cbElem * elements > filesize )
|
||
|
return false;
|
||
|
|
||
|
for( i = 0; i < elements; i++ )
|
||
|
{
|
||
|
uint c;
|
||
|
const u16 *buf = (const u16*)*filebuf;
|
||
|
*filebuf += cbElem;
|
||
|
|
||
|
for( c = 0; c < components; c++ )
|
||
|
dest[c] = buf[c] * scale[c] + bias[c];
|
||
|
|
||
|
dest = (float*)((byte*)dest + elemStride);
|
||
|
}
|
||
|
|
||
|
*inPos += cbElem * elements;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static bool read_packed_floats_s16n( const byte **filebuf, size_t filesize,
|
||
|
size_t *inPos, uint components, float *dest, uint elements, size_t elemStride )
|
||
|
{
|
||
|
uint i;
|
||
|
size_t cbElem;
|
||
|
|
||
|
if( !elements )
|
||
|
return true;
|
||
|
|
||
|
cbElem = sizeof( s16 ) * components;
|
||
|
|
||
|
if( *inPos + cbElem * elements > filesize )
|
||
|
return false;
|
||
|
|
||
|
for( i = 0; i < elements; i++ )
|
||
|
{
|
||
|
uint c;
|
||
|
|
||
|
const s16 *buf = (const s16*)*filebuf;
|
||
|
*filebuf += cbElem;
|
||
|
|
||
|
for( c = 0; c < components; c++ )
|
||
|
dest[c] = X42_FLOAT_S16N_UNPACK( buf[c] );
|
||
|
|
||
|
dest = (float*)((byte*)dest + elemStride);
|
||
|
}
|
||
|
|
||
|
*inPos += cbElem * elements;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static bool read_packed_floats_s8n( const byte **filebuf, size_t filesize,
|
||
|
size_t *inPos, uint components, float *dest, uint elements, size_t elemStride )
|
||
|
{
|
||
|
uint i;
|
||
|
size_t cbElem;
|
||
|
|
||
|
if( !elements )
|
||
|
return true;
|
||
|
|
||
|
cbElem = sizeof( s8 ) * components;
|
||
|
|
||
|
if( *inPos + cbElem * elements > filesize )
|
||
|
return false;
|
||
|
|
||
|
for( i = 0; i < elements; i++ )
|
||
|
{
|
||
|
uint c;
|
||
|
|
||
|
const s8 *buf = (const s8*)*filebuf;
|
||
|
*filebuf += cbElem;
|
||
|
|
||
|
for( c = 0; c < components; c++ )
|
||
|
dest[c] = X42_FLOAT_S8N_UNPACK( buf[c] );
|
||
|
|
||
|
dest = (float*)((byte*)dest + elemStride);
|
||
|
}
|
||
|
|
||
|
*inPos += cbElem * elements;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static bool R_LoadX42Direct( model_t *mod, const void *buffer, size_t header_size, size_t filesize, const char *name, const x42header_t *h )
|
||
|
{
|
||
|
uint i;
|
||
|
|
||
|
bool stat;
|
||
|
x42PackHeader_v5_t pack;
|
||
|
|
||
|
size_t inPos;
|
||
|
const byte *inBuf;
|
||
|
|
||
|
x42data_t *ret;
|
||
|
|
||
|
const uint persist_flags = X42_PERSIST_EVERYTHING;
|
||
|
|
||
|
ret = (x42data_t*)ri.Hunk_Alloc( sizeof( x42data_t ), h_low );
|
||
|
x42_SetupBufferPointers( ret, h, persist_flags );
|
||
|
|
||
|
inPos = sizeof( x42Header_ident_t );
|
||
|
switch( h->ident.version )
|
||
|
{
|
||
|
case X42_VER_V5:
|
||
|
inPos += sizeof( x42Header_v5_t );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ri.Printf( PRINT_ERROR, "Invalid x42 file version in model '%s'\n", name );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
inBuf = (const byte*)buffer + inPos;
|
||
|
|
||
|
#define read_check() if( !stat ) return false; else (void)0
|
||
|
|
||
|
#define checked_read( buf, size ) \
|
||
|
if( !const_cond_false ) \
|
||
|
{ \
|
||
|
size_t cb = (size); \
|
||
|
\
|
||
|
stat = inPos + cb <= filesize; \
|
||
|
read_check(); \
|
||
|
\
|
||
|
Com_Memcpy( buf, inBuf, cb ); \
|
||
|
inBuf += cb; \
|
||
|
\
|
||
|
inPos += cb; \
|
||
|
} \
|
||
|
else \
|
||
|
(void)0
|
||
|
|
||
|
#define checked_align( a ) \
|
||
|
if( !const_cond_false ) \
|
||
|
{ \
|
||
|
size_t _a = (a); \
|
||
|
\
|
||
|
if( _a ) \
|
||
|
{ \
|
||
|
size_t ofs = ((_a - (inPos % _a)) % _a); \
|
||
|
\
|
||
|
stat = inPos + ofs <= filesize; \
|
||
|
read_check(); \
|
||
|
\
|
||
|
inBuf += ofs; \
|
||
|
inPos += ofs; \
|
||
|
} \
|
||
|
} \
|
||
|
else \
|
||
|
(void)0
|
||
|
|
||
|
#define checked_read_a( buf, size, a ) \
|
||
|
if( !const_cond_false ) \
|
||
|
{ \
|
||
|
checked_align( a ); \
|
||
|
checked_read( buf, size ); \
|
||
|
} \
|
||
|
else \
|
||
|
(void)0
|
||
|
|
||
|
#define checked_skip( size, a ) \
|
||
|
if( !const_cond_false ) \
|
||
|
{ \
|
||
|
size_t cb = (size); \
|
||
|
\
|
||
|
checked_align( a ); \
|
||
|
stat = inPos + cb <= filesize; \
|
||
|
read_check(); \
|
||
|
\
|
||
|
inBuf += cb; \
|
||
|
inPos += cb; \
|
||
|
} \
|
||
|
else \
|
||
|
(void)0
|
||
|
|
||
|
checked_read( &pack, sizeof( pack ) );
|
||
|
|
||
|
checked_read_a( ret->bones, sizeof( x42Bone_v5_t ) * h->numBones, 8 );
|
||
|
checked_read_a( ret->animGroups, sizeof( x42AnimGroup_v5_t ) * h->numAnimGroups, 8 );
|
||
|
|
||
|
for( i = 0; i < h->numAnimGroups; i++ )
|
||
|
{
|
||
|
uint j;
|
||
|
for( j = ret->animGroups[i].beginBone; j < ret->animGroups[i].endBone; j++ )
|
||
|
ret->boneGroups[j] = (u8)i;
|
||
|
}
|
||
|
|
||
|
checked_align( 2 );
|
||
|
stat = read_packed_floats( &inBuf, filesize, &inPos, pack.animPosPack, 3,
|
||
|
(float*)ret->posValues, h->numPosValues, sizeof( vec3_t ) );
|
||
|
read_check();
|
||
|
|
||
|
if( h->modelFlags & X42_MF_UNIFORM_SCALE )
|
||
|
{
|
||
|
stat = read_packed_floats( &inBuf, filesize, &inPos, &pack.animScalePack, 1,
|
||
|
(float*)ret->scaleValues, h->numScaleValues, sizeof( vec3_t ) );
|
||
|
read_check();
|
||
|
|
||
|
for( i = 0; i < h->numScaleValues; i++ )
|
||
|
{
|
||
|
ret->scaleValues[i][1] = ret->scaleValues[i][0];
|
||
|
ret->scaleValues[i][2] = ret->scaleValues[i][0];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
vec2_t bdxyz[3];
|
||
|
|
||
|
bdxyz[0][0] = bdxyz[1][0] = bdxyz[2][0] = pack.animScalePack[0];
|
||
|
bdxyz[0][1] = bdxyz[1][1] = bdxyz[2][1] = pack.animScalePack[1];
|
||
|
|
||
|
stat = read_packed_floats( &inBuf, filesize, &inPos, bdxyz, 3,
|
||
|
(float*)ret->scaleValues, h->numScaleValues, sizeof( vec3_t ) );
|
||
|
read_check();
|
||
|
}
|
||
|
|
||
|
stat = read_packed_floats_s16n( &inBuf, filesize, &inPos, 4,
|
||
|
(float*)ret->rotValues, h->numRotValues, sizeof( quat_t ) );
|
||
|
read_check();
|
||
|
|
||
|
checked_read_a( ret->keyStream, sizeof( x42KeyStreamEntry_v5_t ) * h->keyStreamLength, 8 );
|
||
|
checked_read_a( ret->animations, sizeof( x42Animation_v5_t ) * h->numAnims, 8 );
|
||
|
checked_read_a( ret->tags, sizeof( x42Tag_v5_t ) * h->numTags, 8 );
|
||
|
checked_read_a( ret->influences, sizeof( x42influence_t ) * h->numInfluences, 8 );
|
||
|
checked_read_a( ret->lods, sizeof( x42LodRange_v5_t ) * h->numLods, 8 );
|
||
|
checked_read_a( ret->groups, sizeof( x42Group_v5_t ) * h->numGroups, 8 );
|
||
|
|
||
|
checked_align( 2 );
|
||
|
stat = read_packed_floats( &inBuf, filesize, &inPos, pack.vertPosPack, 3,
|
||
|
(float*)&ret->vertPos[0].pos, h->numVerts, sizeof( x42vertAnim_t ) );
|
||
|
read_check();
|
||
|
|
||
|
for( i = 0; i < h->numGroups; i++ )
|
||
|
{
|
||
|
uint j;
|
||
|
|
||
|
const x42group_t *g = ret->groups + i;
|
||
|
size_t cbElem;
|
||
|
|
||
|
if( !g->maxVertInfluences )
|
||
|
continue;
|
||
|
|
||
|
cbElem = sizeof( byte ) * ((g->maxVertInfluences - 1) * 2 + 1);
|
||
|
|
||
|
for( j = 0; j < g->numVerts; j++ )
|
||
|
{
|
||
|
uint k;
|
||
|
u8 in[7];
|
||
|
float sum;
|
||
|
|
||
|
x42vertAnim_t *v;
|
||
|
|
||
|
checked_read( in, cbElem );
|
||
|
|
||
|
v = ret->vertPos + g->firstVert + j;
|
||
|
|
||
|
sum = 0;
|
||
|
for( k = 0; k < g->maxVertInfluences - 1U; k++ )
|
||
|
{
|
||
|
v->idx[k] = in[k * 2 + 0];
|
||
|
v->wt[k] = X42_FLOAT_U8N_UNPACK( in[k * 2 + 1] );
|
||
|
|
||
|
sum += v->wt[k];
|
||
|
}
|
||
|
|
||
|
v->idx[k] = in[k * 2 + 0];
|
||
|
v->wt[k] = 1.0F - sum;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( ret->vertNorm )
|
||
|
{
|
||
|
stat = read_packed_floats_s8n( &inBuf, filesize, &inPos, 3,
|
||
|
(float*)&ret->vertNorm[0].norm, h->numVerts, sizeof( x42vertNormal_t ) );
|
||
|
read_check();
|
||
|
}
|
||
|
else if( h->modelFlags & X42_MF_HAS_NORMALS )
|
||
|
checked_skip( sizeof( s8[3] ) * h->numVerts, 0 );
|
||
|
|
||
|
if( ret->vertTan )
|
||
|
{
|
||
|
stat = read_packed_floats_s8n( &inBuf, filesize, &inPos, 7,
|
||
|
(float*)&ret->vertTan[0].tan, h->numVerts, sizeof( x42vertTangent_t ) );
|
||
|
read_check();
|
||
|
|
||
|
for( i = 0; i < h->numVerts; i++ )
|
||
|
ret->vertTan[i].nfac1 = ret->vertTan[i].nfac0;
|
||
|
}
|
||
|
else if( h->modelFlags & X42_MF_HAS_TANGENT_BASIS )
|
||
|
checked_skip( sizeof( s8[7] ) * h->numVerts, 0 );
|
||
|
|
||
|
if( ret->vertTc )
|
||
|
{
|
||
|
checked_align( 2 );
|
||
|
stat = read_packed_floats( &inBuf, filesize, &inPos, pack.vertTcPack, 2,
|
||
|
(float*)ret->vertTc, h->numVerts, sizeof( vec2_t ) );
|
||
|
read_check();
|
||
|
}
|
||
|
else if( h->modelFlags & X42_MF_HAS_TEXTURE_COORDINATES )
|
||
|
checked_skip( sizeof( u16[2] ) * h->numVerts, 2 );
|
||
|
|
||
|
if( ret->vertCl )
|
||
|
{
|
||
|
checked_read_a( ret->vertCl, sizeof( rgba_t ) * h->numVerts, 4 );
|
||
|
}
|
||
|
else if( h->modelFlags & X42_MF_HAS_COLORS )
|
||
|
checked_skip( sizeof( rgba_t ) * h->numVerts, 4 );
|
||
|
|
||
|
checked_read_a( ret->indices, sizeof( x42index_t ) * h->numIndices, 4 );
|
||
|
|
||
|
checked_read( (char*)ret->strings, sizeof( u8 ) * h->nameBlobLen );
|
||
|
|
||
|
#undef checked_skip
|
||
|
#undef checked_read_a
|
||
|
#undef checked_read
|
||
|
#undef checked_align
|
||
|
#undef read_check
|
||
|
|
||
|
mod->type = MOD_X42;
|
||
|
mod->x42 = ret;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static bool read_packed_floats_swp( const byte **filebuf, size_t filesize,
|
||
|
size_t *inPos, const vec2_t *bounds, uint components, float *dest,
|
||
|
uint elements, size_t elemStride )
|
||
|
{
|
||
|
uint i;
|
||
|
float scale[4], bias[4];
|
||
|
size_t cbElem;
|
||
|
|
||
|
if( !elements )
|
||
|
return true;
|
||
|
|
||
|
for( i = 0; i < components; i++ )
|
||
|
{
|
||
|
bias[i] = bounds[i][0];
|
||
|
scale[i] = (bounds[i][1] - bounds[i][0]) / 65530.0F;
|
||
|
}
|
||
|
|
||
|
cbElem = sizeof( u16 ) * components;
|
||
|
|
||
|
if( *inPos + cbElem * elements > filesize )
|
||
|
return false;
|
||
|
|
||
|
for( i = 0; i < elements; i++ )
|
||
|
{
|
||
|
uint c;
|
||
|
const u16 *buf = (const u16*)*filebuf;
|
||
|
*filebuf += cbElem;
|
||
|
|
||
|
for( c = 0; c < components; c++ )
|
||
|
dest[c] = Swap2u( buf[c] ) * scale[c] + bias[c];
|
||
|
|
||
|
dest = (float*)((byte*)dest + elemStride);
|
||
|
}
|
||
|
|
||
|
*inPos += cbElem * elements;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static bool read_packed_floats_s16n_swp( const byte **filebuf, size_t filesize,
|
||
|
size_t *inPos, uint components, float *dest, uint elements, size_t elemStride )
|
||
|
{
|
||
|
uint i;
|
||
|
size_t cbElem;
|
||
|
|
||
|
if( !elements )
|
||
|
return true;
|
||
|
|
||
|
cbElem = sizeof( s16 ) * components;
|
||
|
|
||
|
if( *inPos + cbElem * elements > filesize )
|
||
|
return false;
|
||
|
|
||
|
for( i = 0; i < elements; i++ )
|
||
|
{
|
||
|
uint c;
|
||
|
|
||
|
const s16 *buf = (const s16*)*filebuf;
|
||
|
*filebuf += cbElem;
|
||
|
|
||
|
for( c = 0; c < components; c++ )
|
||
|
dest[c] = X42_FLOAT_S16N_UNPACK( Swap2s( buf[c] ) );
|
||
|
|
||
|
dest = (float*)((byte*)dest + elemStride);
|
||
|
}
|
||
|
|
||
|
*inPos += cbElem * elements;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
#define read_packed_floats_s8n_swp read_packed_floats_s8n
|
||
|
|
||
|
#define swap_u8( u ) (void)sizeof( u )
|
||
|
#define swap_rgba_t( cl ) (void)sizeof( cl )
|
||
|
|
||
|
#define swap_x42Index_t( idx ) *(idx) = Swap2u( *(idx) )
|
||
|
|
||
|
static void swap_x42PackHeader_v5_t( x42PackHeader_v5_t *pack )
|
||
|
{
|
||
|
pack->animPosPack[0][0] = SwapF( pack->animPosPack[0][0] );
|
||
|
pack->animPosPack[0][1] = SwapF( pack->animPosPack[0][1] );
|
||
|
pack->animPosPack[1][0] = SwapF( pack->animPosPack[1][0] );
|
||
|
pack->animPosPack[1][1] = SwapF( pack->animPosPack[1][1] );
|
||
|
pack->animPosPack[2][0] = SwapF( pack->animPosPack[2][0] );
|
||
|
pack->animPosPack[2][1] = SwapF( pack->animPosPack[2][1] );
|
||
|
|
||
|
pack->animScalePack[0] = SwapF( pack->animScalePack[0] );
|
||
|
pack->animScalePack[1] = SwapF( pack->animScalePack[1] );
|
||
|
|
||
|
pack->vertPosPack[0][0] = SwapF( pack->vertPosPack[0][0] );
|
||
|
pack->vertPosPack[0][1] = SwapF( pack->vertPosPack[0][1] );
|
||
|
pack->vertPosPack[1][0] = SwapF( pack->vertPosPack[1][0] );
|
||
|
pack->vertPosPack[1][1] = SwapF( pack->vertPosPack[1][1] );
|
||
|
pack->vertPosPack[2][0] = SwapF( pack->vertPosPack[2][0] );
|
||
|
pack->vertPosPack[2][1] = SwapF( pack->vertPosPack[2][1] );
|
||
|
|
||
|
pack->vertTcPack[0][0] = SwapF( pack->vertTcPack[0][0] );
|
||
|
pack->vertTcPack[0][1] = SwapF( pack->vertTcPack[0][1] );
|
||
|
pack->vertTcPack[1][0] = SwapF( pack->vertTcPack[1][0] );
|
||
|
pack->vertTcPack[1][1] = SwapF( pack->vertTcPack[1][1] );
|
||
|
}
|
||
|
|
||
|
static void swap_x42KeyStreamEntry_v5_t( x42KeyStreamEntry_v5_t *ks )
|
||
|
{
|
||
|
ks->type = Swap2u( ks->type );
|
||
|
ks->bone = Swap2u( ks->bone );
|
||
|
ks->frame = Swap2u( ks->frame );
|
||
|
ks->value = Swap2u( ks->value );
|
||
|
}
|
||
|
|
||
|
static void swap_x42Animation_v5_t( x42Animation_v5_t *anim )
|
||
|
{
|
||
|
anim->name = Swap2u( anim->name );
|
||
|
anim->firstFrame = Swap2u( anim->firstFrame );
|
||
|
anim->lastFrame = Swap2u( anim->lastFrame );
|
||
|
anim->loopStart = Swap2u( anim->loopStart );
|
||
|
anim->loopEnd = Swap2u( anim->loopEnd );
|
||
|
anim->frameRate = Swap2u( anim->frameRate );
|
||
|
}
|
||
|
|
||
|
static void swap_x42AnimGroup_v5_t( x42AnimGroup_v5_t *group )
|
||
|
{
|
||
|
group->name = Swap2u( group->name );
|
||
|
group->beginBone = Swap2u( group->beginBone );
|
||
|
group->endBone = Swap2u( group->endBone );
|
||
|
}
|
||
|
|
||
|
static void swap_x42Bone_v5_t( x42Bone_v5_t *bone )
|
||
|
{
|
||
|
bone->name = Swap2u( bone->name );
|
||
|
bone->flags = Swap2u( bone->name );
|
||
|
bone->parentIdx = Swap2u( bone->parentIdx );
|
||
|
bone->extent = SwapF( bone->extent );
|
||
|
}
|
||
|
|
||
|
static void swap_affine_t( affine_t *a )
|
||
|
{
|
||
|
a->axis[0][0] = SwapF( a->axis[0][0] );
|
||
|
a->axis[0][1] = SwapF( a->axis[0][1] );
|
||
|
a->axis[0][2] = SwapF( a->axis[0][2] );
|
||
|
|
||
|
a->axis[1][0] = SwapF( a->axis[1][0] );
|
||
|
a->axis[1][1] = SwapF( a->axis[1][1] );
|
||
|
a->axis[1][2] = SwapF( a->axis[1][2] );
|
||
|
|
||
|
a->axis[2][0] = SwapF( a->axis[2][0] );
|
||
|
a->axis[2][1] = SwapF( a->axis[2][1] );
|
||
|
a->axis[2][2] = SwapF( a->axis[2][2] );
|
||
|
|
||
|
a->origin[0] = SwapF( a->origin[0] );
|
||
|
a->origin[1] = SwapF( a->origin[1] );
|
||
|
a->origin[2] = SwapF( a->origin[2] );
|
||
|
}
|
||
|
|
||
|
static void swap_x42Influence_v5_t( x42Influence_v5_t *inf )
|
||
|
{
|
||
|
inf->bone = Swap2u( inf->bone );
|
||
|
swap_affine_t( &inf->meshToBone );
|
||
|
}
|
||
|
|
||
|
static void swap_x42Tag_v5_t( x42Tag_v5_t *tag )
|
||
|
{
|
||
|
tag->name = Swap2u( tag->name );
|
||
|
tag->bone = Swap2u( tag->bone );
|
||
|
swap_affine_t( &tag->tagMatrix );
|
||
|
}
|
||
|
|
||
|
static void swap_x42Group_v5_t( x42Group_v5_t *g )
|
||
|
{
|
||
|
uint i;
|
||
|
|
||
|
g->material = Swap2u( g->material );
|
||
|
g->surfaceName = Swap2u( g->surfaceName );
|
||
|
|
||
|
g->maxVertInfluences = Swap2u( g->maxVertInfluences );
|
||
|
g->numInfluences = Swap2u( g->numInfluences );
|
||
|
|
||
|
for( i = 0; i < X42_MAX_INFLUENCES_PER_BATCH_V5; i++ )
|
||
|
g->influences[i] = Swap2u( g->influences[i] );
|
||
|
|
||
|
g->primType = Swap2u( g->primType );
|
||
|
|
||
|
g->firstVert = Swap4u( g->firstVert );
|
||
|
g->numVerts = Swap4u( g->numVerts );
|
||
|
g->firstIndex = Swap4u( g->firstIndex );
|
||
|
g->numElems = Swap4u( g->numElems );
|
||
|
}
|
||
|
|
||
|
static void swap_x42LodRange_v5_t( x42LodRange_v5_t *lod )
|
||
|
{
|
||
|
lod->lodName = Swap2u( lod->lodName );
|
||
|
lod->firstGroup = Swap2u( lod->firstGroup );
|
||
|
lod->numGroups = Swap2u( lod->numGroups );
|
||
|
}
|
||
|
|
||
|
static bool R_LoadX42Swapped( model_t *mod, void *buffer, size_t header_size, int filesize, const char *name, const x42header_t *h )
|
||
|
{
|
||
|
uint i;
|
||
|
|
||
|
bool stat;
|
||
|
x42PackHeader_v5_t pack;
|
||
|
|
||
|
size_t inPos;
|
||
|
const byte *inBuf;
|
||
|
|
||
|
x42data_t *ret;
|
||
|
|
||
|
const uint persist_flags = X42_PERSIST_EVERYTHING;
|
||
|
|
||
|
ret = (x42data_t*)ri.Hunk_Alloc( sizeof( x42data_t ), h_low );
|
||
|
x42_SetupBufferPointers( ret, h, persist_flags );
|
||
|
|
||
|
inPos = sizeof( x42Header_ident_t );
|
||
|
switch( h->ident.version )
|
||
|
{
|
||
|
case X42_VER_V5:
|
||
|
inPos += sizeof( x42Header_v5_t );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ri.Printf( PRINT_ERROR, "Invalid x42 file version in model '%s'\n", name );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
inBuf = (const byte*)buffer + inPos;
|
||
|
|
||
|
#define read_check() if( !stat ) return false; else (void)0
|
||
|
|
||
|
#define checked_read( buf, type, count ) \
|
||
|
if( !const_cond_false ) \
|
||
|
{ \
|
||
|
uint _i; \
|
||
|
size_t cb = sizeof( type ) * (count); \
|
||
|
\
|
||
|
stat = inPos + cb <= filesize; \
|
||
|
read_check(); \
|
||
|
\
|
||
|
Com_Memcpy( buf, inBuf, cb ); \
|
||
|
inBuf += cb; \
|
||
|
inPos += cb; \
|
||
|
\
|
||
|
for( _i = 0; _i < (count); _i++ ) \
|
||
|
swap_##type( buf + _i ); \
|
||
|
} \
|
||
|
else \
|
||
|
(void)0
|
||
|
|
||
|
#define checked_align( a ) \
|
||
|
if( !const_cond_false ) \
|
||
|
{ \
|
||
|
size_t _a = (a); \
|
||
|
\
|
||
|
if( _a ) \
|
||
|
{ \
|
||
|
size_t ofs = ((_a - (inPos % _a)) % _a); \
|
||
|
\
|
||
|
stat = inPos + ofs <= filesize; \
|
||
|
read_check(); \
|
||
|
\
|
||
|
inBuf += ofs; \
|
||
|
inPos += ofs; \
|
||
|
} \
|
||
|
} \
|
||
|
else \
|
||
|
(void)0
|
||
|
|
||
|
#define checked_read_a( buf, type, count, a ) \
|
||
|
if( !const_cond_false ) \
|
||
|
{ \
|
||
|
checked_align( a ); \
|
||
|
checked_read( buf, type, count ); \
|
||
|
} \
|
||
|
else \
|
||
|
(void)0
|
||
|
|
||
|
#define checked_skip( size, a ) \
|
||
|
if( !const_cond_false ) \
|
||
|
{ \
|
||
|
size_t cb = (size); \
|
||
|
\
|
||
|
checked_align( a ); \
|
||
|
stat = inPos + cb <= filesize; \
|
||
|
read_check(); \
|
||
|
\
|
||
|
inBuf += cb; \
|
||
|
inPos += cb; \
|
||
|
} \
|
||
|
else \
|
||
|
(void)0
|
||
|
|
||
|
checked_read( &pack, x42PackHeader_v5_t, 1 );
|
||
|
|
||
|
checked_read_a( ret->bones, x42Bone_v5_t, h->numBones, 8 );
|
||
|
checked_read_a( ret->animGroups, x42AnimGroup_v5_t, h->numAnimGroups, 8 );
|
||
|
|
||
|
for( i = 0; i < h->numAnimGroups; i++ )
|
||
|
{
|
||
|
uint j;
|
||
|
for( j = ret->animGroups[i].beginBone; j < ret->animGroups[i].endBone; j++ )
|
||
|
ret->boneGroups[j] = (u8)i;
|
||
|
}
|
||
|
|
||
|
checked_align( 2 );
|
||
|
stat = read_packed_floats_swp( &inBuf, filesize, &inPos, pack.animPosPack, 3,
|
||
|
(float*)ret->posValues, h->numPosValues, sizeof( vec3_t ) );
|
||
|
read_check();
|
||
|
|
||
|
if( h->modelFlags & X42_MF_UNIFORM_SCALE )
|
||
|
{
|
||
|
stat = read_packed_floats_swp( &inBuf, filesize, &inPos, &pack.animScalePack, 1,
|
||
|
(float*)ret->scaleValues, h->numScaleValues, sizeof( vec3_t ) );
|
||
|
read_check();
|
||
|
|
||
|
for( i = 0; i < h->numScaleValues; i++ )
|
||
|
{
|
||
|
ret->scaleValues[i][1] = ret->scaleValues[i][0];
|
||
|
ret->scaleValues[i][2] = ret->scaleValues[i][0];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
vec2_t bdxyz[3];
|
||
|
|
||
|
bdxyz[0][0] = bdxyz[1][0] = bdxyz[2][0] = pack.animScalePack[0];
|
||
|
bdxyz[0][1] = bdxyz[1][1] = bdxyz[2][1] = pack.animScalePack[1];
|
||
|
|
||
|
stat = read_packed_floats_swp( &inBuf, filesize, &inPos, bdxyz, 3,
|
||
|
(float*)ret->scaleValues, h->numScaleValues, sizeof( vec3_t ) );
|
||
|
read_check();
|
||
|
}
|
||
|
|
||
|
stat = read_packed_floats_s16n_swp( &inBuf, filesize, &inPos, 4,
|
||
|
(float*)ret->rotValues, h->numRotValues, sizeof( quat_t ) );
|
||
|
read_check();
|
||
|
|
||
|
checked_read_a( ret->keyStream, x42KeyStreamEntry_v5_t, h->keyStreamLength, 8 );
|
||
|
checked_read_a( ret->animations, x42Animation_v5_t, h->numAnims, 8 );
|
||
|
checked_read_a( ret->tags, x42Tag_v5_t, h->numTags, 8 );
|
||
|
checked_read_a( ret->influences, x42Influence_v5_t, h->numInfluences, 8 );
|
||
|
checked_read_a( ret->lods, x42LodRange_v5_t, h->numLods, 8 );
|
||
|
checked_read_a( ret->groups, x42Group_v5_t, h->numGroups, 8 );
|
||
|
|
||
|
checked_align( 2 );
|
||
|
stat = read_packed_floats_swp( &inBuf, filesize, &inPos, pack.vertPosPack, 3,
|
||
|
(float*)&ret->vertPos[0].pos, h->numVerts, sizeof( x42vertAnim_t ) );
|
||
|
read_check();
|
||
|
|
||
|
for( i = 0; i < h->numGroups; i++ )
|
||
|
{
|
||
|
uint j;
|
||
|
|
||
|
const x42group_t *g = ret->groups + i;
|
||
|
size_t cbElem;
|
||
|
|
||
|
if( !g->maxVertInfluences )
|
||
|
continue;
|
||
|
|
||
|
cbElem = sizeof( byte ) * ((g->maxVertInfluences - 1) * 2 + 1);
|
||
|
|
||
|
for( j = 0; j < g->numVerts; j++ )
|
||
|
{
|
||
|
uint k;
|
||
|
u8 in[7];
|
||
|
float sum;
|
||
|
|
||
|
x42vertAnim_t *v;
|
||
|
|
||
|
checked_read( in, u8, cbElem );
|
||
|
|
||
|
v = ret->vertPos + g->firstVert + j;
|
||
|
|
||
|
sum = 0;
|
||
|
for( k = 0; k < g->maxVertInfluences - 1U; k++ )
|
||
|
{
|
||
|
v->idx[k] = in[k * 2 + 0];
|
||
|
v->wt[k] = X42_FLOAT_U8N_UNPACK( in[k * 2 + 1] );
|
||
|
|
||
|
sum += v->wt[k];
|
||
|
}
|
||
|
|
||
|
v->idx[k] = in[k * 2 + 0];
|
||
|
v->wt[k] = 1.0F - sum;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( ret->vertNorm )
|
||
|
{
|
||
|
stat = read_packed_floats_s8n_swp( &inBuf, filesize, &inPos, 3,
|
||
|
(float*)&ret->vertNorm[0].norm, h->numVerts, sizeof( x42vertNormal_t ) );
|
||
|
read_check();
|
||
|
}
|
||
|
else if( h->modelFlags & X42_MF_HAS_NORMALS )
|
||
|
checked_skip( sizeof( s8[3] ) * h->numVerts, 0 );
|
||
|
|
||
|
if( ret->vertTan )
|
||
|
{
|
||
|
stat = read_packed_floats_s8n_swp( &inBuf, filesize, &inPos, 7,
|
||
|
(float*)&ret->vertTan[0].tan, h->numVerts, sizeof( x42vertTangent_t ) );
|
||
|
read_check();
|
||
|
|
||
|
for( i = 0; i < h->numVerts; i++ )
|
||
|
ret->vertTan[i].nfac1 = ret->vertTan[i].nfac0;
|
||
|
}
|
||
|
else if( h->modelFlags & X42_MF_HAS_TANGENT_BASIS )
|
||
|
checked_skip( sizeof( s8[7] ) * h->numVerts, 0 );
|
||
|
|
||
|
if( ret->vertTc )
|
||
|
{
|
||
|
checked_align( 2 );
|
||
|
stat = read_packed_floats_swp( &inBuf, filesize, &inPos, pack.vertTcPack, 2,
|
||
|
(float*)ret->vertTc, h->numVerts, sizeof( vec2_t ) );
|
||
|
read_check();
|
||
|
}
|
||
|
else if( h->modelFlags & X42_MF_HAS_TEXTURE_COORDINATES )
|
||
|
checked_skip( sizeof( u16[2] ) * h->numVerts, 2 );
|
||
|
|
||
|
if( ret->vertCl )
|
||
|
{
|
||
|
checked_read_a( ret->vertCl, rgba_t, h->numVerts, 4 );
|
||
|
}
|
||
|
else if( h->modelFlags & X42_MF_HAS_COLORS )
|
||
|
checked_skip( sizeof( rgba_t ) * h->numVerts, 4 );
|
||
|
|
||
|
checked_read_a( ret->indices, x42Index_t, h->numIndices, 4 );
|
||
|
|
||
|
checked_read( (char*)ret->strings, u8, h->nameBlobLen );
|
||
|
|
||
|
#undef checked_skip
|
||
|
#undef checked_read_a
|
||
|
#undef checked_read
|
||
|
#undef checked_align
|
||
|
#undef read_check
|
||
|
|
||
|
mod->type = MOD_X42;
|
||
|
mod->x42 = ret;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static bool R_LoadX42Header( x42header_t *h, size_t *header_size, const void *buffer, bool swap )
|
||
|
{
|
||
|
const x42Header_ident_t *inIdent = (x42Header_ident_t*)buffer;
|
||
|
|
||
|
Com_Memset( h, 0, sizeof( x42header_t ) );
|
||
|
|
||
|
h->ident = *inIdent;
|
||
|
if( swap )
|
||
|
{
|
||
|
h->ident.ident = Swap4u( h->ident.ident );
|
||
|
h->ident.version = Swap4u( h->ident.version );
|
||
|
}
|
||
|
|
||
|
switch( h->ident.version )
|
||
|
{
|
||
|
case X42_VER_V5:
|
||
|
{
|
||
|
const x42Header_v5_t *inH = (x42Header_v5_t*)(inIdent + 1);
|
||
|
*header_size = sizeof( x42Header_ident_t ) + sizeof( x42Header_v5_t );
|
||
|
|
||
|
h->modelFlags = inH->modelFlags;
|
||
|
|
||
|
h->baseFrame = inH->baseFrame;
|
||
|
h->numFrames = inH->numFrames;
|
||
|
|
||
|
h->nameBlobLen = inH->nameBlobLen;
|
||
|
|
||
|
h->numBones = inH->numBones;
|
||
|
h->numAnimGroups = inH->numAnimGroups;
|
||
|
|
||
|
h->numPosValues = inH->numPosValues;
|
||
|
h->numScaleValues = inH->numScaleValues;
|
||
|
h->numRotValues = inH->numRotValues;
|
||
|
|
||
|
h->keyStreamLength = inH->keyStreamLength;
|
||
|
h->numAnims = inH->numAnims;
|
||
|
|
||
|
h->numTags = inH->numTags;
|
||
|
h->numInfluences = inH->numInfluences;
|
||
|
|
||
|
h->numLods = inH->numLods;
|
||
|
h->numGroups = inH->numGroups;
|
||
|
|
||
|
h->numVerts = inH->numVerts;
|
||
|
h->numIndices = inH->numIndices;
|
||
|
|
||
|
h->boundingBox = inH->boundingBox;
|
||
|
h->boundingSphere = inH->boundingSphere;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if( swap )
|
||
|
{
|
||
|
h->modelFlags = Swap2u( h->modelFlags );
|
||
|
|
||
|
h->baseFrame = Swap2s( h->baseFrame );
|
||
|
h->numFrames = Swap2u( h->numFrames );
|
||
|
|
||
|
h->nameBlobLen = Swap2u( h->nameBlobLen );
|
||
|
|
||
|
h->numBones = Swap2u( h->numBones );
|
||
|
h->numAnimGroups = Swap2u( h->numAnimGroups );
|
||
|
|
||
|
h->numPosValues = Swap2u( h->numPosValues );
|
||
|
h->numScaleValues = Swap2u( h->numScaleValues );
|
||
|
h->numRotValues = Swap2u( h->numRotValues );
|
||
|
|
||
|
h->keyStreamLength = Swap2u( h->keyStreamLength );
|
||
|
h->numAnims = Swap2u( h->numAnims );
|
||
|
|
||
|
h->numTags = Swap2u( h->numTags );
|
||
|
h->numInfluences = Swap2u( h->numInfluences );
|
||
|
|
||
|
h->numLods = Swap2u( h->numLods );
|
||
|
h->numGroups = Swap2u( h->numGroups );
|
||
|
|
||
|
h->numVerts = Swap4u( h->numVerts );
|
||
|
h->numIndices = Swap4u( h->numIndices );
|
||
|
|
||
|
h->boundingBox.mins[0] = SwapF( h->boundingBox.mins[0] );
|
||
|
h->boundingBox.mins[1] = SwapF( h->boundingBox.mins[1] );
|
||
|
h->boundingBox.mins[2] = SwapF( h->boundingBox.mins[2] );
|
||
|
|
||
|
h->boundingBox.maxs[0] = SwapF( h->boundingBox.maxs[0] );
|
||
|
h->boundingBox.maxs[1] = SwapF( h->boundingBox.maxs[1] );
|
||
|
h->boundingBox.maxs[2] = SwapF( h->boundingBox.maxs[2] );
|
||
|
|
||
|
h->boundingSphere.center[0] = SwapF( h->boundingSphere.center[0] );
|
||
|
h->boundingSphere.center[1] = SwapF( h->boundingSphere.center[1] );
|
||
|
h->boundingSphere.center[2] = SwapF( h->boundingSphere.center[2] );
|
||
|
|
||
|
h->boundingSphere.radius = SwapF( h->boundingSphere.radius );
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static void R_x42TransformStaticGroupsIntoQ3Space( x42data_t *x42 )
|
||
|
{
|
||
|
uint i;
|
||
|
|
||
|
for( i = 0; i < x42->header.numGroups; i++ )
|
||
|
{
|
||
|
uint j;
|
||
|
uint lastVert;
|
||
|
|
||
|
const x42group_t *g = x42->groups + i;
|
||
|
|
||
|
if( g->maxVertInfluences )
|
||
|
//not a static group
|
||
|
continue;
|
||
|
|
||
|
lastVert = g->firstVert + g->numVerts;
|
||
|
|
||
|
for( j = g->firstVert; j < lastVert; j++ )
|
||
|
{
|
||
|
Affine_MulPos( x42->vertPos[j].pos, &x42_m2q3, x42->vertPos[j].pos );
|
||
|
|
||
|
if( x42->vertNorm )
|
||
|
{
|
||
|
Affine_MulPos( x42->vertNorm[j].norm, &x42_m2q3, x42->vertNorm[j].norm );
|
||
|
}
|
||
|
|
||
|
if( x42->vertTan )
|
||
|
{
|
||
|
Affine_MulPos( x42->vertTan[j].tan, &x42_m2q3, x42->vertTan[j].tan );
|
||
|
Affine_MulPos( x42->vertTan[j].bit, &x42_m2q3, x42->vertTan[j].bit );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void R_x42LoadDefaultShaders( x42data_t *x42 )
|
||
|
{
|
||
|
uint i;
|
||
|
|
||
|
x42->groupMats = (int*)ri.Hunk_Alloc( sizeof( int ) * x42->header.numGroups, h_low );
|
||
|
for( i = 0; i < x42->header.numGroups; i++ )
|
||
|
{
|
||
|
shader_t *shader = R_FindShader( x42->strings + x42->groups[i].material, LIGHTMAP_NONE, qtrue );
|
||
|
x42->groupMats[i] = shader->defaultShader ? 0 : shader->index;
|
||
|
|
||
|
Q_strlwr( (char*)x42->strings + x42->groups[i].surfaceName );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool R_LoadX42( model_t *mod, void *buffer, int filesize, const char *name )
|
||
|
{
|
||
|
x42header_t h;
|
||
|
size_t header_size;
|
||
|
|
||
|
bool swapped;
|
||
|
|
||
|
const x42Header_ident_t *inIdent = (x42Header_ident_t*)buffer;
|
||
|
|
||
|
if( inIdent->ident != X42_IDENT && Swap4u( inIdent->ident ) != X42_IDENT )
|
||
|
{
|
||
|
ri.Printf( PRINT_WARNING, "R_LoadX42: %s has an invalid ident\n", name );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
swapped = inIdent->ident != X42_IDENT;
|
||
|
|
||
|
if( !R_LoadX42Header( &h, &header_size, buffer, swapped ) )
|
||
|
return false;
|
||
|
|
||
|
if( !swapped )
|
||
|
{
|
||
|
if( !R_LoadX42Direct( mod, buffer, header_size, filesize, name, &h ) )
|
||
|
return false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( !R_LoadX42Swapped( mod, buffer, header_size, filesize, name, &h ) )
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
mod->numLods = h.numLods;
|
||
|
|
||
|
R_x42LoadDefaultShaders( mod->x42 );
|
||
|
R_x42TransformStaticGroupsIntoQ3Space( mod->x42 );
|
||
|
R_x42PoseInitKsStarts( mod->x42 );
|
||
|
|
||
|
return true;
|
||
|
}
|