コード例 #1
0
void IFaceposerModels::CFacePoserModel::RecreateAllAnimationBitmaps()
{
	StudioModel *model = m_pModel;
	if ( !model )
		return;

	CStudioHdr *hdr = model->GetStudioHdr();
	if ( !hdr )
		return;	

	g_pProgressDialog->Start( CFmtStr( "%s - Animation Thumbnails", GetShortModelName() ), "", true );

	for ( int i = 0; i < hdr->GetNumSeq(); ++i )
	{
		const mstudioseqdesc_t &seq = hdr->pSeqdesc( i );

		g_pProgressDialog->UpdateText( "%s", seq.pszLabel() );
		g_pProgressDialog->Update( (float)i / (float)hdr->GetNumSeq() );

		RecreateAnimationBitmap( i, false );

		if ( g_pProgressDialog->IsCancelled() )
		{
			Msg( "Cancelling\n" );
			break;
		}
	}

	g_pProgressDialog->Finish();

	ReconcileAnimationBitmaps();
}
コード例 #2
0
//=========================================================
//=========================================================
bool CAnimating::HasPoseParameter( int iSequence, int iParameter )
{
	CStudioHdr *pstudiohdr = GetModelPtr( );

	if ( !pstudiohdr )
	{
		return false;
	}

	if ( !pstudiohdr->SequencesAvailable() )
	{
		return false;
	}

	if (iSequence < 0 || iSequence >= pstudiohdr->GetNumSeq())
	{
		return false;
	}

	mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( iSequence );
	if (pstudiohdr->GetSharedPoseParameter( iSequence, seqdesc.paramindex[0] ) == iParameter || 
		pstudiohdr->GetSharedPoseParameter( iSequence, seqdesc.paramindex[1] ) == iParameter)
	{
		return true;
	}
	return false;
}
コード例 #3
0
void CEnvParticleScript::PrecacheAnimationEventMaterials()
{
	CStudioHdr *hdr = GetModelPtr();
	if ( hdr )
	{
		int numseq = hdr->GetNumSeq();
		for ( int i = 0; i < numseq; ++i )
		{
			mstudioseqdesc_t& seqdesc = hdr->pSeqdesc( i );
			int ecount = seqdesc.numevents;
			for ( int j = 0 ; j < ecount; ++j )
			{
				const mstudioevent_t* event = (const mstudioevent_for_client_server_t*)seqdesc.pEvent( j );
				if ( event->Event() == CL_EVENT_SPRITEGROUP_CREATE )
				{
					char pAttachmentName[256];
					char pSpriteName[256];
					int nArgs = sscanf( event->pszOptions(), "%255s %255s", pAttachmentName, pSpriteName );
					if ( nArgs == 2 )
					{
						PrecacheMaterial( pSpriteName );
					}
				}
			}
		}
	}
}
コード例 #4
0
// If the local player is visible (thirdperson mode, tf2 taunts, etc., then make sure that we are using the 
//  w_ (world) model not the v_ (view) model or else the model can flicker, etc.
// Otherwise, if we're not the local player, always use the world model
void C_BaseCombatWeapon::EnsureCorrectRenderingModel()
{
	C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();
	if ( localplayer && 
		localplayer == GetOwner() &&
		!localplayer->ShouldDrawLocalPlayer() )
	{
		return;
	}

	MDLCACHE_CRITICAL_SECTION();

	// BRJ 10/14/02
	// FIXME: Remove when Yahn's client-side prediction is done
	// It's a hacky workaround for the model indices fighting
	// (GetRenderBounds uses the model index, which is for the view model)
	SetModelIndex( GetWorldModelIndex() );

	// Validate our current sequence just in case ( in theory the view and weapon models should have the same sequences for sequences that overlap at least )
	CStudioHdr *pStudioHdr = GetModelPtr();
	if ( pStudioHdr && 
		GetSequence() >= pStudioHdr->GetNumSeq() )
	{
		SetSequence( 0 );
	}
}
コード例 #5
0
void C_BaseAnimatingOverlay::GetRenderBounds( Vector& theMins, Vector& theMaxs )
{
	BaseClass::GetRenderBounds( theMins, theMaxs );

	if ( !IsRagdoll() )
	{
		CStudioHdr *pStudioHdr = GetModelPtr();
		if ( !pStudioHdr || !pStudioHdr->SequencesAvailable() )
			return;

		int nSequences = pStudioHdr->GetNumSeq();

		int i;
		for (i = 0; i < m_AnimOverlay.Count(); i++)
		{
			if (m_AnimOverlay[i].m_flWeight > 0.0)
			{
				if ( m_AnimOverlay[i].m_nSequence >= nSequences )
				{
					continue;
				}

				mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( m_AnimOverlay[i].m_nSequence );
				VectorMin( seqdesc.bbmin, theMins, theMins );
				VectorMax( seqdesc.bbmax, theMaxs, theMaxs );
			}
		}
	}
}
コード例 #6
0
ファイル: studio_utils.cpp プロジェクト: chrizonix/RCBot2
void StudioModel::scaleMeshes (float scale)
{
	CStudioHdr *pStudioHdr = GetStudioHdr();
	if (!pStudioHdr)
		return;

	int i, j, k;

	// manadatory to access correct verts
	SetCurrentModel();

	// scale verts
	int tmp = m_bodynum;
	for (i = 0; i < pStudioHdr->numbodyparts(); i++)
	{
		mstudiobodyparts_t *pbodypart = pStudioHdr->pBodypart( i );
		for (j = 0; j < pbodypart->nummodels; j++)
		{
			SetBodygroup (i, j);
			SetupModel (i);

			const mstudio_modelvertexdata_t *vertData = m_pmodel->GetVertexData();

			for (k = 0; k < m_pmodel->numvertices; k++)
			{
				*vertData->Position(k) *= scale;
			}
		}
	}

	m_bodynum = tmp;

	// scale complex hitboxes
	int hitboxset = g_MDLViewer->GetCurrentHitboxSet();

	mstudiobbox_t *pbboxes = pStudioHdr->pHitbox( 0, hitboxset );
	for (i = 0; i < pStudioHdr->iHitboxCount( hitboxset ); i++)
	{
		VectorScale (pbboxes[i].bbmin, scale, pbboxes[i].bbmin);
		VectorScale (pbboxes[i].bbmax, scale, pbboxes[i].bbmax);
	}

	// scale bounding boxes
	for (i = 0; i < pStudioHdr->GetNumSeq(); i++)
	{
		mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( i );
		Vector tmp;

		tmp = seqdesc.bbmin;
		VectorScale( tmp, scale, tmp );
		seqdesc.bbmin = tmp;

		tmp = seqdesc.bbmax;
		VectorScale( tmp, scale, tmp );
		seqdesc.bbmax = tmp;

	}

	// maybe scale exeposition, pivots, attachments
}
コード例 #7
0
int SEditModelRender::QuerySequences( char ***list )
{
	if ( !IsModelReady() )
		return 0;

	MDLCACHE_CRITICAL_SECTION();
	CStudioHdr *pHdr = pModelInstance->GetModelPtr();
	if ( !pHdr )
		return 0;

	CUtlVector< mstudioseqdesc_t* >hSeqs;
	for ( int i = 0; i < pHdr->GetNumSeq(); i++ )
		if ( !( pHdr->pSeqdesc( i ).flags & STUDIO_HIDDEN ) )
			hSeqs.AddToTail( &pHdr->pSeqdesc( i ) );

	int numSequences = hSeqs.Count();

	if ( !numSequences )
		return 0;

	hSeqs.Sort( SequenceSort );

	CUtlVector< const char* >hNameList;
	for ( int i = 0; i < numSequences; i++ )
	{
		const char *seqName = NULL;
		const mstudioseqdesc_t &seqPtr = *hSeqs[ i ];
		if ( seqPtr.pszLabel() )
			seqName = seqPtr.pszLabel();
		else
			seqName = "Unknown Sequence";

		hNameList.AddToTail( seqName );
	}

	*list = new char*[numSequences];

	int iTotalLength = 0;
	for ( int i = 0; i < numSequences; i++ )
		iTotalLength += Q_strlen( hNameList[i] ) + 1;

	**list = new char[ iTotalLength ];

	int curpos = 0;
	for ( int i = 0; i < numSequences; i++ )
	{
		int curLength = Q_strlen( hNameList[i] ) + 1;
		(*list)[ i ] = **list + curpos;
		Q_strcpy( (*list)[ i ], hNameList[i] );
		curpos += curLength;
	}

	hNameList.Purge();
	hSeqs.Purge();
	return numSequences;
}
コード例 #8
0
ファイル: studio_utils.cpp プロジェクト: newroob/bg2-2007
int StudioModel::GetNumFrames( int iSequence )
{
	CStudioHdr *pStudioHdr = GetStudioHdr();
	if ( !pStudioHdr || iSequence < 0 || iSequence >= pStudioHdr->GetNumSeq() )
	{
		return 1;
	}

	return Studio_MaxFrame( pStudioHdr, iSequence, m_poseparameter );
}
コード例 #9
0
void CEventPropertiesSequenceDialog::PopulateSequenceList( HWND wnd )
{
	CStudioHdr *hdr = models->GetActiveStudioModel()->GetStudioHdr();
	if (hdr)
	{
		for (int i = 0; i < hdr->GetNumSeq(); i++)
		{
			SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)hdr->pSeqdesc(i).pszLabel() ); 
		}
	}
}
コード例 #10
0
void CEventPropertiesGestureDialog::PopulateGestureList( HWND wnd )
{
	CStudioHdr *hdr = models->GetActiveStudioModel()->GetStudioHdr();
	if (hdr)
	{
		int i;
		for (i = 0; i < hdr->GetNumSeq(); i++)
		{
			if (CheckSequenceType( models->GetActiveStudioModel(), i, "gesture" ))
			{
				SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)hdr->pSeqdesc(i).pszLabel() ); 
			}
		}
		for (i = 0; i < hdr->GetNumSeq(); i++)
		{
			if (CheckSequenceType( models->GetActiveStudioModel(), i, "posture" ))
			{
				SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)hdr->pSeqdesc(i).pszLabel() ); 
			}
		}
	}
}
コード例 #11
0
void
ControlPanel::initSequenceChoices()
{
	CStudioHdr *hdr = models->GetActiveStudioModel()->GetStudioHdr();
	if (hdr)
	{
		cSequence->removeAll();
		for (int i = 0; i < hdr->GetNumSeq(); i++)
		{
			cSequence->add (hdr->pSeqdesc(i).pszLabel());
		}

		cSequence->select (0);
	}
}
コード例 #12
0
void IFaceposerModels::CFacePoserModel::BuildValidChecksums( CUtlRBTree< CRC32_t > &tree )
{
	StudioModel *model = m_pModel;
	if ( !model )
		return;

	CStudioHdr *hdr = model->GetStudioHdr();
	if ( !hdr )
		return;	

	for ( int i = 0; i < hdr->GetNumSeq(); i++ )
	{
		CRC32_t crc = GetBitmapCRC( i );
		tree.Insert( crc );
	}
}
コード例 #13
0
ファイル: studio_utils.cpp プロジェクト: newroob/bg2-2007
int StudioModel::LookupActivity( const char *szActivity )
{
	int i;

	CStudioHdr *pStudioHdr = GetStudioHdr();
	if ( !pStudioHdr )
		return -1;

	for (i = 0; i < pStudioHdr->GetNumSeq(); i++)
	{
		if (!stricmp( szActivity, pStudioHdr->pSeqdesc( i ).pszActivityName() ))
		{
			return i;
		}
	}
	return -1;
}
コード例 #14
0
ファイル: studio_utils.cpp プロジェクト: newroob/bg2-2007
int StudioModel::LookupSequence( const char *szSequence )
{
	int i;

	CStudioHdr *pStudioHdr = GetStudioHdr();
	if ( !pStudioHdr )
		return -1;

	for (i = 0; i < pStudioHdr->GetNumSeq(); i++)
	{
		if (!stricmp( szSequence, pStudioHdr->pSeqdesc( i ).pszLabel() ))
		{
			return i;
		}
	}
	return -1;
}
コード例 #15
0
ファイル: studio_utils.cpp プロジェクト: newroob/bg2-2007
int StudioModel::SetSequence( int iSequence )
{
	CStudioHdr *pStudioHdr = GetStudioHdr();
	if ( !pStudioHdr )
		return 0;

	if (iSequence < 0)
		return 0;

	if (iSequence > pStudioHdr->GetNumSeq())
		return m_sequence;

	m_prevsequence = m_sequence;
	m_sequence = iSequence;
	m_cycle = 0;
	m_sequencetime = 0.0;

	return m_sequence;
}
コード例 #16
0
void IFaceposerModels::CFacePoserModel::LoadBitmaps()
{
	CStudioHdr *hdr = m_pModel ? m_pModel->GetStudioHdr() : NULL;
	if ( hdr )
	{
		for ( int i = 0 ;i < hdr->GetNumSeq(); i++ )
		{
			mxbitmapdata_t *bm = new mxbitmapdata_t();

			AnimBitmap *entry = new AnimBitmap();
			entry->needsload = true;
			entry->bitmap = bm;

			// Need to load bitmap from disk image via crc, etc.
			//Assert( 0 );

			m_AnimationBitmaps.AddToTail( entry );
		}
	}
}
コード例 #17
0
void
ControlPanel::setModelInfo()
{
	static char str[2048];
	CStudioHdr *hdr = models->GetActiveStudioModel()->GetStudioHdr();

	if (!hdr)
		return;

	int hbcount = 0;
	for ( int s = 0; s < hdr->numhitboxsets(); s++ )
	{
		hbcount += hdr->iHitboxCount( s );
	}

	sprintf (str,
		"Bones: %d\n"
		"Bone Controllers: %d\n"
		"Hit Boxes: %d in %d sets\n"
		"Sequences: %d\n",
		hdr->numbones(),
		hdr->numbonecontrollers(),
		hbcount,
		hdr->numhitboxsets(),
		hdr->GetNumSeq()
		);

	lModelInfo1->setLabel (str);

	sprintf (str,
		"Textures: %d\n"
		"Skin Families: %d\n"
		"Bodyparts: %d\n"
		"Attachments: %d\n",
		hdr->numtextures(),
		hdr->numskinfamilies(),
		hdr->numbodyparts(),
		hdr->GetNumAttachments());

	lModelInfo2->setLabel (str);
}
コード例 #18
0
CRC32_t IFaceposerModels::CFacePoserModel::GetBitmapCRC( int sequence )
{
	CStudioHdr *hdr = m_pModel ? m_pModel->GetStudioHdr() : NULL;
	if ( !hdr )
		return (CRC32_t)-1;

	if ( sequence < 0 || sequence >= hdr->GetNumSeq() )
		return (CRC32_t)-1;

	mstudioseqdesc_t &seqdesc = hdr->pSeqdesc( sequence );

	CRC32_t crc;
	CRC32_Init( &crc );

	// For sequences, we'll checsum a bit of data

	CRC32_ProcessBuffer( &crc, (void *)seqdesc.pszLabel(), Q_strlen( seqdesc.pszLabel() ) );
	CRC32_ProcessBuffer( &crc, (void *)seqdesc.pszActivityName(), Q_strlen( seqdesc.pszActivityName() ) );
	CRC32_ProcessBuffer( &crc, (void *)&seqdesc.flags, sizeof( seqdesc.flags ) );
	//CRC32_ProcessBuffer( &crc, (void *)&seqdesc.numevents, sizeof( seqdesc.numevents ) );
	CRC32_ProcessBuffer( &crc, (void *)&seqdesc.numblends, sizeof( seqdesc.numblends ) );
	CRC32_ProcessBuffer( &crc, (void *)seqdesc.groupsize, sizeof( seqdesc.groupsize ) );

	KeyValues *seqKeyValues = new KeyValues("");
	if ( seqKeyValues->LoadFromBuffer( m_pModel->GetFileName( ), m_pModel->GetKeyValueText( sequence ) ) )
	{
		// Yuck, but I need it in a contiguous block of memory... oh well...
		CUtlBuffer buf;
		seqKeyValues->RecursiveSaveToFile( buf, 0 );
		CRC32_ProcessBuffer( &crc, ( void * )buf.Base(), buf.TellPut() );
	}

	seqKeyValues->deleteThis();

	CRC32_Final( &crc );

	return crc;
}
コード例 #19
0
ファイル: studio_utils.cpp プロジェクト: newroob/bg2-2007
int StudioModel::SetOverlaySequence( int iLayer, int iSequence, float flWeight )
{
	CStudioHdr *pStudioHdr = GetStudioHdr();
	if ( !pStudioHdr )
		return 0;

	if (iSequence < 0)
		return 0;

	if (iLayer < 0 || iLayer >= MAXSTUDIOANIMLAYERS)
	{
		Assert(0);
		return 0;
	}

	if (iSequence > pStudioHdr->GetNumSeq())
		return m_Layer[iLayer].m_sequence;

	m_Layer[iLayer].m_sequence = iSequence;
	m_Layer[iLayer].m_weight = flWeight;
	m_Layer[iLayer].m_playbackrate = 1.0;

	return iSequence;
}
コード例 #20
0
void IFaceposerModels::CFacePoserModel::CreateNewBitmap( char const *pchBitmapFilename, int sequence, int nSnapShotSize, bool bZoomInOnFace, CExpression *pExpression, mxbitmapdata_t *bitmap )
{
	MatSysWindow *pWnd = g_pMatSysWindow;
	if ( !pWnd ) 
		return;

	StudioModel *model = m_pModel;
	if ( !model )
		return;

	CStudioHdr *hdr = model->GetStudioHdr();
	if ( !hdr )
		return;
	if ( sequence < 0 || sequence >= hdr->GetNumSeq() )
		return;

	mstudioseqdesc_t &seqdesc = hdr->pSeqdesc( sequence );

	Con_ColorPrintf( FILE_COLOR, "Creating bitmap %s for sequence '%s'\n", pchBitmapFilename, seqdesc.pszLabel() );

	model->ClearOverlaysSequences();
	int iLayer = model->GetNewAnimationLayer();
	model->SetOverlaySequence( iLayer, sequence, 1.0 );
	model->SetOverlayRate( iLayer, FindPoseCycle( model, sequence ), 0.0 );

	for (int i = 0; i < hdr->GetNumPoseParameters(); i++)
	{
		model->SetPoseParameter( i, 0.0 );
	}

	float flexValues[ GLOBAL_STUDIO_FLEX_CONTROL_COUNT ] = { 0 };

	if ( pExpression )
	{
		float *settings = pExpression->GetSettings();
		float *weights = pExpression->GetWeights();

		// Save existing settings from model
		for ( LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); ++i )
		{
			int j = hdr->pFlexcontroller( i )->localToGlobal;
			if ( j == -1 )
				continue;
			flexValues[ i ] = model->GetFlexController( i );
			// Set Value from passed in settings
			model->SetFlexController( i, settings[ j ] * weights[ j ] );
		}
	}

	model->ClearLookTargets( );

	QAngle oldrot, oldLight;
	Vector oldtrans;
	
	VectorCopy( model->m_angles, oldrot );
	VectorCopy( model->m_origin, oldtrans );
	VectorCopy( g_viewerSettings.lightrot, oldLight );

	model->m_angles.Init();
	model->m_origin.Init();
	g_viewerSettings.lightrot.Init();

	g_viewerSettings.lightrot.y = -180;

	bool bSaveGround = g_viewerSettings.showGround;
	g_viewerSettings.showGround = false;

	if ( bZoomInOnFace )
	{
		Vector size;
		VectorSubtract( hdr->hull_max(), hdr->hull_min(), size );

		float eyeheight = hdr->hull_min().z + 0.9 * size.z;
		//	float width = ( size.x + size.y ) / 2.0f;

		model->m_origin.x = size.z * .6f;

		if ( hdr->GetNumAttachments() > 0 )
		{
			for (int i = 0; i < hdr->GetNumAttachments(); i++)
			{
				const mstudioattachment_t &attachment = hdr->pAttachment( i );
				int iBone = hdr->GetAttachmentBone( i );

				if ( Q_stricmp( attachment.pszName(), "eyes" ) )
					continue;

				mstudiobone_t *bone = hdr->pBone( iBone );
				if ( !bone )
					continue;

				matrix3x4_t boneToPose;
				MatrixInvert( bone->poseToBone, boneToPose );

				matrix3x4_t attachmentPoseToLocal;
				ConcatTransforms( boneToPose, attachment.local, attachmentPoseToLocal );

				Vector localSpaceEyePosition;
				VectorITransform( vec3_origin, attachmentPoseToLocal, localSpaceEyePosition );

				// Not sure why this must be negative?
				eyeheight = -localSpaceEyePosition.z + hdr->hull_min().z;
				break;
			}
		}

		KeyValues *seqKeyValues = new KeyValues("");
		if ( seqKeyValues->LoadFromBuffer( model->GetFileName( ), model->GetKeyValueText( sequence ) ) )
		{
			// Do we have a build point section?
			KeyValues *pkvAllFaceposer = seqKeyValues->FindKey("faceposer");
			if ( pkvAllFaceposer )
			{
				float flEyeheight = pkvAllFaceposer->GetFloat( "eye_height", -9999.0f );
				if ( flEyeheight != -9999.0f )
				{
					eyeheight = flEyeheight;
				}
			}
		}

		model->m_origin.z += eyeheight;
	}
	else
	{
		Vector mins, maxs;
		model->ExtractBbox(mins, maxs);
		Vector size;
		VectorSubtract( maxs, mins, size );

		float maxdim = size.x;
		if ( size.y > maxdim )
			maxdim = size.y;
		if ( size.z > maxdim )
			maxdim = size.z;

		float midpoint = mins.z + 0.5 * size.z;

		model->m_origin.x = 3 * maxdim;
		model->m_origin.z += midpoint;
	}

	pWnd->SuppressResize( true );

	RECT rcClient;
	HWND wnd = (HWND)pWnd->getHandle();

	WINDOWPLACEMENT wp;

	GetWindowPlacement( wnd, &wp );

	GetClientRect( wnd, &rcClient );

	MoveWindow( wnd, 0, 0, nSnapShotSize + 16, nSnapShotSize + 16, TRUE );

	// Snapshots are taken of the back buffer; 
	// we need to render to the back buffer but not move it to the front
	pWnd->SuppressBufferSwap( true );
	pWnd->redraw();
	pWnd->SuppressBufferSwap( false );

	// make it square, assumes w > h
	char fullpath[ 512 ];
	Q_snprintf( fullpath, sizeof( fullpath ), "%s%s", GetGameDirectory(), pchBitmapFilename );
	pWnd->TakeSnapshotRect( fullpath, 0, 0, nSnapShotSize, nSnapShotSize );

	// Move back to original position
	SetWindowPlacement( wnd, &wp );

	pWnd->SuppressResize( false );

	VectorCopy( oldrot, model->m_angles );
	VectorCopy( oldtrans, model->m_origin );
	VectorCopy( oldLight, g_viewerSettings.lightrot );

	g_viewerSettings.showGround = bSaveGround;

	if ( pExpression )
	{
		// Save existing settings from model
		for ( LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); ++i )
		{
			int j = hdr->pFlexcontroller( i )->localToGlobal;
			if ( j == -1 )
				continue;

			model->SetFlexController( i, flexValues[ i ] );
		}
	}

	model->ClearOverlaysSequences();
	
	if ( bitmap->valid )
	{
		DeleteObject( bitmap->image );
		bitmap->image = 0;
		bitmap->valid = false;
	}

	LoadBitmapFromFile( pchBitmapFilename, *bitmap );
}
コード例 #21
0
void CAnimationLayer::DispatchAnimEvents( CBaseAnimating *eventHandler, CBaseAnimating *pOwner )
{
  	animevent_t	event;

	CStudioHdr *pstudiohdr = pOwner->GetModelPtr( );

	if ( !pstudiohdr )
	{
		Assert(!"CBaseAnimating::DispatchAnimEvents: model missing");
		return;
	}

	if ( !pstudiohdr->SequencesAvailable() )
	{
		return;
	}

	if ( m_nSequence >= pstudiohdr->GetNumSeq() )
		return;
	
	// don't fire if here are no events
	if ( pstudiohdr->pSeqdesc( m_nSequence ).numevents == 0 )
	{
		return;
	}

	// look from when it last checked to some short time in the future	
	float flCycleRate = pOwner->GetSequenceCycleRate( m_nSequence ) * m_flPlaybackRate;
	float flStart = m_flLastEventCheck;
	float flEnd = m_flCycle;

	if (!m_bLooping)
	{
		// fire off events early
		float flLastVisibleCycle = 1.0f - (pstudiohdr->pSeqdesc( m_nSequence ).fadeouttime) * flCycleRate;
		if (flEnd >= flLastVisibleCycle || flEnd < 0.0) 
		{
			m_bSequenceFinished = true;
			flEnd = 1.01f;
		}
	}
	m_flLastEventCheck = flEnd;

	/*
	if (pOwner->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)
	{
		Msg( "%s:%s : checking %.2f %.2f (%d)\n", STRING(pOwner->GetModelName()), pstudiohdr->pSeqdesc( m_nSequence ).pszLabel(), flStart, flEnd, m_bSequenceFinished );
	}
	*/

	// FIXME: does not handle negative framerates!
	int index = 0;
	while ( (index = GetAnimationEvent( pstudiohdr, m_nSequence, &event, flStart, flEnd, index ) ) != 0 )
	{
		event.pSource = pOwner;
		// calc when this event should happen
		if (flCycleRate > 0.0)
		{
			float flCycle = event.cycle;
			if (flCycle > m_flCycle)
			{
				flCycle = flCycle - 1.0;
			}
			event.eventtime = pOwner->m_flAnimTime + (flCycle - m_flCycle) / flCycleRate + pOwner->GetAnimTimeInterval();
		}

		// Msg( "dispatch %d (%d : %.2f)\n", index - 1, event.event, event.eventtime );
		event.m_bHandledByScript = eventHandler->HandleScriptedAnimEvent( &event );
		if ( eventHandler->HandleBehaviorAnimEvent( &event ) )
		{
			event.m_bHandledByScript = true;
		}
		eventHandler->HandleAnimEvent( &event );
	}
}