Esempio n. 1
0
//-----------------------------------------------------------------------------
// 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);
}