/* ============== RE_BlendSkeleton ============== */ int RE_BlendSkeleton(refSkeleton_t * skel, const refSkeleton_t * blend, float frac) { int i; vec3_t lerpedOrigin; quat_t lerpedQuat; vec3_t bounds[2]; if(skel->numBones != blend->numBones) { ri.Printf(PRINT_WARNING, "RE_BlendSkeleton: different number of bones %d != %d\n", skel->numBones, blend->numBones); return qfalse; } // lerp between the 2 bone poses for(i = 0; i < skel->numBones; i++) { VectorLerp(skel->bones[i].origin, blend->bones[i].origin, frac, lerpedOrigin); QuatSlerp(skel->bones[i].rotation, blend->bones[i].rotation, frac, lerpedQuat); VectorCopy(lerpedOrigin, skel->bones[i].origin); QuatCopy(lerpedQuat, skel->bones[i].rotation); } // calculate a bounding box in the current coordinate system for(i = 0; i < 3; i++) { bounds[0][i] = skel->bounds[0][i] < blend->bounds[0][i] ? skel->bounds[0][i] : blend->bounds[0][i]; bounds[1][i] = skel->bounds[1][i] > blend->bounds[1][i] ? skel->bounds[1][i] : blend->bounds[1][i]; } VectorCopy(bounds[0], skel->bounds[0]); VectorCopy(bounds[1], skel->bounds[1]); return qtrue; }
/* ============== RE_BuildSkeleton ============== */ int RE_BuildSkeleton( refSkeleton_t *skel, qhandle_t hAnim, int startFrame, int endFrame, float frac, bool clearOrigin ) { skelAnimation_t *skelAnim; skelAnim = R_GetAnimationByHandle( hAnim ); if ( skelAnim->type == animType_t::AT_IQM && skelAnim->iqm ) { return IQMBuildSkeleton( skel, skelAnim, startFrame, endFrame, frac ); } else if ( skelAnim->type == animType_t::AT_MD5 && skelAnim->md5 ) { int i; md5Animation_t *anim; md5Channel_t *channel; md5Frame_t *newFrame, *oldFrame; vec3_t newOrigin, oldOrigin, lerpedOrigin; quat_t newQuat, oldQuat, lerpedQuat; int componentsApplied; anim = skelAnim->md5; // Validate the frames so there is no chance of a crash. // This will write directly into the entity structure, so // when the surfaces are rendered, they don't need to be // range checked again. /* if((startFrame >= anim->numFrames) || (startFrame < 0) || (endFrame >= anim->numFrames) || (endFrame < 0)) { Log::Debug("RE_BuildSkeleton: no such frame %d to %d for '%s'\n", startFrame, endFrame, anim->name); //startFrame = 0; //endFrame = 0; } */ startFrame = Math::Clamp( startFrame, 0, anim->numFrames - 1 ); endFrame = Math::Clamp( endFrame, 0, anim->numFrames - 1 ); // compute frame pointers oldFrame = &anim->frames[ startFrame ]; newFrame = &anim->frames[ endFrame ]; // calculate a bounding box in the current coordinate system for ( i = 0; i < 3; i++ ) { skel->bounds[ 0 ][ i ] = oldFrame->bounds[ 0 ][ i ] < newFrame->bounds[ 0 ][ i ] ? oldFrame->bounds[ 0 ][ i ] : newFrame->bounds[ 0 ][ i ]; skel->bounds[ 1 ][ i ] = oldFrame->bounds[ 1 ][ i ] > newFrame->bounds[ 1 ][ i ] ? oldFrame->bounds[ 1 ][ i ] : newFrame->bounds[ 1 ][ i ]; } for ( i = 0, channel = anim->channels; i < anim->numChannels; i++, channel++ ) { // set baseframe values VectorCopy( channel->baseOrigin, newOrigin ); VectorCopy( channel->baseOrigin, oldOrigin ); QuatCopy( channel->baseQuat, newQuat ); QuatCopy( channel->baseQuat, oldQuat ); componentsApplied = 0; // update tranlation bits if ( channel->componentsBits & COMPONENT_BIT_TX ) { oldOrigin[ 0 ] = oldFrame->components[ channel->componentsOffset + componentsApplied ]; newOrigin[ 0 ] = newFrame->components[ channel->componentsOffset + componentsApplied ]; componentsApplied++; } if ( channel->componentsBits & COMPONENT_BIT_TY ) { oldOrigin[ 1 ] = oldFrame->components[ channel->componentsOffset + componentsApplied ]; newOrigin[ 1 ] = newFrame->components[ channel->componentsOffset + componentsApplied ]; componentsApplied++; } if ( channel->componentsBits & COMPONENT_BIT_TZ ) { oldOrigin[ 2 ] = oldFrame->components[ channel->componentsOffset + componentsApplied ]; newOrigin[ 2 ] = newFrame->components[ channel->componentsOffset + componentsApplied ]; componentsApplied++; } // update quaternion rotation bits if ( channel->componentsBits & COMPONENT_BIT_QX ) { ( ( vec_t * ) oldQuat ) [ 0 ] = oldFrame->components[ channel->componentsOffset + componentsApplied ]; ( ( vec_t * ) newQuat ) [ 0 ] = newFrame->components[ channel->componentsOffset + componentsApplied ]; componentsApplied++; } if ( channel->componentsBits & COMPONENT_BIT_QY ) { ( ( vec_t * ) oldQuat ) [ 1 ] = oldFrame->components[ channel->componentsOffset + componentsApplied ]; ( ( vec_t * ) newQuat ) [ 1 ] = newFrame->components[ channel->componentsOffset + componentsApplied ]; componentsApplied++; } if ( channel->componentsBits & COMPONENT_BIT_QZ ) { ( ( vec_t * ) oldQuat ) [ 2 ] = oldFrame->components[ channel->componentsOffset + componentsApplied ]; ( ( vec_t * ) newQuat ) [ 2 ] = newFrame->components[ channel->componentsOffset + componentsApplied ]; } QuatCalcW( oldQuat ); QuatNormalize( oldQuat ); QuatCalcW( newQuat ); QuatNormalize( newQuat ); #if 1 VectorLerp( oldOrigin, newOrigin, frac, lerpedOrigin ); QuatSlerp( oldQuat, newQuat, frac, lerpedQuat ); #else VectorCopy( newOrigin, lerpedOrigin ); QuatCopy( newQuat, lerpedQuat ); #endif // copy lerped information to the bone + extra data skel->bones[ i ].parentIndex = channel->parentIndex; if ( channel->parentIndex < 0 && clearOrigin ) { VectorClear( skel->bones[ i ].t.trans ); QuatClear( skel->bones[ i ].t.rot ); // move bounding box back VectorSubtract( skel->bounds[ 0 ], lerpedOrigin, skel->bounds[ 0 ] ); VectorSubtract( skel->bounds[ 1 ], lerpedOrigin, skel->bounds[ 1 ] ); } else { VectorCopy( lerpedOrigin, skel->bones[ i ].t.trans ); } QuatCopy( lerpedQuat, skel->bones[ i ].t.rot ); skel->bones[ i ].t.scale = 1.0f; #if defined( REFBONE_NAMES ) Q_strncpyz( skel->bones[ i ].name, channel->name, sizeof( skel->bones[ i ].name ) ); #endif } skel->numBones = anim->numChannels; skel->type = refSkeletonType_t::SK_RELATIVE; return true; } // FIXME: clear existing bones and bounds? return false; }
/* ============== RE_BuildSkeleton ============== */ int RE_BuildSkeleton(refSkeleton_t * skel, qhandle_t hAnim, int startFrame, int endFrame, float frac, qboolean clearOrigin) { skelAnimation_t *skelAnim; skelAnim = R_GetAnimationByHandle(hAnim); if(skelAnim->type == AT_MD5 && skelAnim->md5) { int i; md5Animation_t *anim; md5Channel_t *channel; md5Frame_t *newFrame, *oldFrame; vec3_t newOrigin, oldOrigin, lerpedOrigin; quat_t newQuat, oldQuat, lerpedQuat; int componentsApplied; anim = skelAnim->md5; // Validate the frames so there is no chance of a crash. // This will write directly into the entity structure, so // when the surfaces are rendered, they don't need to be // range checked again. /* if((startFrame >= anim->numFrames) || (startFrame < 0) || (endFrame >= anim->numFrames) || (endFrame < 0)) { ri.Printf(PRINT_DEVELOPER, "RE_BuildSkeleton: no such frame %d to %d for '%s'\n", startFrame, endFrame, anim->name); //startFrame = 0; //endFrame = 0; } */ Q_clamp(startFrame, 0, anim->numFrames - 1); Q_clamp(endFrame, 0, anim->numFrames - 1); // compute frame pointers oldFrame = &anim->frames[startFrame]; newFrame = &anim->frames[endFrame]; // calculate a bounding box in the current coordinate system for(i = 0; i < 3; i++) { skel->bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; skel->bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; } for(i = 0, channel = anim->channels; i < anim->numChannels; i++, channel++) { // set baseframe values VectorCopy(channel->baseOrigin, newOrigin); VectorCopy(channel->baseOrigin, oldOrigin); QuatCopy(channel->baseQuat, newQuat); QuatCopy(channel->baseQuat, oldQuat); componentsApplied = 0; // update tranlation bits if(channel->componentsBits & COMPONENT_BIT_TX) { oldOrigin[0] = oldFrame->components[channel->componentsOffset + componentsApplied]; newOrigin[0] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } if(channel->componentsBits & COMPONENT_BIT_TY) { oldOrigin[1] = oldFrame->components[channel->componentsOffset + componentsApplied]; newOrigin[1] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } if(channel->componentsBits & COMPONENT_BIT_TZ) { oldOrigin[2] = oldFrame->components[channel->componentsOffset + componentsApplied]; newOrigin[2] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } // update quaternion rotation bits if(channel->componentsBits & COMPONENT_BIT_QX) { ((vec_t *) oldQuat)[0] = oldFrame->components[channel->componentsOffset + componentsApplied]; ((vec_t *) newQuat)[0] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } if(channel->componentsBits & COMPONENT_BIT_QY) { ((vec_t *) oldQuat)[1] = oldFrame->components[channel->componentsOffset + componentsApplied]; ((vec_t *) newQuat)[1] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } if(channel->componentsBits & COMPONENT_BIT_QZ) { ((vec_t *) oldQuat)[2] = oldFrame->components[channel->componentsOffset + componentsApplied]; ((vec_t *) newQuat)[2] = newFrame->components[channel->componentsOffset + componentsApplied]; } QuatCalcW(oldQuat); QuatNormalize(oldQuat); QuatCalcW(newQuat); QuatNormalize(newQuat); #if 1 VectorLerp(oldOrigin, newOrigin, frac, lerpedOrigin); QuatSlerp(oldQuat, newQuat, frac, lerpedQuat); #else VectorCopy(newOrigin, lerpedOrigin); QuatCopy(newQuat, lerpedQuat); #endif // copy lerped information to the bone + extra data skel->bones[i].parentIndex = channel->parentIndex; if(channel->parentIndex < 0 && clearOrigin) { VectorClear(skel->bones[i].origin); QuatClear(skel->bones[i].rotation); // move bounding box back VectorSubtract(skel->bounds[0], lerpedOrigin, skel->bounds[0]); VectorSubtract(skel->bounds[1], lerpedOrigin, skel->bounds[1]); } else { VectorCopy(lerpedOrigin, skel->bones[i].origin); } QuatCopy(lerpedQuat, skel->bones[i].rotation); #if defined(REFBONE_NAMES) Q_strncpyz(skel->bones[i].name, channel->name, sizeof(skel->bones[i].name)); #endif } skel->numBones = anim->numChannels; skel->type = SK_RELATIVE; return qtrue; } else if(skelAnim->type == AT_PSA && skelAnim->psa) { int i; psaAnimation_t *anim; axAnimationKey_t *newKey, *oldKey; axReferenceBone_t *refBone; vec3_t newOrigin, oldOrigin, lerpedOrigin; quat_t newQuat, oldQuat, lerpedQuat; refSkeleton_t skeleton; anim = skelAnim->psa; Q_clamp(startFrame, 0, anim->info.numRawFrames - 1); Q_clamp(endFrame, 0, anim->info.numRawFrames - 1); ClearBounds(skel->bounds[0], skel->bounds[1]); skel->numBones = anim->info.numBones; for(i = 0, refBone = anim->bones; i < anim->info.numBones; i++, refBone++) { oldKey = &anim->keys[startFrame * anim->info.numBones + i]; newKey = &anim->keys[endFrame * anim->info.numBones + i]; VectorCopy(newKey->position, newOrigin); VectorCopy(oldKey->position, oldOrigin); QuatCopy(newKey->quat, newQuat); QuatCopy(oldKey->quat, oldQuat); //QuatCalcW(oldQuat); //QuatNormalize(oldQuat); //QuatCalcW(newQuat); //QuatNormalize(newQuat); VectorLerp(oldOrigin, newOrigin, frac, lerpedOrigin); QuatSlerp(oldQuat, newQuat, frac, lerpedQuat); // copy lerped information to the bone + extra data skel->bones[i].parentIndex = refBone->parentIndex; if(refBone->parentIndex < 0 && clearOrigin) { VectorClear(skel->bones[i].origin); QuatClear(skel->bones[i].rotation); // move bounding box back VectorSubtract(skel->bounds[0], lerpedOrigin, skel->bounds[0]); VectorSubtract(skel->bounds[1], lerpedOrigin, skel->bounds[1]); } else { VectorCopy(lerpedOrigin, skel->bones[i].origin); } QuatCopy(lerpedQuat, skel->bones[i].rotation); #if defined(REFBONE_NAMES) Q_strncpyz(skel->bones[i].name, refBone->name, sizeof(skel->bones[i].name)); #endif // calculate absolute values for the bounding box approximation VectorCopy(skel->bones[i].origin, skeleton.bones[i].origin); QuatCopy(skel->bones[i].rotation, skeleton.bones[i].rotation); if(refBone->parentIndex >= 0) { vec3_t rotated; quat_t quat; refBone_t *parent; refBone_t *bone; bone = &skeleton.bones[i]; parent = &skeleton.bones[refBone->parentIndex]; QuatTransformVector(parent->rotation, bone->origin, rotated); VectorAdd(parent->origin, rotated, bone->origin); QuatMultiply1(parent->rotation, bone->rotation, quat); QuatCopy(quat, bone->rotation); AddPointToBounds(bone->origin, skel->bounds[0], skel->bounds[1]); } } skel->numBones = anim->info.numBones; skel->type = SK_RELATIVE; return qtrue; } //ri.Printf(PRINT_WARNING, "RE_BuildSkeleton: bad animation '%s' with handle %i\n", anim->name, hAnim); // FIXME: clear existing bones and bounds? return qfalse; }
void CTrackingMissile::Update(void) { CQuaternion q; float t; m_Age = g_time - m_CreationTime; if(m_Age > m_LifeTime) { Die(); return; } if (!m_Tracking) { if (m_Age <= 0.4f) { if (m_FlyLeft) m_RenderObj.MoveRight(-20.0f * g_FrameTime, 0); else m_RenderObj.MoveRight(20.0f * g_FrameTime, 0); t = m_Age; QuatSlerp(&q, &m_Q0, &m_Q1, t * 2.5f); m_RenderObj.GetFrame(0)->SetOrientation(&q); } else if (m_Age <= 0.8f && !m_Target) { t = m_Age - 0.4f; QuatSlerp(&q, &m_Q1, &m_Q2, t * 2.5f); m_RenderObj.GetFrame(0)->SetOrientation(&q); } else { m_Tracking = true; m_RenderObj.GetFrame(0)->GetOrientation(&m_Q0); m_Q1 = m_Q0; m_Velocity = 120.0f; m_LastUpdate = g_time - m_UpdatePeriod; } } else { if (m_Target) { if (m_Target->IsActive()) { t = g_time - m_LastUpdate; if (t >= m_UpdatePeriod) { CVector3f oldfwd, newfwd, tpos, pos, lead(0.0f, 0.0f, 0.0f); m_Q0 = m_Q1; // Find new orientation, lead target a little m_RenderObj.GetFrame(0)->GetForward(&oldfwd); m_Target->GetPosition(&tpos, 0); m_Target->GetVelocity(&lead); Vec3fScale(&lead, &lead, m_UpdatePeriod); Vec3fAdd(&tpos, &tpos, &lead); GetPosition(&pos, 0); Vec3fSubtract(&newfwd, &tpos, &pos); Vec3fNormalize(&newfwd, &newfwd); QuatRotationArc(&q, &oldfwd, &newfwd); QuatCrossProduct(&m_Q1, &q, &m_Q1); m_LastUpdate += m_UpdatePeriod; t = g_time - m_LastUpdate; } QuatSlerp(&q, &m_Q0, &m_Q1, t * m_SlerpScale); m_RenderObj.GetFrame(0)->SetOrientation(&q); } else m_Target = 0; } } // Move the shot forward MoveForward(m_Velocity * g_FrameTime, 0); // Update the ambient sound GetPosition(&m_CurPosition, 0); CVector3f Velocity; Velocity.x = (m_CurPosition.x - m_LastPosition.x) / g_FrameTime; Velocity.y = (m_CurPosition.y - m_LastPosition.y) / g_FrameTime; Velocity.z = (m_CurPosition.z - m_LastPosition.z) / g_FrameTime; m_MissileInAir->UpdateSound(m_CurPosition, Velocity); m_LastPosition = m_CurPosition; CGameObject::Update(); }