//----------------------------------------------------------------------------- // Purpose: Updates the cached pointers to our start and end entities by looking // for them in the given world. // Input : pWorld - World to search. //----------------------------------------------------------------------------- void CMapLine::UpdateDependencies(CMapWorld *pWorld, CMapClass *pObject) { CMapClass::UpdateDependencies(pWorld, pObject); if (pWorld == NULL) { return; } CMapEntity *pEntity = dynamic_cast <CMapEntity *> (m_pParent); Assert(pEntity != NULL); if (pEntity != NULL) { const char *pszValue = pEntity->GetKeyValue(m_szStartValueKey); m_pStartEntity = (CMapEntity *)UpdateDependency(m_pStartEntity, pWorld->FindChildByKeyValue(m_szStartKey, pszValue)); if (m_szEndValueKey[0] != '\0') { pszValue = pEntity->GetKeyValue(m_szEndValueKey); m_pEndEntity = (CMapEntity *)UpdateDependency(m_pEndEntity, pWorld->FindChildByKeyValue(m_szEndKey, pszValue)); } else { // We don't have an end entity specified, use our parent as the end point. m_pEndEntity = (CMapEntity *)UpdateDependency(m_pEndEntity, GetParent()); } BuildLine(); } }
//----------------------------------------------------------------------------- // Purpose: notifies the keyframe that it has been cloned // inserts the clone into the correct place in the keyframe list // Input : *pClone - //----------------------------------------------------------------------------- void CMapKeyFrame::OnClone( CMapClass *pClone, CMapWorld *pWorld, const CMapObjectList &OriginalList, CMapObjectList &NewList ) { CMapClass::OnClone( pClone, pWorld, OriginalList, NewList ); CMapKeyFrame *pNewKey = dynamic_cast<CMapKeyFrame*>( pClone ); Assert( pNewKey != NULL ); if ( !pNewKey ) return; CMapEntity *pEntity = dynamic_cast<CMapEntity*>( m_pParent ); CMapEntity *pNewEntity = dynamic_cast<CMapEntity*>( pClone->GetParent() ); // insert the newly created keyframe into the sequence // point the clone's next at what we were pointing at const char *nextKey = pEntity->GetKeyValue( "NextKey" ); if ( nextKey ) { pNewEntity->SetKeyValue( "NextKey", nextKey ); } // create a new targetname for the clone char newName[128]; const char *oldName = pEntity->GetKeyValue( "targetname" ); if ( !oldName || oldName[0] == 0 ) oldName = "keyframe"; pWorld->GenerateNewTargetname( oldName, newName, sizeof( newName ), true, NULL ); pNewEntity->SetKeyValue( "targetname", newName ); // point the current keyframe at the clone pEntity->SetKeyValue( "NextKey", newName ); }
//----------------------------------------------------------------------------- // Purpose: // Input : iInterpolator - // Output : IPositionInterpolator //----------------------------------------------------------------------------- IPositionInterpolator* CMapKeyFrame::SetupPositionInterpolator( int iInterpolator ) { if( iInterpolator != m_iPositionInterpolator ) { if( m_pPositionInterpolator ) m_pPositionInterpolator->Release(); m_pPositionInterpolator = Motion_GetPositionInterpolator( iInterpolator ); m_iPositionInterpolator = iInterpolator; // Feed keys.. CMapEntity *pEnt = GetParentEntity(); if( pEnt ) { for ( int i=pEnt->GetFirstKeyValue(); i != pEnt->GetInvalidKeyValue(); i=pEnt->GetNextKeyValue( i ) ) { m_pPositionInterpolator->ProcessKey( pEnt->GetKey( i ), pEnt->GetKeyValue( i ) ); } } } return m_pPositionInterpolator; }
//----------------------------------------------------------------------------- // Purpose: Called when an object that we depend on has changed. //----------------------------------------------------------------------------- void CMapKeyFrame::OnNotifyDependent(CMapClass *pObject, Notify_Dependent_t eNotifyType) { CMapClass::OnNotifyDependent(pObject, eNotifyType); if ((pObject == m_pAnimator) && (eNotifyType == Notify_Removed)) { SetAnimator(NULL); } // // If our next keyframe was deleted, try to link to the one after it. // if ((pObject == m_pNextKeyFrame) && (eNotifyType == Notify_Removed)) { CMapEntity *pNextParent = m_pNextKeyFrame->GetParentEntity(); CMapEntity *pParent = GetParentEntity(); if ( pNextParent && pParent ) { const char *szNext = pNextParent->GetKeyValue("NextKey"); pParent->SetKeyValue("NextKey", szNext); } } m_bRebuildPath = true; }
//----------------------------------------------------------------------------- // Purpose: Called after the entire map has been loaded. This allows the object // to perform any linking with other map objects or to do other operations // that require all world objects to be present. // Input : pWorld - The world that we are in. //----------------------------------------------------------------------------- void CMapSideList::PostloadWorld(CMapWorld *pWorld) { CMapClass::PostloadWorld(pWorld); // // Generate our list of faces from our parent's keyvalue. // CMapEntity *pEntity = dynamic_cast<CMapEntity *>(Parent); if (pEntity != NULL) { const char *pszValue = pEntity->GetKeyValue(m_szKeyName); if (pszValue != NULL) { BuildFaceListForValue(pszValue, pWorld); } } }
//----------------------------------------------------------------------------- // Purpose: // Input : pObject - // FindObject - // Output : Returns true if the object matches the search criteria, false if not. //----------------------------------------------------------------------------- bool FindCheck(CMapClass *pObject, FindObject_t &FindObject) { CMapEntity *pEntity = dynamic_cast <CMapEntity *>(pObject); if (!pEntity) { return false; } if (FindObject.bVisiblesOnly && !pObject->IsVisible()) { return false; } // // Search keyvalues. // int nKeyCount = pEntity->GetKeyValueCount(); for (int i = 0; i < nKeyCount; i++) { const char *pszValue = pEntity->GetKeyValue(i); if (pszValue && MatchString(pszValue, FindObject)) { return true; } } // // Search connections. // POSITION pos = pEntity->Connections_GetHeadPosition(); while (pos) { CEntityConnection *pConn = pEntity->Connections_GetNext(pos); if (pConn) { if (MatchString(pConn->GetTargetName(), FindObject) || MatchString(pConn->GetParam(), FindObject)) { return true; } } } return false; }
//----------------------------------------------------------------------------- // Purpose: // Input : pCopy - // pSourceWorld - // pDestWorld - // OriginalList - // NewList - //----------------------------------------------------------------------------- void CMapSideList::OnPaste(CMapClass *pCopyObject, CMapWorld *pSourceWorld, CMapWorld *pDestWorld, CMapObjectList &OriginalList, CMapObjectList &NewList) { CMapSideList *pCopy = (CMapSideList *)pCopyObject; // // HACK: This is kinda nasty. Build a list of face IDs from our parent keyvalue so // we can remap them to faces in the clipboard. // CMapEntity *pParent = dynamic_cast <CMapEntity *>(pCopy->GetParent()); const char *pszValue = pParent->GetKeyValue(m_szKeyName); if (pszValue != NULL) { char szVal[KEYVALUE_MAX_VALUE_LENGTH]; strcpy(szVal, pszValue); char *psz = strtok(szVal, " "); while (psz != NULL) { // // The substring should now be a single face ID. Get the corresponding // face and add it to the list. // int nFaceID = atoi(psz); CMapFace *pFace = FindFaceIDInList(nFaceID, OriginalList); if (pFace != NULL) { pCopy->m_Faces.AddToTail(pFace); } // // Get the next substring. // psz = strtok(NULL, " "); } } // // Now replace all faces with their new counterparts, as in Clone. // ReplaceFacesInCopy(pCopy, OriginalList, NewList); }
//----------------------------------------------------------------------------- // Purpose: Rebuilds the line path between keyframe entities // samples the interpolator function to get an approximation of the curve //----------------------------------------------------------------------------- void CMapAnimator::RebuildPath( void ) { CMapClass *pWorld = GetWorldObject( this ); if ( !pWorld ) { // Sometimes the object isn't linked back into the world yet when RebuildPath() // is called... we will be get called again when needed, but may cause an incorrect // (linear-only) path to get drawn temporarily. return; } // // Build the path forward from the head. Keep a list of nodes we've visited to // use in detecting circularities. // CMapObjectList VisitedList; CMapKeyFrame *pCurKey = this; while ( pCurKey != NULL ) { VisitedList.AddTail( pCurKey ); // // Attach ourselves as this keyframe's animator. // pCurKey->SetAnimator( this ); // // Get the entity parent of this keyframe so we can query keyvalues. // CMapEntity *pCurEnt = dynamic_cast<CMapEntity *>( pCurKey->GetParent() ); if ( !pCurEnt ) { return; } // // Find the next keyframe in the path. // CMapEntity *pNextEnt = pWorld->FindChildByKeyValue( "targetname", pCurEnt->GetKeyValue( "NextKey" ) ); CMapKeyFrame *pNextKey = NULL; if ( pNextEnt ) { pNextKey = pNextEnt->GetChildOfType( ( CMapKeyFrame * )NULL ); pCurKey->SetNextKeyFrame(pNextKey); } else { pCurKey->SetNextKeyFrame( NULL ); } pCurKey = pNextKey; // // If we detect a circularity, stop. // if ( VisitedList.Find( pCurKey ) ) { break; } } // // Now traverse the path again building the spline points, once again checking // the visited list for circularities. // VisitedList.RemoveAll(); pCurKey = this; CMapKeyFrame *pPrevKey = this; while ( pCurKey != NULL ) { VisitedList.AddTail( pCurKey ); pCurKey->BuildPathSegment(pPrevKey); pPrevKey = pCurKey; pCurKey = pCurKey->m_pNextKeyFrame; // // If we detect a circularity, stop. // if ( VisitedList.Find( pCurKey ) ) { break; } } }
//----------------------------------------------------------------------------- // Purpose: creates a new keyframe at the specified time // Input : time - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- CMapEntity *CMapAnimator::CreateNewKeyFrame( float time ) { // work out where we are in the animation CMapKeyFrame *key; CMapKeyFrame *pPrevKey; float partialTime = GetKeyFramesAtTime( time, key, pPrevKey ); CMapEntity *pCurrentEnt = dynamic_cast<CMapEntity*>( key->Parent ); // check to see if we're direction on a key frame Vector posOffset( 0, 0, 0 ); if ( partialTime == 0 ) { // create this new key frame slightly after the current one, and offset posOffset[0] = 64; } // get our orientation and position at this time Vector vOrigin; QAngle angles; Quaternion qAngles; GetAnimationAtTime( key, pPrevKey, partialTime, vOrigin, qAngles, m_iPositionInterpolator, m_iRotationInterpolator ); QuaternionAngles( qAngles, angles ); // create the new map entity CMapDoc *pDoc = CMapDoc::GetActiveMapDoc(); CMapWorld *pWorld = pDoc->GetMapWorld(); CMapEntity *pNewEntity = new CMapEntity; Vector newPos; VectorAdd( vOrigin, posOffset, newPos ); pNewEntity->SetPlaceholder( TRUE ); pNewEntity->SetOrigin( newPos ); pNewEntity->SetClass( "keyframe_track" ); char buf[128]; sprintf( buf, "%f %f %f", angles[0], angles[1], angles[2] ); pNewEntity->SetKeyValue( "angles", buf ); // link it into the keyframe list // take over this existing next keyframe pointer const char *nextKeyName = pCurrentEnt->GetKeyValue( "NextKey" ); if ( nextKeyName ) { pNewEntity->SetKeyValue( "NextKey", nextKeyName ); } // create a new unique name for this ent char newName[128]; const char *oldName = pCurrentEnt->GetKeyValue( "targetname" ); if ( !oldName || oldName[0] == 0 ) oldName = "keyframe"; CMapEntity::GenerateNewTargetname( oldName, newName, 127 ); pNewEntity->SetKeyValue( "targetname", newName ); // point the current entity at the newly created one pCurrentEnt->SetKeyValue( "NextKey", newName ); // copy any relevant values const char *keyValue = pCurrentEnt->GetKeyValue( "parentname" ); if ( keyValue ) pNewEntity->SetKeyValue( "parentname", keyValue ); keyValue = pCurrentEnt->GetKeyValue( "MoveSpeed" ); if ( keyValue ) pNewEntity->SetKeyValue( "MoveSpeed", keyValue ); return(pNewEntity); }