コード例 #1
0
//+--------------------------------------------------------------------------+
//|							From IPFTest									 |
//+--------------------------------------------------------------------------+
bool PFTestGoToRotation::ProceedStep2(TimeValue timeStartTick, float timeStartFraction, TimeValue& timeEndTick, float& timeEndFraction, BitArray& testResult, Tab<float>& testTime)
{
	PreciseTimeValue timeStart = PreciseTimeValue(timeStartTick, timeStartFraction);
	PreciseTimeValue timeEnd = PreciseTimeValue(timeEndTick, timeEndFraction);
	bool res = Proceed(	_containerFnPub(),
						timeStart,
						timeEnd,
						_particleSystemFnPub(),
						_particleNodeFnPub(),
						_actionNodeFnPub(),
						(IPFIntegrator*)_integratorFnPub(),
						testResult,
						testTime);
	timeEndTick = timeEnd.tick;
	timeEndFraction = timeEnd.fraction;
	return res;
}
コード例 #2
0
bool PFOperatorMaterialStatic::Proceed(IObject* pCont, 
									 PreciseTimeValue timeStart, 
									 PreciseTimeValue& timeEnd,
									 Object* pSystem,
									 INode* pNode,
									 INode* actionNode,
									 IPFIntegrator* integrator)
{
	if (pblock() == NULL) return false;
	int assignID = pblock()->GetInt(kMaterialStatic_assignID, timeEnd);
	if (assignID == 0) return true; // nothing to assign

	int showInViewport = pblock()->GetInt(kMaterialStatic_showInViewport, timeEnd);
	if (!showInViewport) { // check if the system is in render; if not then return
		IPFSystem* iSystem = GetPFSystemInterface(pSystem);
		if (iSystem == NULL) return false;
		if (!iSystem->IsRenderState()) return true; // nothing to show in viewport
	}

	int type = pblock()->GetInt(kMaterialStatic_type, timeEnd);

	// acquire absolutely necessary particle channels
	IParticleChannelAmountR* chAmount = GetParticleChannelAmountRInterface(pCont);
	if (chAmount == NULL) return false; // can't find number of particles in the container
	int i, count = chAmount->Count();
	if (count == 0) return true; // no particles to modify
	IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont);
	if (chTime == NULL) return false; // can't read timing for a particle
	IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont);
	if (chNew == NULL) return false; // can't find newly entered particles for duration calculation
	
	IChannelContainer* chCont = GetChannelContainerInterface(pCont);
	if (chCont == NULL) return false;

	// ensure materialStatic index channel
	IParticleChannelIntW* chMtlIDW = (IParticleChannelIntW*)chCont->EnsureInterface(PARTICLECHANNELMTLINDEXW_INTERFACE,
																ParticleChannelInt_Class_ID,
																true, PARTICLECHANNELMTLINDEXR_INTERFACE,
																PARTICLECHANNELMTLINDEXW_INTERFACE, true);
	if (chMtlIDW == NULL) return false; // can't modify MaterialStatic Index channel in the container
	IParticleChannelIntR* chMtlIDR = GetParticleChannelMtlIndexRInterface(pCont);

	RandGenerator* randGen = randLinker().GetRandGenerator(pCont);

	int rateType = pblock()->GetInt(kMaterialStatic_rateType, timeEnd);
	int numSubMtls = pblock()->GetInt(kMaterialStatic_numSubMtls, timeEnd);
	if (numSubMtls < 1) numSubMtls = 1;
	int cycleLoop = pblock()->GetInt(kMaterialStatic_loop, timeEnd);
	float rateSec = pblock()->GetFloat(kMaterialStatic_ratePerSecond, timeEnd);
	float ratePart = pblock()->GetFloat(kMaterialStatic_ratePerParticle, timeEnd);
	int mtlID;

	bool useRatePerSec = ((type != kMaterialStatic_type_id) && (rateType == kMaterialStatic_rateType_second));
	bool useRatePerPart = ((type != kMaterialStatic_type_id) && (rateType == kMaterialStatic_rateType_particle));

	bool initRands = false;
	// recalc offset if necessary
	if (_offsetTime(pCont) == TIME_NegInfinity) {
		_offsetTime(pCont) = timeStart.TimeValue();
		// find the earliest time of the coming particles
		PreciseTimeValue minTime = chTime->GetValue(0);
		for(i=1; i<count; i++)
			if (minTime > chTime->GetValue(i)) 
				minTime = chTime->GetValue(i);
		if (useRatePerSec)
			if (type == kMaterialStatic_type_cycle)
				_cycleOffset(pCont) = float(PreciseTimeValue(_offsetTime(pCont)) - minTime)*rateSec/TIME_TICKSPERSEC;
		initRands = true;
	} else if (_offsetTime(pCont) != timeStart.TimeValue()) {
		if (useRatePerSec) {
			if (type == kMaterialStatic_type_cycle) {
				float timeDelta = float(timeStart.TimeValue() - _offsetTime(pCont));
				float addOffset = timeDelta*rateSec/TIME_TICKSPERSEC;
				_cycleOffset(pCont) += addOffset;
				if (_cycleOffset(pCont) >= numSubMtls) {
					if (cycleLoop) _cycleOffset(pCont) -= numSubMtls*int(_cycleOffset(pCont)/numSubMtls);
					else _cycleOffset(pCont) = numSubMtls - 1.0f;
				}
			}
		}
		_offsetTime(pCont) = timeStart.TimeValue();
		initRands = true;
	}
	if (initRands && useRatePerSec && (type == kMaterialStatic_type_random)) {
		int intervalDelta = int(timeEnd.TimeValue() - timeStart.TimeValue()) + 1;
		_randMtlIndex(pCont).SetCount(intervalDelta);
		float curOffset = _cycleOffset(pCont);
		int curMtlID = int(curOffset);
		_randMtlIndex(pCont)[0] = curMtlID;
		for(int i=1; i<intervalDelta; i++) {
			float addOffset = rateSec/TIME_TICKSPERSEC;
			curOffset += addOffset;
			if (int(curOffset) != curMtlID) {
				curOffset = randGen->Rand0X(numSubMtls-1) + (curOffset - floor(curOffset));
				curMtlID = int(curOffset);
			}
			_randMtlIndex(pCont)[i] = curMtlID;
			_cycleOffset(pCont) = curOffset;
		}
	}

	float curCycleOffset = _cycleOffset(pCont);
	float ratePerPart = pblock()->GetFloat(kMaterialStatic_ratePerParticle, timeEnd);

	for(i=0; i<count; i++) {
		if (!chNew->IsNew(i)) continue; // the ID is already set
		switch(type) {
		case kMaterialStatic_type_id:
			mtlID = GetPFInt(pblock(), kMaterialStatic_materialID, chTime->GetValue(i).TimeValue());
			mtlID--;
			break;
		case kMaterialStatic_type_cycle:
			if (rateType == kMaterialStatic_rateType_second) {
				float timeDelta = float(chTime->GetValue(i) - timeStart);
				float addOffset = timeDelta*rateSec/TIME_TICKSPERSEC;
				mtlID = int(curCycleOffset + addOffset);
				if (mtlID >= numSubMtls) {
					if (cycleLoop) mtlID = mtlID%numSubMtls;
					else mtlID = numSubMtls - 1;
				}
			} else { // per particle rate type
				mtlID = int(curCycleOffset);
				if (mtlID >= numSubMtls) {
					if (cycleLoop) mtlID = mtlID%numSubMtls;
					else mtlID = numSubMtls - 1;
				}
				if (ratePart > 0.0f) {
					curCycleOffset += 1.0f/ratePart;
					if (curCycleOffset >= numSubMtls) {
						if (cycleLoop) curCycleOffset -= numSubMtls*int(curCycleOffset/numSubMtls);
						else curCycleOffset = numSubMtls - 1.0f;
					}
				}
			}
			break;
		case kMaterialStatic_type_random:
			if (rateType == kMaterialStatic_rateType_second) {
				int timeDelta = int( chTime->GetValue(i) - timeStart.TimeValue() );
				mtlID = _randMtlIndex(pCont)[timeDelta];
			} else { // per particle rate type
				mtlID = int(curCycleOffset);
				int oldMtlID = mtlID;
				if (mtlID >= numSubMtls) {
					if (cycleLoop) mtlID = mtlID%numSubMtls;
					else mtlID = numSubMtls - 1;
				}
				if (ratePart > 0.0f) {
					curCycleOffset += 1.0f/ratePart;
					if (int(curCycleOffset) != oldMtlID)
						curCycleOffset = randGen->Rand0X(numSubMtls-1) + (curCycleOffset - floor(curCycleOffset));
				}
			}
			break;
		default: DbgAssert(0);
		}
		if (mtlID < 0) mtlID = 0;
		chMtlIDW->SetValue(i, mtlID);
	}

	if (useRatePerPart)
		_cycleOffset(pCont) = curCycleOffset;
	
	return true;
}
コード例 #3
0
//+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+
//|							From IPFOperator								 |
//+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+
bool PFTestGoToRotation::Proceed(IObject* pCont, 
									 PreciseTimeValue timeStart, 
									 PreciseTimeValue& timeEnd,
									 Object* pSystem,
									 INode* pNode,
									 INode* actionNode,
									 IPFIntegrator* integrator)
{
	if (postProceed()) return doPostProceed(pCont, timeStart, timeEnd, pSystem, pNode, actionNode, integrator);

	if (pblock() == NULL) return false;
	IChannelContainer* chCont;
	chCont = GetChannelContainerInterface(pCont);
	if (chCont == NULL) return false;

	// acquire absolutely necessary particle channels
	IParticleChannelAmountR* chAmount = GetParticleChannelAmountRInterface(pCont);
	if (chAmount == NULL) return false; // can't find number of particles in the container
	int i, count = chAmount->Count();
	if (count == 0) return true; // no particles to modify
	IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont);
	if (chTime == NULL) return false; // can't read timing info for a particle
	IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont);
	if (chNew == NULL) return false; // can't find newly entered particles for speedGoToTarget calculation
	IParticleChannelPTVR* chBirth = GetParticleChannelBirthTimeRInterface(pCont);
	if (chBirth == NULL) return false; // can't read birth time data
	IParticleChannelQuatR* chOrient = GetParticleChannelOrientationRInterface(pCont);
	if (chOrient == NULL) return false; // can't read current orientation for a particle

	// may create and initialize spin channel if it is not present
	IParticleChannelAngAxisR* chSpinR = NULL;
	IParticleChannelAngAxisW* chSpinW = NULL;
	bool initSpin = false;
	chSpinR = (IParticleChannelAngAxisR*)chCont->EnsureInterface(PARTICLECHANNELSPINR_INTERFACE,
																ParticleChannelAngAxis_Class_ID,
																true, PARTICLECHANNELSPINR_INTERFACE,
																PARTICLECHANNELSPINW_INTERFACE, true,
																actionNode, NULL, &initSpin);
	if (chSpinR == NULL) return false; // can't read spin data
	if (initSpin) {
		chSpinW = GetParticleChannelSpinWInterface(pCont);
		if (chSpinW == NULL) return false; // can't modify spin data
	}
	if (initSpin) {
		AngAxis aa(Point3::XAxis, 0.0f);
		if (!chNew->IsAllOld())
			for(i=0; i<count; i++) {
				if (chNew->IsNew(i))
					chSpinW->SetValue(i, aa);
			}
	}

	// create channel to store the start moment of the transition process
	// the time is when a particle enters the event
	IParticleChannelPTVW* chStartTimeW = NULL;
	bool initStartTime = false;
	chStartTimeW = (IParticleChannelPTVW*)chCont->EnsureInterface(PARTICLECHANNELSTARTTIMEW_INTERFACE,
																ParticleChannelPTV_Class_ID,
																true, PARTICLECHANNELSTARTTIMER_INTERFACE,
																PARTICLECHANNELSTARTTIMEW_INTERFACE, true,
																actionNode, (Object*)this, &initStartTime);
	if (chStartTimeW == NULL) return false; // can't modify the start time
	
	// create channel to store the end moment of the transition process
	// the time is used to determine when a particle should go to the next event, and when to finish the transition process
	IParticleChannelPTVW* chEndTimeW = NULL;
	bool initEndTime = false;
	chEndTimeW = (IParticleChannelPTVW*)chCont->EnsureInterface(PARTICLECHANNELENDTIMEW_INTERFACE,
																ParticleChannelPTV_Class_ID,
																true, PARTICLECHANNELENDTIMER_INTERFACE,
																PARTICLECHANNELENDTIMEW_INTERFACE, true,
																actionNode, (Object*)this, &initEndTime);
	if (chEndTimeW == NULL) return false; // can't modify the end time

	// create channel to store info about the last time for each particle for the proceed function
	// the data is used to rollback the effect of integration to find the desirable orientation
	IParticleChannelPTVW* chProceedTimeW = NULL;
	chProceedTimeW = (IParticleChannelPTVW*)chCont->EnsureInterface(PARTICLECHANNELPROCEEDTIMEW_INTERFACE,
																ParticleChannelPTV_Class_ID,
																true, PARTICLECHANNELPROCEEDTIMER_INTERFACE,
																PARTICLECHANNELPROCEEDTIMEW_INTERFACE, false,
																actionNode, (Object*)this);
	if (chProceedTimeW == NULL) return false; // can't modify the proceed time
	for(i=0; i<count; i++) chProceedTimeW->SetValue(i, chTime->GetValue(i));

	// create channel to store info if the final rotation has been initialized
	IParticleChannelBoolW* chGotInitW = NULL;
	bool initGotInit = false;
	chGotInitW = (IParticleChannelBoolW*)chCont->EnsureInterface(PARTICLECHANNELGOTINITW_INTERFACE,
															ParticleChannelBool_Class_ID,
															true, PARTICLECHANNELGOTINITR_INTERFACE,
															PARTICLECHANNELGOTINITW_INTERFACE, true,
															actionNode, (Object*)this, &initGotInit);
	if (chGotInitW == NULL) return false; // can't modify if init data

	// create channel to store initial rotation
	IParticleChannelQuatW* chStartRotW = NULL;
	bool initStartRot = false;
	chStartRotW = (IParticleChannelQuatW*)chCont->EnsureInterface(PARTICLECHANNELSTARTROTW_INTERFACE,
																ParticleChannelQuat_Class_ID,
																true, PARTICLECHANNELSTARTROTR_INTERFACE,
																PARTICLECHANNELSTARTROTW_INTERFACE, true,
																actionNode, (Object*)this, &initStartRot);
	if (chStartRotW == NULL) return false; // can't modify the start rotation

	// create channel to store end rotation
	IParticleChannelQuatW* chEndRotW = NULL;
	bool initEndRot = false;
	chEndRotW = (IParticleChannelQuatW*)chCont->EnsureInterface(PARTICLECHANNELENDROTW_INTERFACE,
																ParticleChannelQuat_Class_ID,
																true, PARTICLECHANNELENDROTR_INTERFACE,
																PARTICLECHANNELENDROTW_INTERFACE, true,
																actionNode, (Object*)this, &initEndRot);
	if (chEndRotW == NULL) return false; // can't modify the end rotation

	// create channel to store initial spin
	IParticleChannelAngAxisW* chStartSpinW = NULL;
	bool initStartSpin = false;
	chStartSpinW = (IParticleChannelAngAxisW*)chCont->EnsureInterface(PARTICLECHANNELSTARTSPINW_INTERFACE,
																ParticleChannelAngAxis_Class_ID,
																true, PARTICLECHANNELSTARTSPINR_INTERFACE,
																PARTICLECHANNELSTARTSPINW_INTERFACE, true,
																actionNode, (Object*)this, &initStartSpin);
	if (chStartSpinW == NULL) return false; // can't modify the start rotation
	
	// create channel to store final spin rate as a float
	IParticleChannelFloatW* chEndSpinW = NULL;
	bool initEndSpin = false;
	chEndSpinW = (IParticleChannelFloatW*)chCont->EnsureInterface(PARTICLECHANNELENDSPINW_INTERFACE,
																ParticleChannelFloat_Class_ID,
																true, PARTICLECHANNELENDSPINR_INTERFACE,
																PARTICLECHANNELENDSPINW_INTERFACE, true,
																actionNode, (Object*)this, &initEndSpin);
	if (chEndSpinW == NULL) return false; // can't modify the start rotation

	int sync = pblock()->GetInt(kGoToRotation_syncBy, timeEnd);
	TimeValue time = pblock()->GetTimeValue(kGoToRotation_time, timeEnd);
	TimeValue timeVar = pblock()->GetTimeValue(kGoToRotation_variation, timeEnd);
	int matchSpin = pblock()->GetInt(kGoToRotation_matchSpin, timeEnd);
	float spin = GetPFFloat(pblock(), kGoToRotation_spin, timeEnd.TimeValue())/TIME_TICKSPERSEC;
	float spinVar = GetPFFloat(pblock(), kGoToRotation_spinVariation, timeEnd.TimeValue())/TIME_TICKSPERSEC;

	RandGenerator* randGen = randLinker().GetRandGenerator(pCont);
	if (randGen == NULL) return false;

	if (!chNew->IsAllOld()) {
		for(i=0; i<count; i++) {
			if (!chNew->IsNew(i)) continue;
			if (initStartTime) 
				chStartTimeW->SetValue(i, chTime->GetValue(i) );
			if (initEndTime) {
				PreciseTimeValue endTime(time);
				switch(sync) {
				case kGoToRotation_syncBy_age:
					endTime += chBirth->GetValue(i);
					break;
				case kGoToRotation_syncBy_event:
					endTime += chTime->GetValue(i);
					break;
				}
				if (timeVar > 0) {
					int sign = randGen->RandSign();
					endTime += PreciseTimeValue(sign*randGen->Rand0X(timeVar));
				} else {
					randGen->RandSign();
					randGen->Rand0X(10);
				}
				chEndTimeW->SetValue(i, endTime);
			}
			if (initGotInit)
				chGotInitW->SetValue(i, false);
			if (initStartRot)
				chStartRotW->SetValue(i, chOrient->GetValue(i));
			if (initEndRot)
				chEndRotW->SetValue(i, chOrient->GetValue(i));
			if (initStartSpin)
				chStartSpinW->SetValue(i, chSpinR->GetValue(i));
			if (initEndSpin) {
				float endSpin = 0;
				if (matchSpin) {
					AngAxis aa = chSpinR->GetValue(i);
					endSpin = aa.angle;
				} else endSpin = spin;
				if (spinVar > 0.0f) endSpin += spinVar*randGen->Rand11();
				else randGen->Rand11();
				chEndSpinW->SetValue(i, endSpin);
			}
		}
	}

	return true;
}
コード例 #4
0
ファイル: PFTestDuration.cpp プロジェクト: artemeliy/inf4715
//+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+
//|							From IPFTest									 |
//+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+
bool PFTestDuration::Proceed(IObject* pCont, 
							PreciseTimeValue timeStart, 
							PreciseTimeValue& timeEnd, 
							Object* pSystem, 
							INode* pNode, 
							INode* actionNode, 
							IPFIntegrator* integrator, 
							BitArray& testResult, 
							Tab<float>& testTime)
{
	TimeValue proceedTime = timeStart;
	int testType	= pblock()->GetInt(kDuration_testType, proceedTime);
	int disparity	= pblock()->GetInt(kDuration_disparity, proceedTime);

	// get channel container interface
	IChannelContainer* chCont;
	chCont = GetChannelContainerInterface(pCont);
	if (chCont == NULL) return false;

	// acquire absolutely necessary particle channels
	IParticleChannelAmountR* chAmount = GetParticleChannelAmountRInterface(pCont);
	if (chAmount == NULL) return false; // can't find number of particles in the container
	IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont);
	if (chTime == NULL) return false; // can't read timing info for a particle
	IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont);
	if (chNew == NULL) return false; // can't find newly entered particles for duration calculation

	// acquire more particle channels
	IParticleChannelPTVR* chBirthTime = NULL;
	if (testType == kDuration_testType_age)
	{
		chBirthTime = GetParticleChannelBirthTimeRInterface(pCont);
		if (chBirthTime == NULL) return false; // can't read particle age
	}
	IParticleChannelIDR* chID = NULL;
	if (disparity != 0)
	{
		chID = GetParticleChannelIDRInterface(pCont);
		if (chID == NULL) return false; // can't read particle index for first-to-last disparity
	}

	IParticleChannelPTVR* chEventStartR = NULL;
	IParticleChannelPTVW* chEventStartW = NULL;
	bool initEventStart = false;
	if (testType == kDuration_testType_event) {
		chEventStartR = (IParticleChannelPTVR*)chCont->EnsureInterface(PARTICLECHANNELEVENTSTARTR_INTERFACE,
																		ParticleChannelPTV_Class_ID,
																		true, PARTICLECHANNELEVENTSTARTR_INTERFACE,
																		PARTICLECHANNELEVENTSTARTW_INTERFACE, false,
																		actionNode, NULL, &initEventStart);
		if (chEventStartR == NULL) return false; // can't read event start time
		if (initEventStart) {
			chEventStartW = GetParticleChannelEventStartWInterface(pCont);
			if (chEventStartW == NULL) return false; // can't write event start time
		}
	}

	// acquire TestDuration private particle channel; if not present then create it		
	IParticleChannelPTVW* chTestW = (IParticleChannelPTVW*)chCont->EnsureInterface(PARTICLECHANNELTESTDURATIONW_INTERFACE,
																			ParticleChannelPTV_Class_ID,
																			true, PARTICLECHANNELTESTDURATIONR_INTERFACE,
																			PARTICLECHANNELTESTDURATIONW_INTERFACE, false,
																			actionNode, (Object*)this);
	IParticleChannelPTVR* chTestR = (IParticleChannelPTVR*)chCont->GetPrivateInterface(PARTICLECHANNELTESTDURATIONR_INTERFACE, (Object*)this);
	if ((chTestR == NULL) || (chTestW == NULL)) return false; // can't set test value for newly entered particles

	int i, count;
	PreciseTimeValue curTestValue;
	count = chAmount->Count();
	
	// check if all particles are "old". If some particles are "new" then we
	// have to calculate test values for those.
	if (!chNew->IsAllOld())
	{
		TimeValue testValue	= pblock()->GetTimeValue(kDuration_testValue, proceedTime);
		TimeValue variation = pblock()->GetTimeValue(kDuration_variation, proceedTime);
		int subframe		= pblock()->GetInt(kDuration_subframeSampling, proceedTime);
		TimeValue testFirst = pblock()->GetInt(kDuration_testFirst, proceedTime);
		TimeValue testLast	= pblock()->GetInt(kDuration_testLast, proceedTime);
		TimeValue lastIndex = pblock()->GetInt(kDuration_lastIndex, proceedTime);
		if (lastIndex <= 0) lastIndex = 1;
		int tpf = GetTicksPerFrame();

		RandGenerator* randGen = NULL;
		if (variation != 0) randGen = randLinker().GetRandGenerator(pCont);
		
		int index;
		for(i=0; i<count; i++) 
			if (chNew->IsNew(i)) // calculate test value only for new particles
			{
				if (disparity) {
					index = chID->GetParticleIndex(i);
					if (index > lastIndex) 
						curTestValue = PreciseTimeValue( testLast );
					else 
						curTestValue = PreciseTimeValue( testFirst + (testLast-testFirst)*(float(index)/lastIndex) );
				} else
					curTestValue = PreciseTimeValue( testValue );

				if (variation != 0)
					curTestValue += PreciseTimeValue( randGen->Rand11()*variation );

				// adjust test value according to test type
				if (testType == kDuration_testType_age)
					curTestValue += chBirthTime->GetValue(i);
				else if (testType == kDuration_testType_event) {
					if (initEventStart)
						chEventStartW->SetValue(i, chTime->GetValue(i));
					curTestValue += chEventStartR->GetValue(i);
				}

				if (!subframe) // round the test value to the nearest frame
					curTestValue = PreciseTimeValue(int(floor(TimeValue(curTestValue)/float(tpf) + 0.5f) * tpf));

				chTestW->SetValue(i, curTestValue);
			}
	}
	
	// test all particles
	PreciseTimeValue curParticleValue;
	testResult.SetSize(count);
	testResult.ClearAll();
	testTime.SetCount(count);
	int condType = pblock()->GetInt(kDuration_conditionType, proceedTime);
	BitArray particlesToAdvance;
	particlesToAdvance.SetSize(count);
	particlesToAdvance.ClearAll();
	for(i=0; i<count; i++)
	{
		curTestValue = chTestR->GetValue(i);
		curParticleValue = chTime->GetValue(i);
		if (curParticleValue > timeEnd) continue; // particle has been proceeded beyond 
												  // the testing interval [timeStart,timeEnd]
		switch( condType )
		{
		case kDuration_conditionType_less:
			if (curParticleValue <= curTestValue)
			{ // particle doesn't need to be advanced in "time" since the current time value is the condition value
				testResult.Set(i);
				testTime[i] = float( curParticleValue - timeStart );
			}
			break;
		case kDuration_conditionType_greater:
			if (timeEnd < curTestValue) break;	// particle won't satisfy the condition 
												// even at the end of the test interval			
			if (curParticleValue >= curTestValue)
			{ // particle doesn't need to be advanced in "time" since the current time value is more than satisfactory
				testResult.Set(i);
				testTime[i] = float( curParticleValue - timeStart );
				break;
			}

			testResult.Set(i);
			testTime[i] = float( curTestValue - timeStart );
			// the particle needs to be advanced in time if possible
			particlesToAdvance.Set(i);
			break;
		default:
			DbgAssert(0);
			break;
		}
	}

	// advance particles in time if they satisfy the condition and need to be pushed forward
	if (integrator != NULL)
	{
		Tab<PreciseTimeValue> timeToAdvance;
		timeToAdvance.SetCount(count);
		for(i=0; i<count; i++)
			if (particlesToAdvance[i] != 0)
				timeToAdvance[i] = timeStart + testTime[i];
		integrator->Proceed(pCont, timeToAdvance, particlesToAdvance);
	}

	return true;
}