static void RagdollAddConstraint( IPhysicsEnvironment *pPhysEnv, ragdoll_t &ragdoll, const ragdollparams_t ¶ms, constraint_ragdollparams_t &constraint ) { if( constraint.childIndex == constraint.parentIndex ) { DevMsg( 1, "Bogus constraint on ragdoll %s\n", params.pStudioHdr->pszName() ); constraint.childIndex = -1; constraint.parentIndex = -1; } if ( constraint.childIndex >= 0 && constraint.parentIndex >= 0 ) { Assert(constraint.childIndex<ragdoll.listCount); ragdollelement_t &childElement = ragdoll.list[constraint.childIndex]; // save parent index childElement.parentIndex = constraint.parentIndex; if ( params.jointFrictionScale > 0 ) { for ( int k = 0; k < 3; k++ ) { constraint.axes[k].torque *= params.jointFrictionScale; } } // this parent/child pair is not usually a parent/child pair in the skeleton. There // are often bones in between that are collapsed for simulation. So we need to compute // the transform. Studio_CalcBoneToBoneTransform( params.pStudioHdr, ragdoll.boneIndex[constraint.childIndex], ragdoll.boneIndex[constraint.parentIndex], constraint.constraintToAttached ); MatrixGetColumn( constraint.constraintToAttached, 3, childElement.originParentSpace ); // UNDONE: We could transform the constraint limit axes relative to the bone space // using this data. Do we need that feature? SetIdentityMatrix( constraint.constraintToReference ); childElement.pConstraint = pPhysEnv->CreateRagdollConstraint( childElement.pObject, ragdoll.list[constraint.parentIndex].pObject, ragdoll.pGroup, constraint ); } }
void CStudioPhysics::Load( MDLHandle_t mdlHandle ) { m_MDLHandle = mdlHandle; LoadPhysicsProperties(); vcollide_t *pVCollide = GetVCollide( ); if ( !pVCollide ) { m_pList = NULL; m_listCount = 0; return; } m_pList = new CPhysmesh[pVCollide->solidCount]; m_listCount = pVCollide->solidCount; int i; for ( i = 0; i < pVCollide->solidCount; i++ ) { m_pList[i].Clear(); m_pList[i].m_vertCount = physcollision->CreateDebugMesh( pVCollide->solids[i], &m_pList[i].m_pVerts ); m_pList[i].m_pCollisionModel = physcollision->CreateQueryModel( pVCollide->solids[i] ); } ParseKeydata(); CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( mdlHandle ), g_pMDLCache ); for ( i = 0; i < pVCollide->solidCount; i++ ) { CPhysmesh *pmesh = m_pList + i; int boneIndex = FindBoneIndex( &studioHdr, pmesh->m_boneName ); if ( boneIndex < 0 ) continue; if ( pmesh->m_constraint.parentIndex >= 0 ) { CPhysmesh *pparent = m_pList + pmesh->m_constraint.parentIndex; int parentIndex = FindBoneIndex( &studioHdr, pparent->m_boneName ); Studio_CalcBoneToBoneTransform( &studioHdr, boneIndex, parentIndex, pmesh->m_matrix ); } else { MatrixInvert( studioHdr.pBone(boneIndex)->poseToBone, pmesh->m_matrix ); } } // doesn't have a root bone? Make it the first bone if ( !m_edit.rootName[0] ) { strcpy( m_edit.rootName, m_pList[0].m_boneName ); } }
Vector GetAttachmentPositionInSpaceOfBone( CStudioHdr *pStudioHdr, const char *pAttachmentName, int outputBoneIndex ) { if( !pStudioHdr || !pAttachmentName ) return vec3_origin; int attachment = Studio_FindAttachment( pStudioHdr, pAttachmentName ); Vector localAttach; const mstudioattachment_t &pAttachment = pStudioHdr->pAttachment(attachment); int iBone = pStudioHdr->GetAttachmentBone( attachment ); MatrixGetColumn( pAttachment.local, 3, localAttach ); matrix3x4_t inputToOutputBone; Studio_CalcBoneToBoneTransform( pStudioHdr, iBone, outputBoneIndex, inputToOutputBone ); Vector out; VectorTransform( localAttach, inputToOutputBone, out ); return out; }
static void RagdollCreateObjects( IPhysicsCollision *pPhysCollision, IPhysicsEnvironment *pPhysEnv, IPhysicsSurfaceProps *pSurfaceDatabase, ragdoll_t &ragdoll, const ragdollparams_t ¶ms ) { ragdoll.listCount = 0; ragdoll.pGroup = NULL; memset( ragdoll.list, 0, sizeof(ragdoll.list) ); if ( !params.pCollide || params.pCollide->solidCount > RAGDOLL_MAX_ELEMENTS ) return; IVPhysicsKeyParser *pParse = pPhysCollision->VPhysicsKeyParserCreate( params.pCollide->pKeyValues ); ragdoll.pGroup = pPhysEnv->CreateConstraintGroup(); while ( !pParse->Finished() ) { const char *pBlock = pParse->GetCurrentBlockName(); if ( !strcmpi( pBlock, "solid" ) ) { solid_t solid; // collisions off by default pParse->ParseSolid( &solid, NULL ); if ( solid.index >= 0 && solid.index < params.pCollide->solidCount) { Assert( ragdoll.listCount == solid.index ); int boneIndex = Studio_BoneIndexByName( params.pStudioHdr, solid.name ); ragdoll.boneIndex[ragdoll.listCount] = boneIndex; if ( boneIndex >= 0 ) { solid.params.rotInertiaLimit = 0.5; solid.params.pGameData = params.pGameData; int surfaceData = pSurfaceDatabase->GetSurfaceIndex( solid.surfaceprop ); if ( surfaceData < 0 ) surfaceData = pSurfaceDatabase->GetSurfaceIndex( "default" ); solid.params.pName = params.pStudioHdr->name; ragdoll.list[ragdoll.listCount].pObject = pPhysEnv->CreatePolyObject( params.pCollide->solids[solid.index], surfaceData, vec3_origin, vec3_angle, &solid.params ); ragdoll.list[ragdoll.listCount].pObject->SetPositionMatrix( params.pCurrentBones[boneIndex], true ); ragdoll.list[ragdoll.listCount].parentIndex = -1; ragdoll.listCount++; } else { Msg( "CRagdollProp::CreateObjects: Couldn't Lookup Bone %s\n", solid.name ); } } } else if ( !strcmpi( pBlock, "ragdollconstraint" ) ) { constraint_ragdollparams_t constraint; pParse->ParseRagdollConstraint( &constraint, NULL ); if ( constraint.childIndex >= 0 && constraint.parentIndex >= 0 ) { Assert(constraint.childIndex<ragdoll.listCount); ragdollelement_t &childElement = ragdoll.list[constraint.childIndex]; // save parent index childElement.parentIndex = constraint.parentIndex; if ( params.jointFrictionScale > 0 ) { for ( int k = 0; k < 3; k++ ) { constraint.axes[k].torque *= params.jointFrictionScale; } } // this parent/child pair is not usually a parent/child pair in the skeleton. There // are often bones in between that are collapsed for simulation. So we need to compute // the transform. Studio_CalcBoneToBoneTransform( params.pStudioHdr, ragdoll.boneIndex[constraint.childIndex], ragdoll.boneIndex[constraint.parentIndex], constraint.constraintToAttached ); MatrixGetColumn( constraint.constraintToAttached, 3, childElement.originParentSpace ); // UNDONE: We could transform the constraint limit axes relative to the bone space // using this data. Do we need that feature? SetIdentityMatrix( constraint.constraintToReference ); pPhysEnv->DisableCollisions( ragdoll.list[constraint.parentIndex].pObject, childElement.pObject ); childElement.pConstraint = pPhysEnv->CreateRagdollConstraint( childElement.pObject, ragdoll.list[constraint.parentIndex].pObject, ragdoll.pGroup, constraint ); } } else { pParse->SkipBlock(); } } pPhysCollision->VPhysicsKeyParserDestroy( pParse ); }
static cache_ragdoll_t *ParseRagdollIntoCache( CStudioHdr *pStudioHdr, vcollide_t *pCollide, int modelIndex ) { IVPhysicsKeyParser *pParse = physcollision->VPhysicsKeyParserCreate( pCollide ); cache_ragdollsolid_t solidList[RAGDOLL_MAX_ELEMENTS]; cache_ragdollconstraint_t constraintList[RAGDOLL_MAX_ELEMENTS]; solid_t solid; int constraintCount = 0; int solidCount = 0; cache_ragdoll_t cache; V_memset( &cache, 0, sizeof(cache) ); while ( !pParse->Finished() ) { const char *pBlock = pParse->GetCurrentBlockName(); if ( !strcmpi( pBlock, "solid" ) ) { pParse->ParseSolid( &solid, &g_SolidSetup ); cache_ragdollsolid_t *pSolid = &solidList[solidCount]; pSolid->boneIndex = Studio_BoneIndexByName( pStudioHdr, solid.name ); if ( pSolid->boneIndex >= 0 ) { pSolid->collideIndex = solid.index; pSolid->surfacePropIndex = physprops->GetSurfaceIndex( solid.surfaceprop ); if ( pSolid->surfacePropIndex < 0 ) { pSolid->surfacePropIndex = physprops->GetSurfaceIndex( "default" ); } pSolid->params = solid.params; pSolid->params.enableCollisions = false; solidCount++; } else { Msg( "ParseRagdollIntoCache: Couldn't Lookup Bone %s\n", solid.name ); } } else if ( !strcmpi( pBlock, "ragdollconstraint" ) ) { constraint_ragdollparams_t constraint; pParse->ParseRagdollConstraint( &constraint, NULL ); if( constraint.childIndex != constraint.parentIndex && constraint.childIndex >= 0 && constraint.parentIndex >= 0) { cache_ragdollconstraint_t *pOut = &constraintList[constraintCount]; constraintCount++; V_memcpy( pOut->axes, constraint.axes, sizeof(constraint.axes) ); pOut->parentIndex = constraint.parentIndex; pOut->childIndex = constraint.childIndex; Studio_CalcBoneToBoneTransform( pStudioHdr, solidList[constraint.childIndex].boneIndex, solidList[constraint.parentIndex].boneIndex, pOut->constraintToAttached ); } } else if ( !strcmpi( pBlock, "collisionrules" ) ) { ragdollcollisionrules_t rules; IPhysicsCollisionSet *pSet = physics->FindOrCreateCollisionSet( modelIndex, pCollide->solidCount ); rules.Defaults(physics, pSet); pParse->ParseCollisionRules( &rules, NULL ); cache.pCollisionSet = rules.pCollisionSet; } else if ( !strcmpi( pBlock, "animatedfriction") ) { pParse->ParseRagdollAnimatedFriction( &cache.animfriction, NULL ); } else { pParse->SkipBlock(); } } physcollision->VPhysicsKeyParserDestroy( pParse ); cache.solidCount = solidCount; cache.constraintCount = constraintCount; return CreateRagdollCache( pCollide, solidList, constraintList, &cache ); }