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