mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2024-11-10 14:52:00 +00:00
Improve IQM loading
- Only allocate memory for vertex arrays that are present in the IQM file and are actually used (may not have colors or blend index/weights, don't load tangents in opengl1). (Colors is fixed to next commit.) - Explicitly handle loading IQM files without meshes (bones only). - Better IQM validation. Header data offset 0 mean data is not present in file. Check if required vertex arrays are present. This involved a lot of white space changes and moving code around.
This commit is contained in:
parent
6c3d92133d
commit
fdc08e860e
4 changed files with 924 additions and 751 deletions
|
@ -599,6 +599,7 @@ typedef struct {
|
|||
int num_poses;
|
||||
struct srfIQModel_s *surfaces;
|
||||
|
||||
int *triangles;
|
||||
float *positions;
|
||||
float *texcoords;
|
||||
float *normals;
|
||||
|
@ -609,18 +610,17 @@ typedef struct {
|
|||
byte *b;
|
||||
} blendWeights;
|
||||
byte *colors;
|
||||
int *triangles;
|
||||
|
||||
// depending upon the exporter, blend indices and weights might be int/float
|
||||
// as opposed to the recommended byte/byte, for example Noesis exports
|
||||
// int/float whereas the official IQM tool exports byte/byte
|
||||
byte blendWeightsType; // IQM_UBYTE or IQM_FLOAT
|
||||
|
||||
char *jointNames;
|
||||
int *jointParents;
|
||||
float *jointMats;
|
||||
float *poseMats;
|
||||
float *bounds;
|
||||
char *names;
|
||||
} iqmData_t;
|
||||
|
||||
// inter-quake-model surface
|
||||
|
|
|
@ -33,11 +33,11 @@ static float identityMatrix[12] = {
|
|||
};
|
||||
|
||||
static qboolean IQM_CheckRange( iqmHeader_t *header, int offset,
|
||||
int count,int size ) {
|
||||
int count, int size ) {
|
||||
// return true if the range specified by offset, count and size
|
||||
// doesn't fit into the file
|
||||
return ( count <= 0 ||
|
||||
offset < 0 ||
|
||||
offset <= 0 ||
|
||||
offset > header->filesize ||
|
||||
offset + count * size < 0 ||
|
||||
offset + count * size > header->filesize );
|
||||
|
@ -147,10 +147,11 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
float jointInvMats[IQM_MAX_JOINTS * 12] = {0.0f};
|
||||
float *mat, *matInv;
|
||||
size_t size, joint_names;
|
||||
byte *dataPtr;
|
||||
iqmData_t *iqmData;
|
||||
srfIQModel_t *surface;
|
||||
char meshName[MAX_QPATH];
|
||||
byte blendIndexesType, blendWeightsType;
|
||||
int vertexArrayFormat[IQM_COLOR+1];
|
||||
|
||||
if( filesize < sizeof(iqmHeader_t) ) {
|
||||
return qfalse;
|
||||
|
@ -206,8 +207,12 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
return qfalse;
|
||||
}
|
||||
|
||||
blendIndexesType = blendWeightsType = IQM_UBYTE;
|
||||
for ( i = 0; i < ARRAY_LEN( vertexArrayFormat ); i++ ) {
|
||||
vertexArrayFormat[i] = -1;
|
||||
}
|
||||
|
||||
if ( header->num_meshes )
|
||||
{
|
||||
// check and swap vertex arrays
|
||||
if( IQM_CheckRange( header, header->ofs_vertexarrays,
|
||||
header->num_vertexarrays,
|
||||
|
@ -253,6 +258,10 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
break;
|
||||
}
|
||||
|
||||
if( vertexarray->type < ARRAY_LEN( vertexArrayFormat ) ) {
|
||||
vertexArrayFormat[vertexarray->type] = vertexarray->format;
|
||||
}
|
||||
|
||||
switch( vertexarray->type ) {
|
||||
case IQM_POSITION:
|
||||
case IQM_NORMAL:
|
||||
|
@ -279,7 +288,6 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
vertexarray->size != 4 ) {
|
||||
return qfalse;
|
||||
}
|
||||
blendIndexesType = vertexarray->format;
|
||||
break;
|
||||
case IQM_BLENDWEIGHTS:
|
||||
if( (vertexarray->format != IQM_FLOAT &&
|
||||
|
@ -287,7 +295,6 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
vertexarray->size != 4 ) {
|
||||
return qfalse;
|
||||
}
|
||||
blendWeightsType = vertexarray->format;
|
||||
break;
|
||||
case IQM_COLOR:
|
||||
if( vertexarray->format != IQM_UBYTE ||
|
||||
|
@ -298,6 +305,29 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
}
|
||||
}
|
||||
|
||||
// check for required vertex arrays
|
||||
if( vertexArrayFormat[IQM_POSITION] == -1 || vertexArrayFormat[IQM_NORMAL] == -1 || vertexArrayFormat[IQM_TEXCOORD] == -1 ) {
|
||||
ri.Printf( PRINT_WARNING, "R_LoadIQM: %s is missing IQM_POSITION, IQM_NORMAL, and/or IQM_TEXCOORD array.\n", mod_name );
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
if( header->num_joints ) {
|
||||
if( vertexArrayFormat[IQM_BLENDINDEXES] == -1 || vertexArrayFormat[IQM_BLENDWEIGHTS] == -1 ) {
|
||||
ri.Printf( PRINT_WARNING, "R_LoadIQM: %s is missing IQM_BLENDINDEXES and/or IQM_BLENDWEIGHTS array.\n", mod_name );
|
||||
return qfalse;
|
||||
}
|
||||
} else {
|
||||
// ignore blend arrays if present
|
||||
vertexArrayFormat[IQM_BLENDINDEXES] = -1;
|
||||
vertexArrayFormat[IQM_BLENDWEIGHTS] = -1;
|
||||
}
|
||||
|
||||
// opengl1 renderer doesn't use tangents
|
||||
vertexArrayFormat[IQM_TANGENT] = -1;
|
||||
|
||||
// FIXME: don't require colors array when drawing
|
||||
vertexArrayFormat[IQM_COLOR] = IQM_UBYTE;
|
||||
|
||||
// check and swap triangles
|
||||
if( IQM_CheckRange( header, header->ofs_triangles,
|
||||
header->num_triangles, sizeof(iqmTriangle_t) ) ) {
|
||||
|
@ -337,16 +367,14 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
}
|
||||
|
||||
// check ioq3 limits
|
||||
if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES )
|
||||
{
|
||||
ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n",
|
||||
if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES ) {
|
||||
ri.Printf( PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n",
|
||||
mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface",
|
||||
mesh->num_vertexes );
|
||||
return qfalse;
|
||||
}
|
||||
if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES )
|
||||
{
|
||||
ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n",
|
||||
if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES ) {
|
||||
ri.Printf( PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n",
|
||||
mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface",
|
||||
mesh->num_triangles );
|
||||
return qfalse;
|
||||
|
@ -361,9 +389,10 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
return qfalse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( header->num_poses != header->num_joints && header->num_poses != 0 ) {
|
||||
ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n",
|
||||
ri.Printf( PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n",
|
||||
mod_name, header->num_poses, header->num_joints );
|
||||
return qfalse;
|
||||
}
|
||||
|
@ -460,26 +489,41 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
|
||||
// allocate the model and copy the data
|
||||
size = sizeof(iqmData_t);
|
||||
size += header->num_meshes * sizeof( srfIQModel_t );
|
||||
size += header->num_joints * 12 * sizeof( float ); // joint mats
|
||||
size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats
|
||||
if(header->ofs_bounds)
|
||||
size += header->num_frames * 6 * sizeof(float); // model bounds
|
||||
if( header->num_meshes ) {
|
||||
size += header->num_meshes * sizeof( srfIQModel_t ); // surfaces
|
||||
size += header->num_triangles * 3 * sizeof(int); // triangles
|
||||
size += header->num_vertexes * 3 * sizeof(float); // positions
|
||||
size += header->num_vertexes * 2 * sizeof(float); // texcoords
|
||||
size += header->num_vertexes * 3 * sizeof(float); // normals
|
||||
size += header->num_vertexes * 4 * sizeof(float); // tangents
|
||||
size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes
|
||||
size += header->num_vertexes * 4 * sizeof(byte); // colors
|
||||
size += header->num_joints * sizeof(int); // parents
|
||||
size += header->num_triangles * 3 * sizeof(int); // triangles
|
||||
size += joint_names; // joint names
|
||||
|
||||
// blendWeights
|
||||
if (blendWeightsType == IQM_FLOAT) {
|
||||
size += header->num_vertexes * 4 * sizeof(float);
|
||||
} else {
|
||||
size += header->num_vertexes * 4 * sizeof(byte);
|
||||
if ( vertexArrayFormat[IQM_TANGENT] != -1 ) {
|
||||
size += header->num_vertexes * 4 * sizeof(float); // tangents
|
||||
}
|
||||
|
||||
if ( vertexArrayFormat[IQM_BLENDINDEXES] != -1 ) {
|
||||
size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes
|
||||
}
|
||||
|
||||
if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_UBYTE ) {
|
||||
size += header->num_vertexes * 4 * sizeof(byte); // blendWeights
|
||||
} else if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) {
|
||||
size += header->num_vertexes * 4 * sizeof(float); // blendWeights
|
||||
}
|
||||
|
||||
if ( vertexArrayFormat[IQM_COLOR] != -1 ) {
|
||||
size += header->num_vertexes * 4 * sizeof(byte); // colors
|
||||
}
|
||||
}
|
||||
if( header->num_joints ) {
|
||||
size += joint_names; // joint names
|
||||
size += header->num_joints * sizeof(int); // joint parents
|
||||
size += header->num_joints * 12 * sizeof( float ); // joint mats
|
||||
}
|
||||
if( header->num_poses ) {
|
||||
size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats
|
||||
}
|
||||
if( header->ofs_bounds ) {
|
||||
size += header->num_frames * 6 * sizeof(float); // model bounds
|
||||
}
|
||||
|
||||
mod->type = MOD_IQM;
|
||||
|
@ -487,45 +531,186 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
mod->modelData = iqmData;
|
||||
|
||||
// fill header
|
||||
iqmData->num_vertexes = header->num_vertexes;
|
||||
iqmData->num_triangles = header->num_triangles;
|
||||
iqmData->num_vertexes = ( header->num_meshes > 0 ) ? header->num_vertexes : 0;
|
||||
iqmData->num_triangles = ( header->num_meshes > 0 ) ? header->num_triangles : 0;
|
||||
iqmData->num_frames = header->num_frames;
|
||||
iqmData->num_surfaces = header->num_meshes;
|
||||
iqmData->num_joints = header->num_joints;
|
||||
iqmData->num_poses = header->num_poses;
|
||||
iqmData->blendWeightsType = blendWeightsType;
|
||||
iqmData->surfaces = (srfIQModel_t *)(iqmData + 1);
|
||||
iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces);
|
||||
iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints;
|
||||
if(header->ofs_bounds)
|
||||
iqmData->blendWeightsType = vertexArrayFormat[IQM_BLENDWEIGHTS];
|
||||
|
||||
dataPtr = (byte*)iqmData + sizeof(iqmData_t);
|
||||
if( header->num_meshes ) {
|
||||
iqmData->surfaces = (struct srfIQModel_s*)dataPtr;
|
||||
dataPtr += header->num_meshes * sizeof( srfIQModel_t );
|
||||
|
||||
iqmData->triangles = (int*)dataPtr;
|
||||
dataPtr += header->num_triangles * 3 * sizeof(int); // triangles
|
||||
|
||||
iqmData->positions = (float*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 3 * sizeof(float); // positions
|
||||
|
||||
iqmData->texcoords = (float*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 2 * sizeof(float); // texcoords
|
||||
|
||||
iqmData->normals = (float*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 3 * sizeof(float); // normals
|
||||
|
||||
if ( vertexArrayFormat[IQM_TANGENT] != -1 ) {
|
||||
iqmData->tangents = (float*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 4 * sizeof(float); // tangents
|
||||
}
|
||||
|
||||
if ( vertexArrayFormat[IQM_BLENDINDEXES] != -1 ) {
|
||||
iqmData->blendIndexes = (byte*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 4 * sizeof(byte); // blendIndexes
|
||||
}
|
||||
|
||||
if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_UBYTE ) {
|
||||
iqmData->blendWeights.b = (byte*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 4 * sizeof(byte); // blendWeights
|
||||
} else if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) {
|
||||
iqmData->blendWeights.f = (float*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 4 * sizeof(float); // blendWeights
|
||||
}
|
||||
|
||||
if ( vertexArrayFormat[IQM_COLOR] != -1 ) {
|
||||
iqmData->colors = (byte*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 4 * sizeof(byte); // colors
|
||||
}
|
||||
}
|
||||
if( header->num_joints ) {
|
||||
iqmData->jointNames = (char*)dataPtr;
|
||||
dataPtr += joint_names; // joint names
|
||||
|
||||
iqmData->jointParents = (int*)dataPtr;
|
||||
dataPtr += header->num_joints * sizeof(int); // joint parents
|
||||
|
||||
iqmData->jointMats = (float*)dataPtr;
|
||||
dataPtr += header->num_joints * 12 * sizeof( float ); // joint mats
|
||||
}
|
||||
if( header->num_poses ) {
|
||||
iqmData->poseMats = (float*)dataPtr;
|
||||
dataPtr += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats
|
||||
}
|
||||
if( header->ofs_bounds ) {
|
||||
iqmData->bounds = (float*)dataPtr;
|
||||
dataPtr += header->num_frames * 6 * sizeof(float); // model bounds
|
||||
}
|
||||
|
||||
if( header->num_meshes )
|
||||
{
|
||||
iqmData->bounds = iqmData->poseMats + 12 * header->num_poses * header->num_frames;
|
||||
iqmData->positions = iqmData->bounds + 6 * header->num_frames;
|
||||
// register shaders
|
||||
// overwrite the material offset with the shader index
|
||||
mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes);
|
||||
surface = iqmData->surfaces;
|
||||
str = (char *)header + header->ofs_text;
|
||||
for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) {
|
||||
surface->surfaceType = SF_IQM;
|
||||
Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name));
|
||||
Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster
|
||||
surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, qtrue );
|
||||
if( surface->shader->defaultShader )
|
||||
surface->shader = tr.defaultShader;
|
||||
surface->data = iqmData;
|
||||
surface->first_vertex = mesh->first_vertex;
|
||||
surface->num_vertexes = mesh->num_vertexes;
|
||||
surface->first_triangle = mesh->first_triangle;
|
||||
surface->num_triangles = mesh->num_triangles;
|
||||
}
|
||||
else
|
||||
iqmData->positions = iqmData->poseMats + 12 * header->num_poses * header->num_frames;
|
||||
iqmData->texcoords = iqmData->positions + 3 * header->num_vertexes;
|
||||
iqmData->normals = iqmData->texcoords + 2 * header->num_vertexes;
|
||||
iqmData->tangents = iqmData->normals + 3 * header->num_vertexes;
|
||||
iqmData->blendIndexes = (byte *)(iqmData->tangents + 4 * header->num_vertexes);
|
||||
|
||||
if(blendWeightsType == IQM_FLOAT) {
|
||||
iqmData->blendWeights.f = (float *)(iqmData->blendIndexes + 4 * header->num_vertexes);
|
||||
iqmData->colors = (byte *)(iqmData->blendWeights.f + 4 * header->num_vertexes);
|
||||
// copy triangles
|
||||
triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles);
|
||||
for( i = 0; i < header->num_triangles; i++, triangle++ ) {
|
||||
iqmData->triangles[3*i+0] = triangle->vertex[0];
|
||||
iqmData->triangles[3*i+1] = triangle->vertex[1];
|
||||
iqmData->triangles[3*i+2] = triangle->vertex[2];
|
||||
}
|
||||
|
||||
// copy vertexarrays and indexes
|
||||
vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays);
|
||||
for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) {
|
||||
int n;
|
||||
|
||||
// skip disabled arrays
|
||||
if( vertexarray->type < ARRAY_LEN( vertexArrayFormat )
|
||||
&& vertexArrayFormat[vertexarray->type] == -1 )
|
||||
continue;
|
||||
|
||||
// total number of values
|
||||
n = header->num_vertexes * vertexarray->size;
|
||||
|
||||
switch( vertexarray->type ) {
|
||||
case IQM_POSITION:
|
||||
Com_Memcpy( iqmData->positions,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_NORMAL:
|
||||
Com_Memcpy( iqmData->normals,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_TANGENT:
|
||||
Com_Memcpy( iqmData->tangents,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_TEXCOORD:
|
||||
Com_Memcpy( iqmData->texcoords,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_BLENDINDEXES:
|
||||
if( vertexarray->format == IQM_INT ) {
|
||||
int *data = (int*)((byte*)header + vertexarray->offset);
|
||||
for ( j = 0; j < n; j++ ) {
|
||||
iqmData->blendIndexes[j] = (byte)data[j];
|
||||
}
|
||||
} else {
|
||||
iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes;
|
||||
iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes;
|
||||
Com_Memcpy( iqmData->blendIndexes,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(byte) );
|
||||
}
|
||||
break;
|
||||
case IQM_BLENDWEIGHTS:
|
||||
if( vertexarray->format == IQM_FLOAT ) {
|
||||
Com_Memcpy( iqmData->blendWeights.f,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
} else {
|
||||
Com_Memcpy( iqmData->blendWeights.b,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(byte) );
|
||||
}
|
||||
break;
|
||||
case IQM_COLOR:
|
||||
Com_Memcpy( iqmData->colors,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(byte) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iqmData->jointParents = (int *)(iqmData->colors + 4 * header->num_vertexes);
|
||||
iqmData->triangles = iqmData->jointParents + header->num_joints;
|
||||
iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles);
|
||||
if( header->num_joints )
|
||||
{
|
||||
// copy joint names
|
||||
str = iqmData->jointNames;
|
||||
joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
|
||||
for( i = 0; i < header->num_joints; i++, joint++ ) {
|
||||
char *name = (char *)header + header->ofs_text +
|
||||
joint->name;
|
||||
int len = strlen( name ) + 1;
|
||||
Com_Memcpy( str, name, len );
|
||||
str += len;
|
||||
}
|
||||
|
||||
if ( header->num_joints == 0 )
|
||||
iqmData->jointMats = NULL;
|
||||
|
||||
if ( header->num_poses == 0 )
|
||||
iqmData->poseMats = NULL;
|
||||
// copy joint parents
|
||||
joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
|
||||
for( i = 0; i < header->num_joints; i++, joint++ ) {
|
||||
iqmData->jointParents[i] = joint->parent;
|
||||
}
|
||||
|
||||
// calculate joint matrices and their inverses
|
||||
// joint inverses are needed only until the pose matrices are calculated
|
||||
|
@ -553,7 +738,10 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
matInv += 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( header->num_poses )
|
||||
{
|
||||
// calculate pose matrices
|
||||
framedata = (unsigned short *)((byte *)header + header->ofs_frames);
|
||||
mat = iqmData->poseMats;
|
||||
|
@ -612,109 +800,6 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
mat += 12;
|
||||
}
|
||||
}
|
||||
|
||||
// register shaders
|
||||
// overwrite the material offset with the shader index
|
||||
mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes);
|
||||
surface = iqmData->surfaces;
|
||||
str = (char *)header + header->ofs_text;
|
||||
for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) {
|
||||
surface->surfaceType = SF_IQM;
|
||||
Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name));
|
||||
Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster
|
||||
surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, qtrue );
|
||||
if( surface->shader->defaultShader )
|
||||
surface->shader = tr.defaultShader;
|
||||
surface->data = iqmData;
|
||||
surface->first_vertex = mesh->first_vertex;
|
||||
surface->num_vertexes = mesh->num_vertexes;
|
||||
surface->first_triangle = mesh->first_triangle;
|
||||
surface->num_triangles = mesh->num_triangles;
|
||||
}
|
||||
|
||||
// copy vertexarrays and indexes
|
||||
vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays);
|
||||
for( 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:
|
||||
Com_Memcpy( iqmData->positions,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_NORMAL:
|
||||
Com_Memcpy( iqmData->normals,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_TANGENT:
|
||||
Com_Memcpy( iqmData->tangents,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_TEXCOORD:
|
||||
Com_Memcpy( iqmData->texcoords,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_BLENDINDEXES:
|
||||
if( blendIndexesType == IQM_INT ) {
|
||||
int *data = (int*)((byte*)header + vertexarray->offset);
|
||||
for ( j = 0; j < n; j++ ) {
|
||||
iqmData->blendIndexes[j] = (byte)data[j];
|
||||
}
|
||||
} else {
|
||||
Com_Memcpy( iqmData->blendIndexes,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(byte) );
|
||||
}
|
||||
break;
|
||||
case IQM_BLENDWEIGHTS:
|
||||
if( blendWeightsType == IQM_FLOAT ) {
|
||||
Com_Memcpy( iqmData->blendWeights.f,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
} else {
|
||||
Com_Memcpy( iqmData->blendWeights.b,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(byte) );
|
||||
}
|
||||
break;
|
||||
case IQM_COLOR:
|
||||
Com_Memcpy( iqmData->colors,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(byte) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// copy joint parents
|
||||
joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
|
||||
for( i = 0; i < header->num_joints; i++, joint++ ) {
|
||||
iqmData->jointParents[i] = joint->parent;
|
||||
}
|
||||
|
||||
// copy triangles
|
||||
triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles);
|
||||
for( i = 0; i < header->num_triangles; i++, triangle++ ) {
|
||||
iqmData->triangles[3*i+0] = triangle->vertex[0];
|
||||
iqmData->triangles[3*i+1] = triangle->vertex[1];
|
||||
iqmData->triangles[3*i+2] = triangle->vertex[2];
|
||||
}
|
||||
|
||||
// copy joint names
|
||||
str = iqmData->names;
|
||||
joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
|
||||
for( i = 0; i < header->num_joints; i++, joint++ ) {
|
||||
char *name = (char *)header + header->ofs_text +
|
||||
joint->name;
|
||||
int len = strlen( name ) + 1;
|
||||
Com_Memcpy( str, name, len );
|
||||
str += len;
|
||||
}
|
||||
|
||||
// copy model bounds
|
||||
|
@ -1152,7 +1237,7 @@ int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
|
|||
float frac, const char *tagName ) {
|
||||
float jointMats[IQM_MAX_JOINTS * 12];
|
||||
int joint;
|
||||
char *names = data->names;
|
||||
char *names = data->jointNames;
|
||||
|
||||
// get joint number by reading the joint names
|
||||
for( joint = 0; joint < data->num_joints; joint++ ) {
|
||||
|
|
|
@ -949,6 +949,7 @@ typedef struct {
|
|||
int num_poses;
|
||||
struct srfIQModel_s *surfaces;
|
||||
|
||||
int *triangles;
|
||||
float *positions;
|
||||
float *texcoords;
|
||||
float *normals;
|
||||
|
@ -959,18 +960,17 @@ typedef struct {
|
|||
byte *b;
|
||||
} blendWeights;
|
||||
byte *colors;
|
||||
int *triangles;
|
||||
|
||||
// depending upon the exporter, blend indices and weights might be int/float
|
||||
// as opposed to the recommended byte/byte, for example Noesis exports
|
||||
// int/float whereas the official IQM tool exports byte/byte
|
||||
byte blendWeightsType; // IQM_UBYTE or IQM_FLOAT
|
||||
|
||||
char *jointNames;
|
||||
int *jointParents;
|
||||
float *jointMats;
|
||||
float *poseMats;
|
||||
float *bounds;
|
||||
char *names;
|
||||
} iqmData_t;
|
||||
|
||||
// inter-quake-model surface
|
||||
|
|
|
@ -33,11 +33,11 @@ static float identityMatrix[12] = {
|
|||
};
|
||||
|
||||
static qboolean IQM_CheckRange( iqmHeader_t *header, int offset,
|
||||
int count,int size ) {
|
||||
int count, int size ) {
|
||||
// return true if the range specified by offset, count and size
|
||||
// doesn't fit into the file
|
||||
return ( count <= 0 ||
|
||||
offset < 0 ||
|
||||
offset <= 0 ||
|
||||
offset > header->filesize ||
|
||||
offset + count * size < 0 ||
|
||||
offset + count * size > header->filesize );
|
||||
|
@ -147,10 +147,11 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
float jointInvMats[IQM_MAX_JOINTS * 12] = {0.0f};
|
||||
float *mat, *matInv;
|
||||
size_t size, joint_names;
|
||||
byte *dataPtr;
|
||||
iqmData_t *iqmData;
|
||||
srfIQModel_t *surface;
|
||||
char meshName[MAX_QPATH];
|
||||
byte blendIndexesType, blendWeightsType;
|
||||
int vertexArrayFormat[IQM_COLOR+1];
|
||||
|
||||
if( filesize < sizeof(iqmHeader_t) ) {
|
||||
return qfalse;
|
||||
|
@ -206,8 +207,12 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
return qfalse;
|
||||
}
|
||||
|
||||
blendIndexesType = blendWeightsType = IQM_UBYTE;
|
||||
for ( i = 0; i < ARRAY_LEN( vertexArrayFormat ); i++ ) {
|
||||
vertexArrayFormat[i] = -1;
|
||||
}
|
||||
|
||||
if ( header->num_meshes )
|
||||
{
|
||||
// check and swap vertex arrays
|
||||
if( IQM_CheckRange( header, header->ofs_vertexarrays,
|
||||
header->num_vertexarrays,
|
||||
|
@ -253,6 +258,10 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
break;
|
||||
}
|
||||
|
||||
if( vertexarray->type < ARRAY_LEN( vertexArrayFormat ) ) {
|
||||
vertexArrayFormat[vertexarray->type] = vertexarray->format;
|
||||
}
|
||||
|
||||
switch( vertexarray->type ) {
|
||||
case IQM_POSITION:
|
||||
case IQM_NORMAL:
|
||||
|
@ -279,7 +288,6 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
vertexarray->size != 4 ) {
|
||||
return qfalse;
|
||||
}
|
||||
blendIndexesType = vertexarray->format;
|
||||
break;
|
||||
case IQM_BLENDWEIGHTS:
|
||||
if( (vertexarray->format != IQM_FLOAT &&
|
||||
|
@ -287,7 +295,6 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
vertexarray->size != 4 ) {
|
||||
return qfalse;
|
||||
}
|
||||
blendWeightsType = vertexarray->format;
|
||||
break;
|
||||
case IQM_COLOR:
|
||||
if( vertexarray->format != IQM_UBYTE ||
|
||||
|
@ -298,6 +305,32 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
}
|
||||
}
|
||||
|
||||
// check for required vertex arrays
|
||||
if( vertexArrayFormat[IQM_POSITION] == -1 || vertexArrayFormat[IQM_NORMAL] == -1 || vertexArrayFormat[IQM_TEXCOORD] == -1 ) {
|
||||
ri.Printf( PRINT_WARNING, "R_LoadIQM: %s is missing IQM_POSITION, IQM_NORMAL, and/or IQM_TEXCOORD array.\n", mod_name );
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
if( header->num_joints ) {
|
||||
if( vertexArrayFormat[IQM_BLENDINDEXES] == -1 || vertexArrayFormat[IQM_BLENDWEIGHTS] == -1 ) {
|
||||
ri.Printf( PRINT_WARNING, "R_LoadIQM: %s is missing IQM_BLENDINDEXES and/or IQM_BLENDWEIGHTS array.\n", mod_name );
|
||||
return qfalse;
|
||||
}
|
||||
} else {
|
||||
// ignore blend arrays if present
|
||||
vertexArrayFormat[IQM_BLENDINDEXES] = -1;
|
||||
vertexArrayFormat[IQM_BLENDWEIGHTS] = -1;
|
||||
}
|
||||
|
||||
// opengl2 renderer requires tangents
|
||||
if( vertexArrayFormat[IQM_TANGENT] == -1 ) {
|
||||
ri.Printf( PRINT_WARNING, "R_LoadIQM: %s is missing IQM_TANGENT array.\n", mod_name );
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
// FIXME: don't require colors array when drawing
|
||||
vertexArrayFormat[IQM_COLOR] = IQM_UBYTE;
|
||||
|
||||
// check and swap triangles
|
||||
if( IQM_CheckRange( header, header->ofs_triangles,
|
||||
header->num_triangles, sizeof(iqmTriangle_t) ) ) {
|
||||
|
@ -337,16 +370,14 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
}
|
||||
|
||||
// check ioq3 limits
|
||||
if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES )
|
||||
{
|
||||
ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n",
|
||||
if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES ) {
|
||||
ri.Printf( PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n",
|
||||
mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface",
|
||||
mesh->num_vertexes );
|
||||
return qfalse;
|
||||
}
|
||||
if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES )
|
||||
{
|
||||
ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n",
|
||||
if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES ) {
|
||||
ri.Printf( PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n",
|
||||
mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface",
|
||||
mesh->num_triangles );
|
||||
return qfalse;
|
||||
|
@ -361,9 +392,10 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
return qfalse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( header->num_poses != header->num_joints && header->num_poses != 0 ) {
|
||||
ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n",
|
||||
ri.Printf( PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n",
|
||||
mod_name, header->num_poses, header->num_joints );
|
||||
return qfalse;
|
||||
}
|
||||
|
@ -460,26 +492,41 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
|
||||
// allocate the model and copy the data
|
||||
size = sizeof(iqmData_t);
|
||||
size += header->num_meshes * sizeof( srfIQModel_t );
|
||||
size += header->num_joints * 12 * sizeof( float ); // joint mats
|
||||
size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats
|
||||
if(header->ofs_bounds)
|
||||
size += header->num_frames * 6 * sizeof(float); // model bounds
|
||||
if( header->num_meshes ) {
|
||||
size += header->num_meshes * sizeof( srfIQModel_t ); // surfaces
|
||||
size += header->num_triangles * 3 * sizeof(int); // triangles
|
||||
size += header->num_vertexes * 3 * sizeof(float); // positions
|
||||
size += header->num_vertexes * 2 * sizeof(float); // texcoords
|
||||
size += header->num_vertexes * 3 * sizeof(float); // normals
|
||||
size += header->num_vertexes * 4 * sizeof(float); // tangents
|
||||
size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes
|
||||
size += header->num_vertexes * 4 * sizeof(byte); // colors
|
||||
size += header->num_joints * sizeof(int); // parents
|
||||
size += header->num_triangles * 3 * sizeof(int); // triangles
|
||||
size += joint_names; // joint names
|
||||
|
||||
// blendWeights
|
||||
if (blendWeightsType == IQM_FLOAT) {
|
||||
size += header->num_vertexes * 4 * sizeof(float);
|
||||
} else {
|
||||
size += header->num_vertexes * 4 * sizeof(byte);
|
||||
if ( vertexArrayFormat[IQM_TANGENT] != -1 ) {
|
||||
size += header->num_vertexes * 4 * sizeof(float); // tangents
|
||||
}
|
||||
|
||||
if ( vertexArrayFormat[IQM_BLENDINDEXES] != -1 ) {
|
||||
size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes
|
||||
}
|
||||
|
||||
if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_UBYTE ) {
|
||||
size += header->num_vertexes * 4 * sizeof(byte); // blendWeights
|
||||
} else if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) {
|
||||
size += header->num_vertexes * 4 * sizeof(float); // blendWeights
|
||||
}
|
||||
|
||||
if ( vertexArrayFormat[IQM_COLOR] != -1 ) {
|
||||
size += header->num_vertexes * 4 * sizeof(byte); // colors
|
||||
}
|
||||
}
|
||||
if( header->num_joints ) {
|
||||
size += joint_names; // joint names
|
||||
size += header->num_joints * sizeof(int); // joint parents
|
||||
size += header->num_joints * 12 * sizeof( float ); // joint mats
|
||||
}
|
||||
if( header->num_poses ) {
|
||||
size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats
|
||||
}
|
||||
if( header->ofs_bounds ) {
|
||||
size += header->num_frames * 6 * sizeof(float); // model bounds
|
||||
}
|
||||
|
||||
mod->type = MOD_IQM;
|
||||
|
@ -487,45 +534,186 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
mod->modelData = iqmData;
|
||||
|
||||
// fill header
|
||||
iqmData->num_vertexes = header->num_vertexes;
|
||||
iqmData->num_triangles = header->num_triangles;
|
||||
iqmData->num_vertexes = ( header->num_meshes > 0 ) ? header->num_vertexes : 0;
|
||||
iqmData->num_triangles = ( header->num_meshes > 0 ) ? header->num_triangles : 0;
|
||||
iqmData->num_frames = header->num_frames;
|
||||
iqmData->num_surfaces = header->num_meshes;
|
||||
iqmData->num_joints = header->num_joints;
|
||||
iqmData->num_poses = header->num_poses;
|
||||
iqmData->blendWeightsType = blendWeightsType;
|
||||
iqmData->surfaces = (srfIQModel_t *)(iqmData + 1);
|
||||
iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces);
|
||||
iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints;
|
||||
if(header->ofs_bounds)
|
||||
iqmData->blendWeightsType = vertexArrayFormat[IQM_BLENDWEIGHTS];
|
||||
|
||||
dataPtr = (byte*)iqmData + sizeof(iqmData_t);
|
||||
if( header->num_meshes ) {
|
||||
iqmData->surfaces = (struct srfIQModel_s*)dataPtr;
|
||||
dataPtr += header->num_meshes * sizeof( srfIQModel_t );
|
||||
|
||||
iqmData->triangles = (int*)dataPtr;
|
||||
dataPtr += header->num_triangles * 3 * sizeof(int); // triangles
|
||||
|
||||
iqmData->positions = (float*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 3 * sizeof(float); // positions
|
||||
|
||||
iqmData->texcoords = (float*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 2 * sizeof(float); // texcoords
|
||||
|
||||
iqmData->normals = (float*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 3 * sizeof(float); // normals
|
||||
|
||||
if ( vertexArrayFormat[IQM_TANGENT] != -1 ) {
|
||||
iqmData->tangents = (float*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 4 * sizeof(float); // tangents
|
||||
}
|
||||
|
||||
if ( vertexArrayFormat[IQM_BLENDINDEXES] != -1 ) {
|
||||
iqmData->blendIndexes = (byte*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 4 * sizeof(byte); // blendIndexes
|
||||
}
|
||||
|
||||
if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_UBYTE ) {
|
||||
iqmData->blendWeights.b = (byte*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 4 * sizeof(byte); // blendWeights
|
||||
} else if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) {
|
||||
iqmData->blendWeights.f = (float*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 4 * sizeof(float); // blendWeights
|
||||
}
|
||||
|
||||
if ( vertexArrayFormat[IQM_COLOR] != -1 ) {
|
||||
iqmData->colors = (byte*)dataPtr;
|
||||
dataPtr += header->num_vertexes * 4 * sizeof(byte); // colors
|
||||
}
|
||||
}
|
||||
if( header->num_joints ) {
|
||||
iqmData->jointNames = (char*)dataPtr;
|
||||
dataPtr += joint_names; // joint names
|
||||
|
||||
iqmData->jointParents = (int*)dataPtr;
|
||||
dataPtr += header->num_joints * sizeof(int); // joint parents
|
||||
|
||||
iqmData->jointMats = (float*)dataPtr;
|
||||
dataPtr += header->num_joints * 12 * sizeof( float ); // joint mats
|
||||
}
|
||||
if( header->num_poses ) {
|
||||
iqmData->poseMats = (float*)dataPtr;
|
||||
dataPtr += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats
|
||||
}
|
||||
if( header->ofs_bounds ) {
|
||||
iqmData->bounds = (float*)dataPtr;
|
||||
dataPtr += header->num_frames * 6 * sizeof(float); // model bounds
|
||||
}
|
||||
|
||||
if( header->num_meshes )
|
||||
{
|
||||
iqmData->bounds = iqmData->poseMats + 12 * header->num_poses * header->num_frames;
|
||||
iqmData->positions = iqmData->bounds + 6 * header->num_frames;
|
||||
// register shaders
|
||||
// overwrite the material offset with the shader index
|
||||
mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes);
|
||||
surface = iqmData->surfaces;
|
||||
str = (char *)header + header->ofs_text;
|
||||
for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) {
|
||||
surface->surfaceType = SF_IQM;
|
||||
Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name));
|
||||
Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster
|
||||
surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, qtrue );
|
||||
if( surface->shader->defaultShader )
|
||||
surface->shader = tr.defaultShader;
|
||||
surface->data = iqmData;
|
||||
surface->first_vertex = mesh->first_vertex;
|
||||
surface->num_vertexes = mesh->num_vertexes;
|
||||
surface->first_triangle = mesh->first_triangle;
|
||||
surface->num_triangles = mesh->num_triangles;
|
||||
}
|
||||
else
|
||||
iqmData->positions = iqmData->poseMats + 12 * header->num_poses * header->num_frames;
|
||||
iqmData->texcoords = iqmData->positions + 3 * header->num_vertexes;
|
||||
iqmData->normals = iqmData->texcoords + 2 * header->num_vertexes;
|
||||
iqmData->tangents = iqmData->normals + 3 * header->num_vertexes;
|
||||
iqmData->blendIndexes = (byte *)(iqmData->tangents + 4 * header->num_vertexes);
|
||||
|
||||
if(blendWeightsType == IQM_FLOAT) {
|
||||
iqmData->blendWeights.f = (float *)(iqmData->blendIndexes + 4 * header->num_vertexes);
|
||||
iqmData->colors = (byte *)(iqmData->blendWeights.f + 4 * header->num_vertexes);
|
||||
// copy triangles
|
||||
triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles);
|
||||
for( i = 0; i < header->num_triangles; i++, triangle++ ) {
|
||||
iqmData->triangles[3*i+0] = triangle->vertex[0];
|
||||
iqmData->triangles[3*i+1] = triangle->vertex[1];
|
||||
iqmData->triangles[3*i+2] = triangle->vertex[2];
|
||||
}
|
||||
|
||||
// copy vertexarrays and indexes
|
||||
vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays);
|
||||
for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) {
|
||||
int n;
|
||||
|
||||
// skip disabled arrays
|
||||
if( vertexarray->type < ARRAY_LEN( vertexArrayFormat )
|
||||
&& vertexArrayFormat[vertexarray->type] == -1 )
|
||||
continue;
|
||||
|
||||
// total number of values
|
||||
n = header->num_vertexes * vertexarray->size;
|
||||
|
||||
switch( vertexarray->type ) {
|
||||
case IQM_POSITION:
|
||||
Com_Memcpy( iqmData->positions,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_NORMAL:
|
||||
Com_Memcpy( iqmData->normals,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_TANGENT:
|
||||
Com_Memcpy( iqmData->tangents,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_TEXCOORD:
|
||||
Com_Memcpy( iqmData->texcoords,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_BLENDINDEXES:
|
||||
if( vertexarray->format == IQM_INT ) {
|
||||
int *data = (int*)((byte*)header + vertexarray->offset);
|
||||
for ( j = 0; j < n; j++ ) {
|
||||
iqmData->blendIndexes[j] = (byte)data[j];
|
||||
}
|
||||
} else {
|
||||
iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes;
|
||||
iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes;
|
||||
Com_Memcpy( iqmData->blendIndexes,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(byte) );
|
||||
}
|
||||
break;
|
||||
case IQM_BLENDWEIGHTS:
|
||||
if( vertexarray->format == IQM_FLOAT ) {
|
||||
Com_Memcpy( iqmData->blendWeights.f,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
} else {
|
||||
Com_Memcpy( iqmData->blendWeights.b,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(byte) );
|
||||
}
|
||||
break;
|
||||
case IQM_COLOR:
|
||||
Com_Memcpy( iqmData->colors,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(byte) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iqmData->jointParents = (int *)(iqmData->colors + 4 * header->num_vertexes);
|
||||
iqmData->triangles = iqmData->jointParents + header->num_joints;
|
||||
iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles);
|
||||
if( header->num_joints )
|
||||
{
|
||||
// copy joint names
|
||||
str = iqmData->jointNames;
|
||||
joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
|
||||
for( i = 0; i < header->num_joints; i++, joint++ ) {
|
||||
char *name = (char *)header + header->ofs_text +
|
||||
joint->name;
|
||||
int len = strlen( name ) + 1;
|
||||
Com_Memcpy( str, name, len );
|
||||
str += len;
|
||||
}
|
||||
|
||||
if ( header->num_joints == 0 )
|
||||
iqmData->jointMats = NULL;
|
||||
|
||||
if ( header->num_poses == 0 )
|
||||
iqmData->poseMats = NULL;
|
||||
// copy joint parents
|
||||
joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
|
||||
for( i = 0; i < header->num_joints; i++, joint++ ) {
|
||||
iqmData->jointParents[i] = joint->parent;
|
||||
}
|
||||
|
||||
// calculate joint matrices and their inverses
|
||||
// joint inverses are needed only until the pose matrices are calculated
|
||||
|
@ -553,7 +741,10 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
matInv += 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( header->num_poses )
|
||||
{
|
||||
// calculate pose matrices
|
||||
framedata = (unsigned short *)((byte *)header + header->ofs_frames);
|
||||
mat = iqmData->poseMats;
|
||||
|
@ -612,109 +803,6 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
|||
mat += 12;
|
||||
}
|
||||
}
|
||||
|
||||
// register shaders
|
||||
// overwrite the material offset with the shader index
|
||||
mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes);
|
||||
surface = iqmData->surfaces;
|
||||
str = (char *)header + header->ofs_text;
|
||||
for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) {
|
||||
surface->surfaceType = SF_IQM;
|
||||
Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name));
|
||||
Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster
|
||||
surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, qtrue );
|
||||
if( surface->shader->defaultShader )
|
||||
surface->shader = tr.defaultShader;
|
||||
surface->data = iqmData;
|
||||
surface->first_vertex = mesh->first_vertex;
|
||||
surface->num_vertexes = mesh->num_vertexes;
|
||||
surface->first_triangle = mesh->first_triangle;
|
||||
surface->num_triangles = mesh->num_triangles;
|
||||
}
|
||||
|
||||
// copy vertexarrays and indexes
|
||||
vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays);
|
||||
for( 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:
|
||||
Com_Memcpy( iqmData->positions,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_NORMAL:
|
||||
Com_Memcpy( iqmData->normals,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_TANGENT:
|
||||
Com_Memcpy( iqmData->tangents,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_TEXCOORD:
|
||||
Com_Memcpy( iqmData->texcoords,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
break;
|
||||
case IQM_BLENDINDEXES:
|
||||
if( blendIndexesType == IQM_INT ) {
|
||||
int *data = (int*)((byte*)header + vertexarray->offset);
|
||||
for ( j = 0; j < n; j++ ) {
|
||||
iqmData->blendIndexes[j] = (byte)data[j];
|
||||
}
|
||||
} else {
|
||||
Com_Memcpy( iqmData->blendIndexes,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(byte) );
|
||||
}
|
||||
break;
|
||||
case IQM_BLENDWEIGHTS:
|
||||
if( blendWeightsType == IQM_FLOAT ) {
|
||||
Com_Memcpy( iqmData->blendWeights.f,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(float) );
|
||||
} else {
|
||||
Com_Memcpy( iqmData->blendWeights.b,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(byte) );
|
||||
}
|
||||
break;
|
||||
case IQM_COLOR:
|
||||
Com_Memcpy( iqmData->colors,
|
||||
(byte *)header + vertexarray->offset,
|
||||
n * sizeof(byte) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// copy joint parents
|
||||
joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
|
||||
for( i = 0; i < header->num_joints; i++, joint++ ) {
|
||||
iqmData->jointParents[i] = joint->parent;
|
||||
}
|
||||
|
||||
// copy triangles
|
||||
triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles);
|
||||
for( i = 0; i < header->num_triangles; i++, triangle++ ) {
|
||||
iqmData->triangles[3*i+0] = triangle->vertex[0];
|
||||
iqmData->triangles[3*i+1] = triangle->vertex[1];
|
||||
iqmData->triangles[3*i+2] = triangle->vertex[2];
|
||||
}
|
||||
|
||||
// copy joint names
|
||||
str = iqmData->names;
|
||||
joint = (iqmJoint_t *)((byte *)header + header->ofs_joints);
|
||||
for( i = 0; i < header->num_joints; i++, joint++ ) {
|
||||
char *name = (char *)header + header->ofs_text +
|
||||
joint->name;
|
||||
int len = strlen( name ) + 1;
|
||||
Com_Memcpy( str, name, len );
|
||||
str += len;
|
||||
}
|
||||
|
||||
// copy model bounds
|
||||
|
@ -1161,7 +1249,7 @@ int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
|
|||
float frac, const char *tagName ) {
|
||||
float jointMats[IQM_MAX_JOINTS * 12];
|
||||
int joint;
|
||||
char *names = data->names;
|
||||
char *names = data->jointNames;
|
||||
|
||||
// get joint number by reading the joint names
|
||||
for( joint = 0; joint < data->num_joints; joint++ ) {
|
||||
|
|
Loading…
Reference in a new issue