bool PFOperatorForceSpaceWarp::Proceed(IObject* pCont, 
									 PreciseTimeValue timeStart, 
									 PreciseTimeValue& timeEnd,
									 Object* pSystem,
									 INode* pNode,
									 INode* actionNode,
									 IPFIntegrator* integrator)
{
	// acquire all necessary channels, create additional if needed

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

	IParticleChannelAmountR* chAmount = GetParticleChannelAmountRInterface(pCont);
	if(chAmount == NULL) return false;
	int iQuant = chAmount->Count();
	if (iQuant < 1) return true; // no particles to proceed

	IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont);
	if (chNew == NULL) return false; 

	IParticleChannelIDR* chID = GetParticleChannelIDRInterface(pCont);
	if (chID == NULL) return false;

	IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont);
	if(chTime == NULL) return false;

	IParticleChannelPTVR* chAge = GetParticleChannelBirthTimeRInterface(pCont);
	if(chAge == NULL) return false;

// the channel of interest speed
	bool initSpeed = false;
//channel does not exist so make it and note that we have to fill it out
	IParticleChannelPoint3W* chSpeedW = (IParticleChannelPoint3W*)chCont->EnsureInterface(PARTICLECHANNELSPEEDW_INTERFACE,
																			ParticleChannelPoint3_Class_ID,
																			true, PARTICLECHANNELSPEEDR_INTERFACE,
																			PARTICLECHANNELSPEEDW_INTERFACE, true,
																			actionNode, NULL, &initSpeed);
	IParticleChannelPoint3R* chSpeed = GetParticleChannelSpeedRInterface(pCont);
	if ((chSpeedW == NULL) || (chSpeed == NULL)) return false;

	bool initPosition = false;
	IParticleChannelPoint3W* chPosW = (IParticleChannelPoint3W*)chCont->EnsureInterface(PARTICLECHANNELPOSITIONW_INTERFACE,
																			ParticleChannelPoint3_Class_ID,
																			true, PARTICLECHANNELPOSITIONR_INTERFACE,
																			PARTICLECHANNELPOSITIONW_INTERFACE, true,
																			actionNode, NULL, &initPosition);
	IParticleChannelPoint3R* chPos = GetParticleChannelPositionRInterface(pCont);
	if ((chPosW == NULL) || (chPos == NULL)) return false;

	bool useScript = ((scriptPBlock()->GetInt(kForceSpaceWarp_useScriptWiring, 0) != 0)
						&& (scriptPBlock()->GetInt(kForceSpaceWarp_useFloat, 0) == kForceSpaceWarp_useFloat_influence));
	IParticleChannelFloatR* chFloat = NULL;
	if (useScript) {
		chFloat = GetParticleChannelMXSFloatRInterface(pCont);
		if (chFloat == NULL) return false;
	}

	int timeType = kAbsoluteTime;
	_pblock()->GetValue(kForceSpaceWarp_Sync,0, timeType, FOREVER);

	IParticleChannelPTVR* chEventStart = NULL;
	IParticleChannelPTVW* chEventStartW = NULL;
	bool initEventStart = false;
	if (timeType == kEventDuration)
	{
		chEventStartW = (IParticleChannelPTVW*) chCont->EnsureInterface(PARTICLECHANNELEVENTSTARTW_INTERFACE,
								  ParticleChannelPTV_Class_ID,
								  true, PARTICLECHANNELEVENTSTARTR_INTERFACE,
								  PARTICLECHANNELEVENTSTARTW_INTERFACE, false,
								  actionNode, NULL, &initEventStart);

		chEventStart = GetParticleChannelEventStartRInterface(pCont);
		if ((chEventStart == NULL) || (chEventStartW == NULL)) return false;
	}

	int overlapping = pblock()->GetInt(kForceSpaceWarp_Overlapping, 0);
	// collecting force fields
	Tab<ForceField*> ff;
	ForceField* curFF;
	int i, j;
	for(i=0; i<pblock()->Count(kForceSpaceWarp_ForceNodeList); i++) {
		INode* node = pblock()->GetINode(kForceSpaceWarp_ForceNodeList, 0, i);
		if (node == NULL) continue;
		Object* ob = GetPFObject(node->GetObjectRef());
		if (ob == NULL) continue;
		if (ob->SuperClassID() == WSM_OBJECT_CLASS_ID) {
			WSMObject* obref = (WSMObject*)ob;
			curFF = obref->GetForceField(node);
			if (curFF != NULL) {
				if (ob->ClassID() == CS_VFIELDOBJECT_CLASS_ID) {
					// CS VectorField SW doesn't init properly partobj on GetForceField
					// this is a quick fix for that (bayboro 3/6/2003)
					CS_VectorField* vf = (CS_VectorField*)curFF;
					vf->partobj = GetParticleInterface(pSystem);
				}
				ff.Append(1, &curFF);
			}
		}
	}
	if (ff.Count() == 0) return true; // no force fields

	// some calls for a reference node TM may initiate REFMSG_CHANGE notification
	// we have to ignore that while processing the particles
	bool wasIgnoring = IsIgnoringRefNodeChange();
	if (!wasIgnoring) SetIgnoreRefNodeChange();

	float influence = 0.0f;
	for(i = 0; i < iQuant; i++) 
	{
		TimeValue t = 0;
		if (timeType == kAbsoluteTime)
			t = chTime->GetValue(i).TimeValue();
		else if (timeType == kParticleAge)
			t = chTime->GetValue(i).TimeValue() - chAge->GetValue(i).TimeValue();
		else 
		{
			if (initEventStart && chNew->IsNew(i))
				chEventStartW->SetValue(i, chTime->GetValue(i));
			t = chTime->GetValue(i).TimeValue() - chEventStart->GetValue(i).TimeValue();
		}

		if (useScript) {
			influence = chFloat->GetValue(i);
		} else {
			influence = GetPFFloat(pblock(), kForceSpaceWarp_Influence, t);
		}

		Point3 v(0.0f,0.0f,0.0f);
		if (!initSpeed || !chNew->IsNew(i)) //if we created a speed channel the channel incoming is bogus so just use 0,0,0 ad default
			v = chSpeed->GetValue(i);

		Point3 p(0.0f,0.0f,0.0f);
		if (!initPosition || !chNew->IsNew(i)) //if we created a pos channel the channel incoming is bogus so just use 0,0,0 ad default
			p = chPos->GetValue(i);

		Point3 force = Point3::Origin;
		for(j=0; j<ff.Count(); j++) {
			// buffer vectors to guard true position and speed from malicious force
			Point3 pp = p;
			Point3 vv = v;
			Point3 nextForce = ff[j]->Force(t,pp,vv,chID->GetParticleBorn(i)) * influence;
			float lenSq = LengthSquared(nextForce);
			if (lenSq <= 0.0f) continue; // not a valid force
			if (overlapping == kForceSpaceWarp_Overlapping_additive) {
				force += nextForce;
			} else {
				if (lenSq > LengthSquared(force))
					force = nextForce;
			}
//			p = pp;
//			v = vv;
		}

		v += force * float(timeEnd - chTime->GetValue(i));
		chPosW->SetValue(i, p);
		chSpeedW->SetValue(i, v);
	}

	for(i=0; i<ff.Count(); i++)
		if (ff[i] != NULL) ff[i]->DeleteThis();

	if (!wasIgnoring) ClearIgnoreRefNodeChange();
	return true;
}
bool PFOperatorSimpleSpeed::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;
	// the position channel may not be present. For some option configurations it is okay
	IParticleChannelPoint3R* chPos = GetParticleChannelPositionRInterface(pCont);
	int iDir = _pblock()->GetInt(kSimpleSpeed_direction, timeStart);
	if ((chPos == NULL) && ((iDir == kSS_Icon_Center_Out) || (iDir == kSS_Icon_Arrow_Out)))
		return false;

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

	// the channel of interest
	bool initSpeed = false;
	IParticleChannelPoint3W* chSpeed = (IParticleChannelPoint3W*)chCont->EnsureInterface(PARTICLECHANNELSPEEDW_INTERFACE,
																			ParticleChannelPoint3_Class_ID,
																			true, PARTICLECHANNELSPEEDR_INTERFACE,
																			PARTICLECHANNELSPEEDW_INTERFACE, true,
																			actionNode, (Object*)NULL, &initSpeed);
	IParticleChannelPoint3R* chSpeedR = GetParticleChannelSpeedRInterface(pCont);
	if ((chSpeed == NULL) || (chSpeedR == NULL)) return false;

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

	float fUPFScale = 1.0f/TIME_TICKSPERSEC; // conversion units per seconds to units per tick
	Point3 pt3SpeedVec;
	RandGenerator* prg = randLinker().GetRandGenerator(pCont);
	int iQuant = chAmount->Count();
	bool wasIgnoringEmitterTMChange = IsIgnoringEmitterTMChange();
	if (!wasIgnoringEmitterTMChange) SetIgnoreEmitterTMChange();
	for(int i = 0; i < iQuant; i++) {
		if(chNew->IsNew(i)) { // apply only to new particles
			TimeValue tv = chTime->GetValue(i).TimeValue();
			Matrix3 nodeTM = pNode->GetObjectTM(tv);
			float fSpeedParam = fUPFScale * GetPFFloat(pblock(), kSimpleSpeed_speed, tv);
			// change speed in user selected direction
			switch(iDir) {
				case kSS_Along_Icon_Arrow: {
						// icon arrow appears to be in the negative z direction
						pt3SpeedVec = -Normalize(nodeTM.GetRow(2));
					}
					break;
				case kSS_Icon_Center_Out: {
						Point3 pt3IconCenter = nodeTM.GetTrans();
						Point3 pt3PartPos = chPos->GetValue(i);
						pt3SpeedVec = Normalize(pt3PartPos - pt3IconCenter);
					}
					break;
				case kSS_Icon_Arrow_Out: {
						Point3 pt3PartPos = chPos->GetValue(i);
						Point3 pt3ArrowVec = nodeTM.GetRow(2);
						Point3 pt3Tmp = CrossProd(pt3PartPos - nodeTM.GetTrans(), pt3ArrowVec);
						pt3SpeedVec = Normalize(CrossProd(pt3ArrowVec, pt3Tmp));
					}
					break;
				case kSS_Rand_3D: {
						pt3SpeedVec = RandSphereSurface(prg);
					}
					break;
				case kSS_Rand_Horiz: {
						float fAng = TWOPI * prg->Rand01();
						// establish x, y coordinates of random angle, z component zero
						float x = cos(fAng); float y = sin(fAng); float z = 0.0f;
						pt3SpeedVec = Point3(x, y, z);
					}
					break;
				case kSS_Inherit_Prev: {
						if (initSpeed) 
							pt3SpeedVec = Point3::Origin;
						else
							pt3SpeedVec = Normalize(chSpeedR->GetValue(i));
					}
					break;
			}
			// account for reverse check box
			int iRev = _pblock()->GetInt(kSimpleSpeed_reverse, 0);
			float fDirMult = iRev > 0 ? -1.f : 1.f;
			// calculate variation
			float fVar = fUPFScale * GetPFFloat(pblock(), kSimpleSpeed_variation, tv);
			if(fVar > 0.f)
				fSpeedParam = fSpeedParam + fVar * prg->Rand11();
			pt3SpeedVec = fDirMult * fSpeedParam * pt3SpeedVec;
			// calculate divergence
			float fDiv = GetPFFloat(pblock(), kSimpleSpeed_divergence, tv);
			pt3SpeedVec = DivergeVectorRandom(pt3SpeedVec, prg, fDiv);

			chSpeed->SetValue(i, pt3SpeedVec);
		}
	}
	if (!wasIgnoringEmitterTMChange) ClearIgnoreEmitterTMChange();

	return true;
}
Example #3
0
//+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+
//|							From IPFTest									 |
//+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+
bool PFTestSpeed::Proceed(IObject* pCont, 
							PreciseTimeValue timeStart, 
							PreciseTimeValue& timeEnd, 
							Object* pSystem, 
							INode* pNode, 
							INode* actionNode, 
							IPFIntegrator* integrator, 
							BitArray& testResult, 
							Tab<float>& testTime)
{
	bool exactStep = IsExactIntegrationStep(timeEnd, pSystem);

	// get the constant properties of the test
	int testType = pblock()->GetInt(kSpeedTest_testType, timeEnd);
	int condType = pblock()->GetInt(kSpeedTest_conditionType, timeEnd);
	int syncType = pblock()->GetInt(kSpeedTest_sync, timeEnd);
	ParamID varParamID = (testType == kSpeedTest_testType_steering) ? kSpeedTest_angleVariation : kSpeedTest_unitVariation;
	bool hasTestVariation = (pblock()->GetFloat(varParamID, 0) != 0.0f);
	if (!hasTestVariation) {
		Control* ctrl = pblock()->GetControllerByID(varParamID);
		if (ctrl != NULL)
			hasTestVariation = (ctrl->IsAnimated() != 0);
	}
	if (testType >= kSpeedTest_testType_whenAccels) {
		hasTestVariation = false;
		syncType = kSpeedTest_sync_time;
	}
	bool needPrevValue = (testType >= kSpeedTest_testType_accel);

	// 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 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
	IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont);
	if (chNew == NULL) return false; // can't find newly entered particles for duration calculation
	IParticleChannelPoint3R* chSpeed = GetParticleChannelSpeedRInterface(pCont);
	if (chSpeed == NULL) return false; // can't read speed values

	// acquire more particle channels
	IParticleChannelPTVR* chBirthTime = NULL;
	if (syncType == kSpeedTest_sync_age && (testType < kSpeedTest_testType_whenAccels))
	{
		chBirthTime = GetParticleChannelBirthTimeRInterface(pCont);
		if (chBirthTime == NULL) return false; // can't read particle age
	}
	IParticleChannelPTVR* chEventStartR = NULL;
	IParticleChannelPTVW* chEventStartW = NULL;
	bool initEventStart = false;
	if (syncType == kSpeedTest_sync_event && (testType < kSpeedTest_testType_whenAccels)) {
		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
		}
	}
	IParticleChannelFloatR* chRandFloatR = NULL;
	IParticleChannelFloatW* chRandFloatW = NULL;
	bool initRandFloat = false;
	if (hasTestVariation) {
		chRandFloatW = (IParticleChannelFloatW*)chCont->EnsureInterface(PARTICLECHANNELRANDFLOATW_INTERFACE,
																		ParticleChannelFloat_Class_ID,
																		true, PARTICLECHANNELRANDFLOATR_INTERFACE,
																		PARTICLECHANNELRANDFLOATW_INTERFACE, true,
																		actionNode, (Object*)this, &initRandFloat);
		chRandFloatR = (IParticleChannelFloatR*)chCont->GetPrivateInterface(PARTICLECHANNELRANDFLOATR_INTERFACE, (Object*)this);
		if ((chRandFloatR == NULL) || (chRandFloatW == NULL)) return false; // can't set rand float value for newly entered particles
	}
	IParticleChannelPoint3R* chPrevSpeedR = NULL;
	IParticleChannelPoint3W* chPrevSpeedW = NULL;
	IParticleChannelPTVR* chPrevTimeR = NULL;
	IParticleChannelPTVW* chPrevTimeW = NULL;
	bool initPrevValue = false;
	if (needPrevValue) {
		chPrevSpeedW = (IParticleChannelPoint3W*)chCont->EnsureInterface(PARTICLECHANNELPREVSPEEDW_INTERFACE,
																		ParticleChannelPoint3_Class_ID,
																		true, PARTICLECHANNELPREVSPEEDR_INTERFACE,
																		PARTICLECHANNELPREVSPEEDW_INTERFACE, true,
																		actionNode, (Object*)this, &initPrevValue);
		chPrevSpeedR = (IParticleChannelPoint3R*)chCont->GetPrivateInterface(PARTICLECHANNELPREVSPEEDR_INTERFACE, (Object*)this);
		chPrevTimeW = (IParticleChannelPTVW*)chCont->EnsureInterface(PARTICLECHANNELPREVTIMEW_INTERFACE,
																		ParticleChannelPTV_Class_ID,
																		true, PARTICLECHANNELPREVTIMER_INTERFACE,
																		PARTICLECHANNELPREVTIMEW_INTERFACE, true,
																		actionNode, (Object*)this, &initPrevValue);
		chPrevTimeR = (IParticleChannelPTVR*)chCont->GetPrivateInterface(PARTICLECHANNELPREVTIMER_INTERFACE, (Object*)this);
		if ((chPrevSpeedR == NULL) || (chPrevSpeedW == NULL) || (chPrevTimeR == NULL) || (chPrevTimeW == NULL)) return false; 
	}

	// grab the rand generator for test variation
	RandGenerator* randGen = randLinker().GetRandGenerator(pCont);
	if (randGen == NULL) return false;

	// check all particles
	testResult.SetSize(count);
	testResult.ClearAll();
	testTime.SetCount(count);
	for(int i=0; i<count; i++)
	{
		if (chNew->IsNew(i)) { // initialize some channels
			if (initEventStart)
				chEventStartW->SetValue(i, chTime->GetValue(i));
			if (initRandFloat)
				chRandFloatW->SetValue(i, randGen->Rand11());
		}

		PreciseTimeValue prevTime;
		Point3 prevSpeed;
		Point3 currentSpeed = chSpeed->GetValue(i);
		PreciseTimeValue currentTime = chTime->GetValue(i);
		if (needPrevValue) {
			prevTime = chPrevTimeR->GetValue(i);
			prevSpeed = chPrevSpeedR->GetValue(i);
			chPrevTimeW->SetValue(i, currentTime);
			chPrevSpeedW->SetValue(i, currentSpeed);
			if (initPrevValue && chNew->IsNew(i))
				continue; // particle just came into the event and doesn't have previous value
		}

		PreciseTimeValue syncTime = currentTime;
		switch(syncType) {
		case kSpeedTest_sync_age:
			syncTime -= chBirthTime->GetValue(i);
			break;
		case kSpeedTest_sync_event:
			syncTime -= chEventStartR->GetValue(i);
			break;
		}
		TimeValue syncTimeTV = TimeValue(syncTime);

		float testValue = 0.0f;
		if (testType < kSpeedTest_testType_whenAccels) {
			if (testType == kSpeedTest_testType_steering) {
				testValue = GetPFFloat(pblock(), kSpeedTest_angleValue, syncTimeTV);
				if (hasTestVariation)
					testValue += chRandFloatR->GetValue(i)*GetPFFloat(pblock(), kSpeedTest_angleVariation, syncTimeTV);
			} else {
				testValue = GetPFFloat(pblock(), kSpeedTest_unitValue, syncTimeTV);
				if (hasTestVariation)
					testValue += chRandFloatR->GetValue(i)*GetPFFloat(pblock(), kSpeedTest_unitVariation, syncTimeTV);
			}
			testValue /= TIME_TICKSPERSEC;
		}

		float currentValue = 0.0f;
		bool testSatisfied = false;
		if (testType < kSpeedTest_testType_whenAccels) {
			if (testType < kSpeedTest_testType_accel) {
				switch(testType) {
				case kSpeedTest_testType_speed:
					currentValue = Length(currentSpeed);
					break;
				case kSpeedTest_testType_speedX:
					currentValue = currentSpeed.x;
					break;
				case kSpeedTest_testType_speedY:
					currentValue = currentSpeed.y;
					break;
				case kSpeedTest_testType_speedZ:
					currentValue = currentSpeed.z;
					break;
				}
			} else if (testType == kSpeedTest_testType_steering) {
				float timeDif = float(currentTime - prevTime);
				if (timeDif <= 0.0f) continue; // no time difference
				float normFactor = Length(currentSpeed)*Length(prevSpeed);
				if (normFactor <= 0.0f) continue; // steering rate is not calculatable
				float vv = DotProd(currentSpeed,prevSpeed)/normFactor;
				float uu = 0.0;
				if (vv >= 1.0f) uu = 0.0;
				else if (vv <= -1.0f) uu = PI;
				else uu = acos(vv);
				currentValue = uu/timeDif;
			} else { // acceleration
				float timeDif = float(currentTime - prevTime);
				if (timeDif <= 0.0f) continue; // no time difference
				Point3 curAccel;
				switch(testType) {
				case kSpeedTest_testType_accel:
					currentValue = Length((currentSpeed - prevSpeed)/timeDif);
					break;
				case kSpeedTest_testType_accelX:
					currentValue = (currentSpeed.x - prevSpeed.x)/timeDif;	
					break;
				case kSpeedTest_testType_accelY:
					currentValue = (currentSpeed.y - prevSpeed.y)/timeDif;	
					break;
				case kSpeedTest_testType_accelZ:
					currentValue = (currentSpeed.z - prevSpeed.z)/timeDif;	
					break;
				}
				testValue /= TIME_TICKSPERSEC; // acceleration is per second squared
			}
			testSatisfied = (condType == kSpeedTest_conditionType_less) ?
								(currentValue < testValue) : (currentValue > testValue);
		} else {
			if (testType == kSpeedTest_testType_whenAccels) {
				testSatisfied = (Length(currentSpeed) > Length(prevSpeed));
			} else {
				testSatisfied = (Length(currentSpeed) < Length(prevSpeed));
			}
		}

		if (testSatisfied && exactStep) {
			testResult.Set(i);
			testTime[i] = 0.0f;
		}
	}

	return true;
}