//+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+ //| 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; }
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; }
//+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+ //| From IPFTest | //+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+ bool PFTestSplitByAmount::Proceed(IObject* pCont, PreciseTimeValue timeStart, PreciseTimeValue& timeEnd, Object* pSystem, INode* pNode, INode* actionNode, IPFIntegrator* integrator, BitArray& testResult, Tab<float>& testTime) { int contIndex; if (!hasParticleContainer(pCont, contIndex)) return false; _lastUpdate(contIndex) = timeEnd.TimeValue(); bool exactStep = IsExactIntegrationStep(timeEnd, pSystem); // update all other systems to the current time; everybody should be in sync // for proper accumulation amounts int i; for(i=0; i<allParticleContainers().Count(); i++) { if (allParticleContainer(i) == pCont) continue; if (allSystemNode(i) == pNode) continue; if (lastUpdate(i) == timeEnd.TimeValue()) continue; TimeValue timeToUpdateTo = timeEnd.TimeValue(); allSystemNode(i)->NotifyDependents(FOREVER, PartID(&timeToUpdateTo), kPFMSG_UpdateToTime, NOTIFY_ALL, TRUE ); } // 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 IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont); if (chNew == NULL) return false; // can't find "new" property of particles in the container // acquire TestSplitByAmount private particle channel; if not present then create it IParticleChannelBoolW* chTestW = (IParticleChannelBoolW*)chCont->EnsureInterface(PARTICLECHANNELTESTSPLITBYAMOUNTW_INTERFACE, ParticleChannelBool_Class_ID, true, PARTICLECHANNELTESTSPLITBYAMOUNTR_INTERFACE, PARTICLECHANNELTESTSPLITBYAMOUNTW_INTERFACE, false, actionNode, (Object*)this); IParticleChannelBoolR* chTestR = (IParticleChannelBoolR*)chCont->GetPrivateInterface(PARTICLECHANNELTESTSPLITBYAMOUNTR_INTERFACE, (Object*)this); if ((chTestR == NULL) || (chTestW == NULL)) return false; // can't set test value for newly entered particles int 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()) { RandGenerator* randGen = randLinker().GetRandGenerator(pCont); if (randGen == NULL) return false; int testType = pblock()->GetInt(kSplitByAmount_testType, timeStart); float fraction = GetPFFloat(pblock(), kSplitByAmount_fraction, timeStart); int everyN = GetPFInt(pblock(), kSplitByAmount_everyN, timeStart); int firstN = pblock()->GetInt(kSplitByAmount_firstN, timeStart); bool perSource = (pblock()->GetInt(kSplitByAmount_perSource, timeStart) != 0); int curWentThru = perSource ? wentThruTotal(pNode) : wentThruTotal(); // number of "first N" particles is adjusted by multiplier coefficient // of the master particle system. This is done to make "first N" // parameter to be consistent to "total" number of particles acclaimed // by a birth operator IPFSystem* pfSys = PFSystemInterface(pSystem); if (pfSys == NULL) return false; // no handle for PFSystem interface firstN *= pfSys->GetMultiplier(timeStart); for(i=0; i<count; i++) { if (chNew->IsNew(i)) { // calculate test value only for new particles bool sendOut = false; switch(testType) { case kSplitByAmount_testType_fraction: sendOut = (randGen->Rand01() <= fraction); break; case kSplitByAmount_testType_everyN: _wentThruAccum(contIndex) += 1; if (wentThruAccum(contIndex) >= everyN) { sendOut = true; _wentThruAccum(contIndex) = 0; } break; case kSplitByAmount_testType_firstN: _wentThruTotal(contIndex) += 1; if (curWentThru++ < firstN) sendOut = true; break; case kSplitByAmount_testType_afterFirstN: _wentThruTotal(contIndex) += 1; if (curWentThru++ >= firstN) sendOut = true; break; } chTestW->SetValue(i, sendOut); } } } // check all particles by predefined test channel testResult.SetSize(count); testResult.ClearAll(); testTime.SetCount(count); if (exactStep) { for(i=0; i<count; i++) { if (chTestR->GetValue(i)) { testResult.Set(i); testTime[i] = 0.0f; } } } return true; }