diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/renderergl1/tr_local.h | 10 | ||||
-rw-r--r-- | src/renderergl1/tr_model_iqm.c | 88 | ||||
-rw-r--r-- | src/renderergl2/tr_local.h | 10 | ||||
-rw-r--r-- | src/renderergl2/tr_model_iqm.c | 88 |
4 files changed, 150 insertions, 46 deletions
diff --git a/src/renderergl1/tr_local.h b/src/renderergl1/tr_local.h index 96fa6445..59058eaf 100644 --- a/src/renderergl1/tr_local.h +++ b/src/renderergl1/tr_local.h @@ -619,10 +619,18 @@ typedef struct { float *normals; float *tangents; byte *blendIndexes; - byte *blendWeights; + union { + float *f; + 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_BYTE or IQM_FLOAT + int *jointParents; float *jointMats; float *poseMats; diff --git a/src/renderergl1/tr_model_iqm.c b/src/renderergl1/tr_model_iqm.c index 1340c7ae..0636bb46 100644 --- a/src/renderergl1/tr_model_iqm.c +++ b/src/renderergl1/tr_model_iqm.c @@ -151,6 +151,7 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na iqmData_t *iqmData; srfIQModel_t *surface; char meshName[MAX_QPATH]; + byte blendIndexesType, blendWeightsType; if( filesize < sizeof(iqmHeader_t) ) { return qfalse; @@ -272,11 +273,20 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na } break; case IQM_BLENDINDEXES: + if( (vertexarray->format != IQM_INT && + vertexarray->format != IQM_UBYTE) || + vertexarray->size != 4 ) { + return qfalse; + } + blendIndexesType = vertexarray->format; + break; case IQM_BLENDWEIGHTS: - if( vertexarray->format != IQM_UBYTE || + if( (vertexarray->format != IQM_FLOAT && + vertexarray->format != IQM_UBYTE) || vertexarray->size != 4 ) { return qfalse; } + blendWeightsType = vertexarray->format; break; case IQM_COLOR: if( vertexarray->format != IQM_UBYTE || @@ -459,12 +469,18 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na 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); // blendWeights 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); + } + mod->type = MOD_IQM; iqmData = (iqmData_t *)ri.Hunk_Alloc( size, h_low ); mod->modelData = iqmData; @@ -476,6 +492,7 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na 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; @@ -490,8 +507,15 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na 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); - iqmData->blendWeights = iqmData->blendIndexes + 4 * header->num_vertexes; - iqmData->colors = iqmData->blendWeights + 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); + } else { + iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes; + iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes; + } + 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); @@ -637,14 +661,28 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na n * sizeof(float) ); break; case IQM_BLENDINDEXES: - Com_Memcpy( iqmData->blendIndexes, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); + if( blendIndexesType == IQM_INT ) { + int *data = (int*)((byte*)header + vertexarray->offset); + for ( j = 0; j < n; j++ ) { + iqmData->blendIndexes[j] = (byte)LittleLong( data[j] ); + } + } else { + Com_Memcpy( iqmData->blendIndexes, + (byte *)header + vertexarray->offset, + n * sizeof(byte) ); + } break; case IQM_BLENDWEIGHTS: - Com_Memcpy( iqmData->blendWeights, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); + if( blendWeightsType == IQM_FLOAT ) { + float *data = (float*)((byte*)header + vertexarray->offset); + for ( j = 0; j < n; j++ ) { + iqmData->blendWeights.f[j] = LittleFloat( data[j] ); + } + } else { + Com_Memcpy( iqmData->blendWeights.b, + (byte *)header + vertexarray->offset, + n * sizeof(byte) ); + } break; case IQM_COLOR: Com_Memcpy( iqmData->colors, @@ -1014,25 +1052,31 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { float vtxMat[12]; float nrmMat[9]; int vtx = i + surf->first_vertex; + float blendWeights[4]; + int numWeights; - if ( data->num_poses == 0 || data->blendWeights[4*vtx] <= 0 ) { + for ( numWeights = 0; numWeights < 4; numWeights++ ) { + if ( data->blendWeightsType == IQM_FLOAT ) + blendWeights[numWeights] = data->blendWeights.f[4*vtx + numWeights]; + else // IQM_BYTE + blendWeights[numWeights] = (float)data->blendWeights.b[4*vtx + numWeights] / 255.0f; + + if ( blendWeights[numWeights] <= 0 ) + break; + } + + if ( data->num_poses == 0 || numWeights == 0 ) { // no blend joint, use identity matrix. Com_Memcpy( vtxMat, identityMatrix, 12 * sizeof (float) ); } else { // compute the vertex matrix by blending the up to // four blend weights - for( k = 0; k < 12; k++ ) - vtxMat[k] = data->blendWeights[4*vtx] - * jointMats[12*data->blendIndexes[4*vtx] + k]; - for( j = 1; j < 4; j++ ) { - if( data->blendWeights[4*vtx + j] <= 0 ) - break; - for( k = 0; k < 12; k++ ) - vtxMat[k] += data->blendWeights[4*vtx + j] - * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + Com_Memset( vtxMat, 0, 12 * sizeof (float) ); + for( j = 0; j < numWeights; j++ ) { + for( k = 0; k < 12; k++ ) { + vtxMat[k] += blendWeights[j] * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + } } - for( k = 0; k < 12; k++ ) - vtxMat[k] *= 1.0f / 255.0f; } // compute the normal matrix as transpose of the adjoint diff --git a/src/renderergl2/tr_local.h b/src/renderergl2/tr_local.h index 75b44a11..05662f99 100644 --- a/src/renderergl2/tr_local.h +++ b/src/renderergl2/tr_local.h @@ -1095,10 +1095,18 @@ typedef struct { float *normals; float *tangents; byte *blendIndexes; - byte *blendWeights; + union { + float *f; + 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_BYTE or IQM_FLOAT + int *jointParents; float *jointMats; float *poseMats; diff --git a/src/renderergl2/tr_model_iqm.c b/src/renderergl2/tr_model_iqm.c index 382f76e0..3086293d 100644 --- a/src/renderergl2/tr_model_iqm.c +++ b/src/renderergl2/tr_model_iqm.c @@ -150,6 +150,7 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na iqmData_t *iqmData; srfIQModel_t *surface; char meshName[MAX_QPATH]; + byte blendIndexesType, blendWeightsType; if( filesize < sizeof(iqmHeader_t) ) { return qfalse; @@ -271,11 +272,20 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na } break; case IQM_BLENDINDEXES: + if( (vertexarray->format != IQM_INT && + vertexarray->format != IQM_UBYTE) || + vertexarray->size != 4 ) { + return qfalse; + } + blendIndexesType = vertexarray->format; + break; case IQM_BLENDWEIGHTS: - if( vertexarray->format != IQM_UBYTE || + if( (vertexarray->format != IQM_FLOAT && + vertexarray->format != IQM_UBYTE) || vertexarray->size != 4 ) { return qfalse; } + blendWeightsType = vertexarray->format; break; case IQM_COLOR: if( vertexarray->format != IQM_UBYTE || @@ -458,12 +468,18 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na 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); // blendWeights 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); + } + mod->type = MOD_IQM; iqmData = (iqmData_t *)ri.Hunk_Alloc( size, h_low ); mod->modelData = iqmData; @@ -475,6 +491,7 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na 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; @@ -489,8 +506,15 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na 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); - iqmData->blendWeights = iqmData->blendIndexes + 4 * header->num_vertexes; - iqmData->colors = iqmData->blendWeights + 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); + } else { + iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes; + iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes; + } + 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); @@ -636,14 +660,28 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na n * sizeof(float) ); break; case IQM_BLENDINDEXES: - Com_Memcpy( iqmData->blendIndexes, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); + if( blendIndexesType == IQM_INT ) { + int *data = (int*)((byte*)header + vertexarray->offset); + for ( j = 0; j < n; j++ ) { + iqmData->blendIndexes[j] = (byte)LittleLong( data[j] ); + } + } else { + Com_Memcpy( iqmData->blendIndexes, + (byte *)header + vertexarray->offset, + n * sizeof(byte) ); + } break; case IQM_BLENDWEIGHTS: - Com_Memcpy( iqmData->blendWeights, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); + if( blendWeightsType == IQM_FLOAT ) { + float *data = (float*)((byte*)header + vertexarray->offset); + for ( j = 0; j < n; j++ ) { + iqmData->blendWeights.f[j] = LittleFloat( data[j] ); + } + } else { + Com_Memcpy( iqmData->blendWeights.b, + (byte *)header + vertexarray->offset, + n * sizeof(byte) ); + } break; case IQM_COLOR: Com_Memcpy( iqmData->colors, @@ -1016,25 +1054,31 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { float vtxMat[12]; float nrmMat[9]; int vtx = i + surf->first_vertex; + float blendWeights[4]; + int numWeights; - if ( data->num_poses == 0 || data->blendWeights[4*vtx] <= 0 ) { + for ( numWeights = 0; numWeights < 4; numWeights++ ) { + if ( data->blendWeightsType == IQM_FLOAT ) + blendWeights[numWeights] = data->blendWeights.f[4*vtx + numWeights]; + else // IQM_BYTE + blendWeights[numWeights] = (float)data->blendWeights.b[4*vtx + numWeights] / 255.0f; + + if ( blendWeights[numWeights] <= 0 ) + break; + } + + if ( data->num_poses == 0 || numWeights == 0 ) { // no blend joint, use identity matrix. Com_Memcpy( vtxMat, identityMatrix, 12 * sizeof (float) ); } else { // compute the vertex matrix by blending the up to // four blend weights - for( k = 0; k < 12; k++ ) - vtxMat[k] = data->blendWeights[4*vtx] - * jointMats[12*data->blendIndexes[4*vtx] + k]; - for( j = 1; j < 4; j++ ) { - if( data->blendWeights[4*vtx + j] <= 0 ) - break; - for( k = 0; k < 12; k++ ) - vtxMat[k] += data->blendWeights[4*vtx + j] - * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + Com_Memset( vtxMat, 0, 12 * sizeof (float) ); + for( j = 0; j < numWeights; j++ ) { + for( k = 0; k < 12; k++ ) { + vtxMat[k] += blendWeights[j] * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + } } - for( k = 0; k < 12; k++ ) - vtxMat[k] *= 1.0f / 255.0f; } // compute the normal matrix as transpose of the adjoint |