Ejemplo n.º 1
0
//+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+
//|							From IPFTest									 |
//+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+
bool PFTestGoToRotation::Proceed(IObject* pCont, 
							PreciseTimeValue timeStart, 
							PreciseTimeValue& timeEnd, 
							Object* pSystem, 
							INode* pNode, 
							INode* actionNode, 
							IPFIntegrator* integrator, 
							BitArray& testResult, 
							Tab<float>& testTime)
{

	if (pblock() == NULL) return false;
	// 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
	int i, count = chAmount->Count();
	if (count == 0) return true; // no particles to test
	IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont);
	if (chTime == NULL) return false; // can't read timing info for a particle
	IParticleChannelQuatW* chOrientW = GetParticleChannelOrientationWInterface(pCont);
	if (chOrientW == NULL) return false; // can't modify current orientation for a particle
	IParticleChannelAngAxisR* chSpinR = GetParticleChannelSpinRInterface(pCont);
	if (chSpinR == NULL) return false; // can't read current spin for a particle
	IParticleChannelAngAxisW* chSpinW = GetParticleChannelSpinWInterface(pCont);
	if (chSpinW == NULL) return false; // can't modify current spin for a particle

	// acquire private channels
	IParticleChannelPTVR* chEndTime = (IParticleChannelPTVR*)(chCont->GetPrivateInterface(PARTICLECHANNELENDTIMER_INTERFACE, (Object*)this));
	if (chEndTime == NULL) return false;
	IParticleChannelBoolR* chGotInitR = (IParticleChannelBoolR*)(chCont->GetPrivateInterface(PARTICLECHANNELGOTINITR_INTERFACE, (Object*)this));
	if (chGotInitR == NULL) return false;
	IParticleChannelQuatR* chEndRotR = (IParticleChannelQuatR*)(chCont->GetPrivateInterface(PARTICLECHANNELENDROTR_INTERFACE, (Object*)this));
	if (chEndRotR == NULL) return false;
	IParticleChannelFloatR* chEndSpin = (IParticleChannelFloatR*)(chCont->GetPrivateInterface(PARTICLECHANNELENDSPINR_INTERFACE, (Object*)this));
	if (chEndSpin == NULL) return false;

	bool sendOut = (pblock()->GetInt(kGoToRotation_sendOut, timeEnd) != 0);
	bool stopSpin = (pblock()->GetInt(kGoToRotation_stopSpin, timeEnd) != 0);

	// test all particles
	PreciseTimeValue curTime;
	testResult.SetSize(count);
	testResult.ClearAll();
	testTime.SetCount(count);
	BitArray particlesToAdvance;
	particlesToAdvance.SetSize(count);
	particlesToAdvance.ClearAll();
	for(i=0; i<count; i++)
	{
		curTime = chEndTime->GetValue(i);
		if (curTime > timeEnd) continue;
		if (curTime < timeStart) {
			testTime[i] = float(chTime->GetValue(i) - timeStart);
		} else {
			testTime[i] = float(curTime - timeStart);
			particlesToAdvance.Set(i);
		}
		testResult.Set(i);
	}

	// 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);
	}

	for(i=0; i<count; i++) {
		if (particlesToAdvance[i] == 0) continue;

		Quat curRot = chEndRotR->GetValue(i);

		chOrientW->SetValue(i, chEndRotR->GetValue(i));
		AngAxis spin = chSpinR->GetValue(i);
		spin.angle = stopSpin ? 0.0f : chEndSpin->GetValue(i);
		chSpinW->SetValue(i, spin);
	}

	if (!sendOut) testResult.ClearAll();

	return true;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
bool PFTestGoToRotation::doPostProceed(IObject* pCont, 
									 PreciseTimeValue timeStart, 
									 PreciseTimeValue& timeEnd,
									 Object* pSystem,
									 INode* pNode,
									 INode* actionNode,
									 IPFIntegrator* 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
	IParticleChannelQuatR* chOrientR = GetParticleChannelOrientationRInterface(pCont);
	if (chOrientR == NULL) return false; // can't read current orientation for a particle
	IParticleChannelQuatW* chOrientW = GetParticleChannelOrientationWInterface(pCont);
	if (chOrientW == NULL) return false; // can't modify current orientation for a particle
	IParticleChannelAngAxisR* chSpinR = GetParticleChannelSpinRInterface(pCont);
	if (chSpinR == NULL) return false; // can't read current spin for a particle
	IParticleChannelAngAxisW* chSpinW = GetParticleChannelSpinWInterface(pCont);
	if (chSpinW == NULL) return false; // can't modify current spin for a particle

	// acquire private channels
	IParticleChannelPTVR* chStartTime = (IParticleChannelPTVR*)(chCont->GetPrivateInterface(PARTICLECHANNELSTARTTIMER_INTERFACE, (Object*)this));
	if (chStartTime == NULL) return false;
	IParticleChannelPTVR* chEndTime = (IParticleChannelPTVR*)(chCont->GetPrivateInterface(PARTICLECHANNELENDTIMER_INTERFACE, (Object*)this));
	if (chEndTime == NULL) return false;
	IParticleChannelPTVR* chProceedTime = (IParticleChannelPTVR*)(chCont->GetPrivateInterface(PARTICLECHANNELPROCEEDTIMER_INTERFACE, (Object*)this));
	if (chProceedTime == NULL) return false;
		
	int targetType = pblock()->GetInt(kGoToRotation_targetType, timeEnd);
	bool initOnce = (targetType == kGoToRotation_targetType_constant);
	IParticleChannelBoolR* chGotInitR = (IParticleChannelBoolR*)(chCont->GetPrivateInterface(PARTICLECHANNELGOTINITR_INTERFACE, (Object*)this));
	IParticleChannelBoolW* chGotInitW = (IParticleChannelBoolW*)(chCont->GetPrivateInterface(PARTICLECHANNELGOTINITW_INTERFACE, (Object*)this));
	if ((chGotInitR == NULL) || (chGotInitW == NULL)) return false;

	IParticleChannelQuatR* chStartRot = (IParticleChannelQuatR*)(chCont->GetPrivateInterface(PARTICLECHANNELSTARTROTR_INTERFACE, (Object*)this));
	if (chStartRot == NULL) return false;
	IParticleChannelQuatR* chEndRotR = (IParticleChannelQuatR*)(chCont->GetPrivateInterface(PARTICLECHANNELENDROTR_INTERFACE, (Object*)this));
	if (chEndRotR == NULL) return false;
	IParticleChannelQuatW* chEndRotW = (IParticleChannelQuatW*)(chCont->GetPrivateInterface(PARTICLECHANNELENDROTW_INTERFACE, (Object*)this));
	if (chEndRotW == NULL) return false;
	
	IParticleChannelAngAxisR* chStartSpin = (IParticleChannelAngAxisR*)(chCont->GetPrivateInterface(PARTICLECHANNELSTARTSPINR_INTERFACE, (Object*)this));
	if (chStartSpin == NULL) return false;
	IParticleChannelFloatR* chEndSpin = (IParticleChannelFloatR*)(chCont->GetPrivateInterface(PARTICLECHANNELENDSPINR_INTERFACE, (Object*)this));
	if (chEndSpin == NULL) return false;
	
	float easyIn = GetPFFloat(pblock(), kGoToRotation_easeIn, timeEnd.TimeValue() );

	// particle properties modification
	for(i=0; i<count; i++) {
		// if the particle out of the transition period then do nothing
		PreciseTimeValue startT = chStartTime->GetValue(i);
		PreciseTimeValue endT = chEndTime->GetValue(i);
		if (endT < timeEnd) continue;
		if (endT <= startT) continue;

		// rollback the current rotation: remove the effect of the integration to know the real orientation value
		// need that if not initialized, or the target rotation is changing
		Quat curOrient = chOrientR->GetValue(i);
		bool needRollback = true;
		if (initOnce)
			if (chGotInitR->GetValue(i)) needRollback = false;
		if (needRollback) {
			AngAxis curSpin = chSpinR->GetValue(i);
			float timeDif = float(timeEnd - chProceedTime->GetValue(i));
			curSpin.angle *= -timeDif;
			curOrient += Quat(curSpin);
		}
		if (initOnce) {
			if (!chGotInitR->GetValue(i)) {
				chEndRotW->SetValue(i, curOrient);
			}
		} else {
			chEndRotW->SetValue(i, curOrient);
		}
		chGotInitW->SetValue(i, true);
	
		Quat resRot;
		AngAxis resSpin;
		InterpolateRotation(chStartRot->GetValue(i), chEndRotR->GetValue(i), chStartSpin->GetValue(i),
							chEndSpin->GetValue(i), startT, endT, timeEnd,
							easyIn, initOnce, resRot, resSpin);
		chOrientW->SetValue(i, resRot);
		chSpinW->SetValue(i, resSpin);
	}

	return true;
}
bool PFOperatorSimpleOrientation::Proceed(IObject* pCont, 
									 PreciseTimeValue timeStart, 
									 PreciseTimeValue& timeEnd,
									 Object* pSystem,
									 INode* pNode,
									 INode* actionNode,
									 IPFIntegrator* integrator)
{
	// acquire all necessary channels, create additional if needed
	IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont);
	if(chNew == NULL) return false;
	IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont);
	if(chTime == NULL) return false;
	IParticleChannelAmountR* chAmount = GetParticleChannelAmountRInterface(pCont);
	if(chAmount == NULL) return false;

	// there are no new particles
//	if (chNew->IsAllOld()) return true;

	// we may need speed channel for "Speed Space" and "Speed Space Follow" types
	IParticleChannelPoint3R* chSpeed;
	int iDir = pblock()->GetInt(kSimpleOrientation_direction, 0);
	if ((iDir == kSO_Speed) || (iDir == kSO_SpeedFollow))
		chSpeed = GetParticleChannelSpeedRInterface(pCont);
	bool bRestrictToAxis = (pblock()->GetInt(kSimpleOrientation_restrictToAxis, 0) != 0);

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

	// the channel of interest
	IParticleChannelQuatW* chOrient = (IParticleChannelQuatW*)chCont->EnsureInterface(PARTICLECHANNELORIENTATIONW_INTERFACE,
																			ParticleChannelQuat_Class_ID,
																			true, PARTICLECHANNELORIENTATIONR_INTERFACE,
																			PARTICLECHANNELORIENTATIONW_INTERFACE, true );
	if (chOrient == NULL) return false;

	RandGenerator* prg = randLinker().GetRandGenerator(pCont);
	Matrix3 m3Orient;
	float fEulerAng[3];
	int iQuant = chAmount->Count();
	for(int i = 0; i < iQuant; i++) {
		if((chNew->IsNew(i)) || (iDir == kSO_SpeedFollow)) { // apply only to new particles or to all for "follow" type
			TimeValue tv = chTime->GetValue(i).TimeValue();
			// set particle direction in user selected direction
			switch(iDir) {
				case kSO_Rand_3D: {
						Point3 p3x = RandSphereSurface(prg);
						Point3 p3y = RandSphereSurface(prg);
						while(p3x == p3y)
							p3y = RandSphereSurface(prg);
						p3y = Normalize(p3y - p3x * DotProd(p3x, p3y));
						Point3 p3z = p3x ^ p3y;
						m3Orient = Matrix3(p3x, p3y, p3z, Point3::Origin);
					}
					break;
				case kSO_Rand_Horiz: {
						fEulerAng[0] = fEulerAng[1] = 0.0f;
						fEulerAng[2] = TWOPI * prg->Rand01();
						EulerToMatrix(fEulerAng, m3Orient, EULERTYPE_XYZ);
					}
					break;
				case kSO_World: {
						fEulerAng[0] = GetPFFloat(pblock(), kSimpleOrientation_x, tv);
						fEulerAng[1] = GetPFFloat(pblock(), kSimpleOrientation_y, tv);
						fEulerAng[2] = GetPFFloat(pblock(), kSimpleOrientation_z, tv);
						EulerToMatrix(fEulerAng, m3Orient, EULERTYPE_XYZ);
					}
					break;
				case kSO_Speed:
				case kSO_SpeedFollow: {
						fEulerAng[0] = GetPFFloat(pblock(), kSimpleOrientation_x, tv);
						fEulerAng[1] = GetPFFloat(pblock(), kSimpleOrientation_y, tv);
						fEulerAng[2] = GetPFFloat(pblock(), kSimpleOrientation_z, tv);
						if (chSpeed != NULL)
							m3Orient = SpeedSpaceMatrix(chSpeed->GetValue(i));
						else
							m3Orient = Matrix3(Point3::XAxis, Point3::YAxis, Point3::ZAxis, Point3::Origin);
//						m3Orient.SetRotate(Quat(m3Orient));
						Matrix3 eulerRot;
						EulerToMatrix(fEulerAng, eulerRot, EULERTYPE_XYZ);
//						m3Orient = m3Orient * eulerRot;
						m3Orient = eulerRot * m3Orient;
					}
					break;
			}
			// account for divergence parameter
			if ((iDir != kSO_SpeedFollow) && (iDir != kSO_Rand_3D)) {
				float fDiv = GetPFFloat(pblock(), kSimpleOrientation_divergence, tv);
				Point3 p3RotAxis = RandSphereSurface(prg);
				if(fDiv > 0.f) {
					if (bRestrictToAxis) {
						p3RotAxis.x = GetPFFloat(pblock(), kSimpleOrientation_axisX, tv);
						p3RotAxis.y = GetPFFloat(pblock(), kSimpleOrientation_axisY, tv);
						p3RotAxis.z = GetPFFloat(pblock(), kSimpleOrientation_axisZ, tv);
						if (LengthSquared(p3RotAxis) > 0.0f) {
							p3RotAxis = Normalize(p3RotAxis);
						} else {
							p3RotAxis = Point3::XAxis;
							fDiv = 0.0f;
						}
					}
					float fRandDiv = fDiv * prg->Rand11();
					m3Orient = m3Orient * RotAngleAxisMatrix(p3RotAxis, fRandDiv);
				} else { // perform operations that change randomness state
					prg->Rand11();
				}
			}
			chOrient->SetValue(i, Quat(m3Orient));
		}
	}

	return true;
}