From c551aefd77b72993328225d600b6160e55648b1e Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:05:23 +0500 Subject: [PATCH] utils: mdldec: add boneweights support. --- utils/mdldec/qc.c | 11 ++++- utils/mdldec/smd.c | 121 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 107 insertions(+), 25 deletions(-) diff --git a/utils/mdldec/qc.c b/utils/mdldec/qc.c index b3da410b..6ac563d1 100644 --- a/utils/mdldec/qc.c +++ b/utils/mdldec/qc.c @@ -513,12 +513,15 @@ static void WriteSequenceInfo( FILE *fp ) } } - if( seqdesc->blendtype[0] ) + if( seqdesc->numblends > 1 ) { GetMotionTypeString( seqdesc->blendtype[0], motion_types, sizeof( motion_types ), false ); fprintf( fp, "\tblend %s %.0f %.0f\n", motion_types, seqdesc->blendstart[0], seqdesc->blendend[0] ); + + if( !seqdesc->blendtype[0] ) + printf( "WARNING: Something wrong with blending type for sequence: %s\n", seqdesc->label ); } for( j = 0; j < seqdesc->numevents; j++ ) @@ -613,7 +616,7 @@ void WriteQCScript( void ) WriteBodyGroupInfo( fp ); - fprintf( fp, "$flags %i\n\n", model_hdr->flags ); + fprintf( fp, "$flags %u\n\n", model_hdr->flags &~( STUDIO_HAS_BONEINFO | STUDIO_HAS_BONEWEIGHTS ) ); fprintf( fp, "$eyeposition %f %f %f\n\n", model_hdr->eyeposition[0], model_hdr->eyeposition[1], model_hdr->eyeposition[2] ); if( !model_hdr->numtextures ) @@ -621,6 +624,10 @@ void WriteQCScript( void ) WriteSkinFamilyInfo( fp ); WriteTextureRenderMode( fp ); + + if( model_hdr->flags & ( STUDIO_HAS_BONEINFO | STUDIO_HAS_BONEWEIGHTS ) ) + fputs( "$boneweights\n\n", fp ); + WriteAttachmentInfo( fp ); fprintf( fp, "$bbox %f %f %f", model_hdr->min[0], model_hdr->min[1], model_hdr->min[2] ); diff --git a/utils/mdldec/smd.c b/utils/mdldec/smd.c index 9c3b4a5b..d1ad5875 100644 --- a/utils/mdldec/smd.c +++ b/utils/mdldec/smd.c @@ -25,17 +25,18 @@ GNU General Public License for more details. #include "smd.h" static matrix3x4 *bonetransform; +static matrix3x4 *worldtransform; /* ============ CreateBoneTransformMatrices ============ */ -static qboolean CreateBoneTransformMatrices( void ) +static qboolean CreateBoneTransformMatrices( matrix3x4 **matrix ) { - bonetransform = calloc( model_hdr->numbones, sizeof( matrix3x4 ) ); + *matrix = calloc( model_hdr->numbones, sizeof( matrix3x4 ) ); - if( !bonetransform ) + if( !*matrix ) { fputs( "ERROR: Couldn't allocate memory for bone transformation matrices!\n", stderr ); return false; @@ -73,14 +74,28 @@ static void FillBoneTransformMatrices( void ) } } +/* +============ +FillWorldTransformMatrices +============ +*/ +static void FillWorldTransformMatrices( void ) +{ + int i; + mstudioboneinfo_t *boneinfo = (mstudioboneinfo_t *)( (byte *)model_hdr + model_hdr->boneindex + model_hdr->numbones * sizeof( mstudiobone_t ) ); + + for( i = 0; i < model_hdr->numbones; i++, boneinfo++ ) + Matrix3x4_ConcatTransforms( worldtransform[i], bonetransform[i], boneinfo->poseToBone ); +} + /* ============ RemoveBoneTransformMatrices ============ */ -static void RemoveBoneTransformMatrices( void ) +static void RemoveBoneTransformMatrices( matrix3x4 **matrix ) { - free( bonetransform ); + free( *matrix ); } /* @@ -220,15 +235,19 @@ WriteTriangleInfo */ static void WriteTriangleInfo( FILE *fp, mstudiomodel_t *model, mstudiotexture_t *texture, mstudiotrivert_t **triverts, qboolean isevenstrip ) { - int i, indices[3]; - int vert_index; - int norm_index; - int bone_index; - float s, t, u, v; - byte *vertbone; - vec3_t *studioverts; - vec3_t *studionorms; - vec3_t vert, norm; + int i, j, k, l, indices[3]; + int vert_index; + int norm_index; + int bone_index; + int valid_bones; + float s, t, u, v; + byte *vertbone; + vec3_t *studioverts; + vec3_t *studionorms; + vec3_t vert, norm; + float weights[MAXSTUDIOBONEWEIGHTS], oldweight, totalweight; + matrix3x4 bonematrix[MAXSTUDIOBONEWEIGHTS], skinmatrix, *pskinmatrix; + mstudioboneweight_t *studioboneweights; if( isevenstrip ) { @@ -246,6 +265,7 @@ static void WriteTriangleInfo( FILE *fp, mstudiomodel_t *model, mstudiotexture_t vertbone = ( (byte *)model_hdr + model->vertinfoindex ); studioverts = (vec3_t *)( (byte *)model_hdr + model->vertindex ); studionorms = (vec3_t *)( (byte *)model_hdr + model->normindex ); + studioboneweights = (mstudioboneweight_t *)( (byte *)model_hdr + model->blendvertinfoindex ); s = 1.0f / texture->width; t = 1.0f / texture->height; @@ -258,8 +278,39 @@ static void WriteTriangleInfo( FILE *fp, mstudiomodel_t *model, mstudiotexture_t norm_index = triverts[indices[i]]->normindex; bone_index = vertbone[vert_index]; - Matrix3x4_VectorTransform( bonetransform[bone_index], studioverts[vert_index], vert ); - Matrix3x4_VectorRotate( bonetransform[bone_index], studionorms[norm_index], norm ); + if( model_hdr->flags & STUDIO_HAS_BONEWEIGHTS ) + { + valid_bones = 0, totalweight = 0; + memset(skinmatrix, 0, sizeof(matrix3x4)); + + for( j = 0; j < MAXSTUDIOBONEWEIGHTS; ++j ) + if( studioboneweights[vert_index].bone[j] != -1 ) + valid_bones++; + + for( j = 0; j < valid_bones; ++j ) + { + Matrix3x4_Copy( bonematrix[j], worldtransform[studioboneweights[vert_index].bone[j]] ); + weights[j] = studioboneweights[vert_index].weight[j] / 255.0f; + totalweight += weights[j]; + } + + oldweight = weights[0]; + + if( totalweight < 1.0f ) + weights[0] += 1.0f - totalweight; + + for( j = 0; j < valid_bones; ++j ) + for( k = 0; k < 3; ++k ) + for( l = 0; l < 4; ++l ) + skinmatrix[k][l] += bonematrix[j][k][l] * weights[j]; + + pskinmatrix = &skinmatrix; + } + else + pskinmatrix = &bonetransform[bone_index]; + + Matrix3x4_VectorTransform( *pskinmatrix, studioverts[vert_index], vert ); + Matrix3x4_VectorRotate( *pskinmatrix, studionorms[norm_index], norm ); VectorNormalize( norm ); if( texture->flags & STUDIO_NF_UV_COORDS ) @@ -273,11 +324,25 @@ static void WriteTriangleInfo( FILE *fp, mstudiomodel_t *model, mstudiotexture_t v = 1.0f - triverts[indices[i]]->t * t; } - fprintf( fp, "%3i %f %f %f %f %f %f %f %f\n", + fprintf( fp, "%3i %f %f %f %f %f %f %f %f", bone_index, vert[0], vert[1], vert[2], norm[0], norm[1], norm[2], u, v ); + + if( model_hdr->flags & STUDIO_HAS_BONEWEIGHTS ) + { + fprintf( fp, " %d", valid_bones ); + + weights[0] = oldweight; + + for( j = 0; j < valid_bones; ++j ) + fprintf( fp, " %d %f", + studioboneweights[vert_index].bone[j], + weights[j] ); + } + + fputs( "\n", fp ); } } @@ -451,11 +516,19 @@ static void WriteReferences( void ) char name[64]; char filename[MAX_SYSPATH]; - if( !CreateBoneTransformMatrices() ) + if( !CreateBoneTransformMatrices( &bonetransform ) ) return; FillBoneTransformMatrices(); + if( model_hdr->flags & STUDIO_HAS_BONEINFO ) + { + if( !CreateBoneTransformMatrices( &worldtransform ) ) + return; + + FillWorldTransformMatrices(); + } + for( i = 0; i < model_hdr->numbodyparts; i++ ) { bodypart = (mstudiobodyparts_t *)( (byte *)model_hdr + model_hdr->bodypartindex ) + i; @@ -474,8 +547,7 @@ static void WriteReferences( void ) if( len == -1 ) { fprintf( stderr, "ERROR: Destination path is too long. Can't write %s.smd\n", name ); - RemoveBoneTransformMatrices(); - return; + goto _fail; } fp = fopen( filename, "w" ); @@ -483,8 +555,7 @@ static void WriteReferences( void ) if( !fp ) { fprintf( stderr, "ERROR: Can't write %s\n", filename ); - RemoveBoneTransformMatrices(); - return; + goto _fail; } fputs( "version 1\n", fp ); @@ -499,7 +570,11 @@ static void WriteReferences( void ) } } - RemoveBoneTransformMatrices(); +_fail: + RemoveBoneTransformMatrices( &bonetransform ); + + if( model_hdr->flags & STUDIO_HAS_BONEINFO ) + RemoveBoneTransformMatrices( &worldtransform ); } /*