00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llviewerpartsim.h"
00035
00036 #include "llviewercontrol.h"
00037
00038 #include "llagent.h"
00039 #include "llviewercamera.h"
00040 #include "llviewerobjectlist.h"
00041 #include "llviewerpartsource.h"
00042 #include "llviewerregion.h"
00043 #include "llvopartgroup.h"
00044 #include "llworld.h"
00045 #include "pipeline.h"
00046 #include "llspatialpartition.h"
00047
00048 const F32 PART_SIM_BOX_SIDE = 16.f;
00049 const F32 PART_SIM_BOX_OFFSET = 0.5f*PART_SIM_BOX_SIDE;
00050 const F32 PART_SIM_BOX_RAD = 0.5f*F_SQRT3*PART_SIM_BOX_SIDE;
00051
00052
00053 S32 LLViewerPartSim::sMaxParticleCount = 0;
00054 S32 LLViewerPartSim::sParticleCount = 0;
00055
00056 F32 LLViewerPartSim::sParticleAdaptiveRate = 0.0625f;
00057 F32 LLViewerPartSim::sParticleBurstRate = 0.5f;
00058
00059
00060 const S32 LLViewerPartSim::MAX_PART_COUNT = 8192;
00061 const F32 LLViewerPartSim::PART_THROTTLE_THRESHOLD = 0.9f;
00062 const F32 LLViewerPartSim::PART_ADAPT_RATE_MULT = 2.0f;
00063
00064
00065 const F32 LLViewerPartSim::PART_THROTTLE_RESCALE = PART_THROTTLE_THRESHOLD / (1.0f-PART_THROTTLE_THRESHOLD);
00066 const F32 LLViewerPartSim::PART_ADAPT_RATE_MULT_RECIP = 1.0f/PART_ADAPT_RATE_MULT;
00067
00068
00069 U32 LLViewerPart::sNextPartID = 1;
00070
00071 F32 calc_desired_size(LLVector3 pos, LLVector2 scale)
00072 {
00073 F32 desired_size = (pos-LLViewerCamera::getInstance()->getOrigin()).magVec();
00074 desired_size /= 4;
00075 return llclamp(desired_size, scale.magVec()*0.5f, PART_SIM_BOX_SIDE*2);
00076 }
00077
00078 LLViewerPart::LLViewerPart() :
00079 mPartID(0),
00080 mLastUpdateTime(0.f),
00081 mVPCallback(NULL),
00082 mImagep(NULL)
00083 {
00084 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00085 mPartSourcep = NULL;
00086 }
00087
00088 LLViewerPart::~LLViewerPart()
00089 {
00090 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00091 mPartSourcep = NULL;
00092 }
00093
00094 void LLViewerPart::init(LLPointer<LLViewerPartSource> sourcep, LLViewerImage *imagep, LLVPCallback cb)
00095 {
00096 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00097 mPartID = LLViewerPart::sNextPartID;
00098 LLViewerPart::sNextPartID++;
00099 mFlags = 0x00f;
00100 mLastUpdateTime = 0.f;
00101 mMaxAge = 10.f;
00102 mSkipOffset = 0.0f;
00103
00104 mVPCallback = cb;
00105 mPartSourcep = sourcep;
00106
00107 mImagep = imagep;
00108 }
00109
00110
00112
00113
00114
00115
00116
00117
00118 LLViewerPartGroup::LLViewerPartGroup(const LLVector3 ¢er_agent, const F32 box_side)
00119 {
00120 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00121 mVOPartGroupp = NULL;
00122 mUniformParticles = TRUE;
00123
00124 mRegionp = LLWorld::getInstance()->getRegionFromPosAgent(center_agent);
00125 llassert_always(center_agent.isFinite());
00126
00127 if (!mRegionp)
00128 {
00129
00130 mRegionp = gAgent.getRegion();
00131 }
00132 mCenterAgent = center_agent;
00133 mBoxRadius = F_SQRT3*box_side*0.5f;
00134
00135 mVOPartGroupp = (LLVOPartGroup *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_PART_GROUP, getRegion());
00136 mVOPartGroupp->setViewerPartGroup(this);
00137 mVOPartGroupp->setPositionAgent(getCenterAgent());
00138 F32 scale = box_side * 0.5f;
00139 mVOPartGroupp->setScale(LLVector3(scale,scale,scale));
00140 gPipeline.addObject(mVOPartGroupp);
00141
00142 LLSpatialGroup* group = mVOPartGroupp->mDrawable->getSpatialGroup();
00143
00144 if (group != NULL)
00145 {
00146 LLVector3 center(group->mOctreeNode->getCenter());
00147 LLVector3 size(group->mOctreeNode->getSize());
00148 size += LLVector3(0.01f, 0.01f, 0.01f);
00149 mMinObjPos = center - size;
00150 mMaxObjPos = center + size;
00151 }
00152 else
00153 {
00154
00155 LLVector3 extents(mBoxRadius, mBoxRadius, mBoxRadius);
00156 mMinObjPos = center_agent - extents;
00157 mMaxObjPos = center_agent + extents;
00158 }
00159
00160 mSkippedTime = 0.f;
00161
00162 static U32 id_seed = 0;
00163 mID = ++id_seed;
00164 }
00165
00166 LLViewerPartGroup::~LLViewerPartGroup()
00167 {
00168 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00169 cleanup();
00170
00171 S32 count = (S32) mParticles.size();
00172 mParticles.clear();
00173
00174 LLViewerPartSim::decPartCount(count);
00175 }
00176
00177 void LLViewerPartGroup::cleanup()
00178 {
00179 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00180 if (mVOPartGroupp)
00181 {
00182 if (!mVOPartGroupp->isDead())
00183 {
00184 gObjectList.killObject(mVOPartGroupp);
00185 }
00186 mVOPartGroupp = NULL;
00187 }
00188 }
00189
00190 BOOL LLViewerPartGroup::posInGroup(const LLVector3 &pos, const F32 desired_size)
00191 {
00192 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00193 if ((pos.mV[VX] < mMinObjPos.mV[VX])
00194 || (pos.mV[VY] < mMinObjPos.mV[VY])
00195 || (pos.mV[VZ] < mMinObjPos.mV[VZ]))
00196 {
00197 return FALSE;
00198 }
00199
00200 if ((pos.mV[VX] > mMaxObjPos.mV[VX])
00201 || (pos.mV[VY] > mMaxObjPos.mV[VY])
00202 || (pos.mV[VZ] > mMaxObjPos.mV[VZ]))
00203 {
00204 return FALSE;
00205 }
00206
00207 if (desired_size > 0 &&
00208 (desired_size < mBoxRadius*0.5f ||
00209 desired_size > mBoxRadius*2.f))
00210 {
00211 return FALSE;
00212 }
00213
00214 return TRUE;
00215 }
00216
00217
00218 BOOL LLViewerPartGroup::addPart(LLViewerPart* part, F32 desired_size)
00219 {
00220 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00221 BOOL uniform_part = part->mScale.mV[0] == part->mScale.mV[1] &&
00222 !(part->mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK);
00223
00224 if (!posInGroup(part->mPosAgent, desired_size) ||
00225 (mUniformParticles && !uniform_part) ||
00226 (!mUniformParticles && uniform_part))
00227 {
00228 return FALSE;
00229 }
00230
00231 gPipeline.markRebuild(mVOPartGroupp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
00232
00233 mParticles.push_back(part);
00234 part->mSkipOffset=mSkippedTime;
00235 LLViewerPartSim::incPartCount(1);
00236 return TRUE;
00237 }
00238
00239
00240 void LLViewerPartGroup::updateParticles(const F32 lastdt)
00241 {
00242 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00243 S32 i;
00244 F32 dt;
00245
00246 LLVector3 gravity(0.f, 0.f, GRAVITY);
00247
00248 LLViewerRegion *regionp = getRegion();
00249 S32 end = (S32) mParticles.size();
00250 for (i = 0; i < end; i++)
00251 {
00252 LLVector3 a(0.f, 0.f, 0.f);
00253 LLViewerPart& part = *((LLViewerPart*) mParticles[i]);
00254
00255 dt=lastdt+mSkippedTime-part.mSkipOffset;
00256 part.mSkipOffset=0.f;
00257
00258
00259 const F32 cur_time = part.mLastUpdateTime + dt;
00260 const F32 frac = cur_time/part.mMaxAge;
00261
00262
00263 if (part.mFlags & LLPartData::LL_PART_FOLLOW_SRC_MASK)
00264 {
00265 part.mPosAgent = part.mPartSourcep->mPosAgent;
00266 part.mPosAgent += part.mPosOffset;
00267 }
00268
00269
00270 if (part.mVPCallback)
00271 {
00272 (*part.mVPCallback)(part, dt);
00273 }
00274
00275 if (part.mFlags & LLPartData::LL_PART_WIND_MASK)
00276 {
00277 LLVector3 tempVel(part.mVelocity);
00278 part.mVelocity *= 1.f - 0.1f*dt;
00279 part.mVelocity += 0.1f*dt*regionp->mWind.getVelocity(regionp->getPosRegionFromAgent(part.mPosAgent));
00280 }
00281
00282
00283 if (part.mFlags & LLPartData::LL_PART_TARGET_POS_MASK)
00284 {
00285 F32 remaining = part.mMaxAge - part.mLastUpdateTime;
00286 F32 step = dt / remaining;
00287
00288 step = llclamp(step, 0.f, 0.1f);
00289 step *= 5.f;
00290
00291
00292 LLVector3 delta_pos = part.mPartSourcep->mTargetPosAgent - part.mPosAgent;
00293
00294 delta_pos /= remaining;
00295
00296 part.mVelocity *= (1.f - step);
00297 part.mVelocity += step*delta_pos;
00298 }
00299
00300
00301 if (part.mFlags & LLPartData::LL_PART_TARGET_LINEAR_MASK)
00302 {
00303 LLVector3 delta_pos = part.mPartSourcep->mTargetPosAgent - part.mPartSourcep->mPosAgent;
00304 part.mPosAgent = part.mPartSourcep->mPosAgent;
00305 part.mPosAgent += frac*delta_pos;
00306 part.mVelocity = delta_pos;
00307 }
00308 else
00309 {
00310
00311 part.mPosAgent += dt*part.mVelocity;
00312 part.mPosAgent += 0.5f*dt*dt*part.mAccel;
00313 part.mVelocity += part.mAccel*dt;
00314 }
00315
00316
00317 if (part.mFlags & LLPartData::LL_PART_BOUNCE_MASK)
00318 {
00319
00320
00321 F32 dz = part.mPosAgent.mV[VZ] - part.mPartSourcep->mPosAgent.mV[VZ];
00322 if (dz < 0)
00323 {
00324 part.mPosAgent.mV[VZ] += -2.f*dz;
00325 part.mVelocity.mV[VZ] *= -0.75f;
00326 }
00327 }
00328
00329
00330
00331 if (part.mFlags & LLPartData::LL_PART_FOLLOW_SRC_MASK)
00332 {
00333 part.mPosOffset = part.mPosAgent;
00334 part.mPosOffset -= part.mPartSourcep->mPosAgent;
00335 }
00336
00337
00338 if (part.mFlags & LLPartData::LL_PART_INTERP_COLOR_MASK)
00339 {
00340 part.mColor.setVec(part.mStartColor);
00341
00342
00343 part.mColor *= 1.f - frac;
00344 part.mColor %= 1.f - frac;
00345 part.mColor += frac%(frac*part.mEndColor);
00346 }
00347
00348
00349 if (part.mFlags & LLPartData::LL_PART_INTERP_SCALE_MASK)
00350 {
00351 part.mScale.setVec(part.mStartScale);
00352 part.mScale *= 1.f - frac;
00353 part.mScale += frac*part.mEndScale;
00354 }
00355
00356
00357 part.mLastUpdateTime = cur_time;
00358
00359
00360
00361 if ((part.mLastUpdateTime > part.mMaxAge) || (LLViewerPart::LL_PART_DEAD_MASK == part.mFlags))
00362 {
00363 end--;
00364 LLPointer<LLViewerPart>::swap(mParticles[i], mParticles[end]);
00365
00366 i--;
00367 }
00368 else
00369 {
00370 F32 desired_size = calc_desired_size(part.mPosAgent, part.mScale);
00371 if (!posInGroup(part.mPosAgent, desired_size))
00372 {
00373
00374 LLViewerPartSim::getInstance()->put(&part);
00375 end--;
00376 LLPointer<LLViewerPart>::swap(mParticles[i], mParticles[end]);
00377
00378 i--;
00379 }
00380 }
00381 }
00382
00383 S32 removed = (S32)mParticles.size() - end;
00384 if (removed > 0)
00385 {
00386
00387 mParticles.erase(mParticles.begin() + end, mParticles.end());
00388 if (mVOPartGroupp.notNull())
00389 {
00390 gPipeline.markRebuild(mVOPartGroupp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
00391 }
00392 LLViewerPartSim::decPartCount(removed);
00393 }
00394
00395
00396 if (mParticles.empty())
00397 {
00398 gObjectList.killObject(mVOPartGroupp);
00399 mVOPartGroupp = NULL;
00400 }
00401 }
00402
00403
00404 void LLViewerPartGroup::shift(const LLVector3 &offset)
00405 {
00406 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00407 mCenterAgent += offset;
00408 mMinObjPos += offset;
00409 mMaxObjPos += offset;
00410
00411 S32 count = (S32) mParticles.size();
00412 S32 i;
00413 for (i = 0; i < count; i++)
00414 {
00415 mParticles[i]->mPosAgent += offset;
00416 }
00417 }
00418
00419 void LLViewerPartGroup::removeParticlesByID(const U32 source_id)
00420 {
00421 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00422 S32 end = (S32) mParticles.size();
00423 for (int i = 0; i < end; i++)
00424 {
00425 if(mParticles[i]->mPartSourcep->getID() == source_id)
00426 {
00427 mParticles[i]->mFlags = LLViewerPart::LL_PART_DEAD_MASK;
00428 }
00429 }
00430 }
00431
00433
00434
00435
00436
00437
00438
00439 LLViewerPartSim::LLViewerPartSim()
00440 {
00441 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00442 sMaxParticleCount = gSavedSettings.getS32("RenderMaxPartCount");
00443 static U32 id_seed = 0;
00444 mID = ++id_seed;
00445 }
00446
00447
00448 void LLViewerPartSim::destroyClass()
00449 {
00450 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00451 S32 i;
00452 S32 count;
00453
00454
00455 count = (S32) mViewerPartGroups.size();
00456 for (i = 0; i < count; i++)
00457 {
00458 delete mViewerPartGroups[i];
00459 }
00460 mViewerPartGroups.clear();
00461
00462
00463 mViewerPartSources.clear();
00464 }
00465
00466 BOOL LLViewerPartSim::shouldAddPart()
00467 {
00468 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00469 if (sParticleCount > PART_THROTTLE_THRESHOLD*sMaxParticleCount)
00470 {
00471
00472 F32 frac = (F32)sParticleCount/(F32)sMaxParticleCount;
00473 frac -= PART_THROTTLE_THRESHOLD;
00474 frac *= PART_THROTTLE_RESCALE;
00475 if (ll_frand() < frac)
00476 {
00477
00478 return FALSE;
00479 }
00480 }
00481 if (sParticleCount >= MAX_PART_COUNT)
00482 {
00483 return FALSE;
00484 }
00485
00486 return TRUE;
00487 }
00488
00489 void LLViewerPartSim::addPart(LLViewerPart* part)
00490 {
00491 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00492 if (sParticleCount < MAX_PART_COUNT)
00493 {
00494 put(part);
00495 }
00496 }
00497
00498
00499 LLViewerPartGroup *LLViewerPartSim::put(LLViewerPart* part)
00500 {
00501 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00502 const F32 MAX_MAG = 1000000.f*1000000.f;
00503 if (part->mPosAgent.magVecSquared() > MAX_MAG || !part->mPosAgent.isFinite())
00504 {
00505 #if 0 && !LL_RELEASE_FOR_DOWNLOAD
00506 llwarns << "LLViewerPartSim::put Part out of range!" << llendl;
00507 llwarns << part->mPosAgent << llendl;
00508 #endif
00509 return NULL;
00510 }
00511
00512 F32 desired_size = calc_desired_size(part->mPosAgent, part->mScale);
00513
00514 S32 count = (S32) mViewerPartGroups.size();
00515 for (S32 i = 0; i < count; i++)
00516 {
00517 if (mViewerPartGroups[i]->addPart(part, desired_size))
00518 {
00519
00520 return mViewerPartGroups[i];
00521 }
00522 }
00523
00524
00525
00526 llassert_always(part->mPosAgent.isFinite());
00527 LLViewerPartGroup *groupp = createViewerPartGroup(part->mPosAgent, desired_size);
00528 groupp->mUniformParticles = (part->mScale.mV[0] == part->mScale.mV[1] &&
00529 !(part->mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK));
00530 if (!groupp->addPart(part))
00531 {
00532 llwarns << "LLViewerPartSim::put - Particle didn't go into its box!" << llendl;
00533 llinfos << groupp->getCenterAgent() << llendl;
00534 llinfos << part->mPosAgent << llendl;
00535 delete groupp;
00536 return NULL;
00537 }
00538 return groupp;
00539 }
00540
00541 LLViewerPartGroup *LLViewerPartSim::createViewerPartGroup(const LLVector3 &pos_agent, const F32 desired_size)
00542 {
00543 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00544
00545
00546 LLViewerPartGroup *groupp = new LLViewerPartGroup(pos_agent, desired_size);
00547 mViewerPartGroups.push_back(groupp);
00548 return groupp;
00549 }
00550
00551
00552 void LLViewerPartSim::shift(const LLVector3 &offset)
00553 {
00554 S32 i;
00555 S32 count;
00556
00557 count = (S32) mViewerPartSources.size();
00558 for (i = 0; i < count; i++)
00559 {
00560 mViewerPartSources[i]->mPosAgent += offset;
00561 mViewerPartSources[i]->mTargetPosAgent += offset;
00562 mViewerPartSources[i]->mLastUpdatePosAgent += offset;
00563 }
00564
00565 count = (S32) mViewerPartGroups.size();
00566 for (i = 0; i < count; i++)
00567 {
00568 mViewerPartGroups[i]->shift(offset);
00569 }
00570 }
00571
00572 void LLViewerPartSim::updateSimulation()
00573 {
00574 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00575
00576 static LLFrameTimer update_timer;
00577
00578 const F32 dt = llmin(update_timer.getElapsedTimeAndResetF32(), 0.1f);
00579
00580 if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES)))
00581 {
00582 return;
00583 }
00584
00585 LLFastTimer ftm(LLFastTimer::FTM_SIMULATE_PARTICLES);
00586
00587
00588
00589
00590
00591
00592 S32 i;
00593 S32 count = (S32) mViewerPartSources.size();
00594 S32 start = (S32)ll_frand((F32)count);
00595 S32 dir = 1;
00596 S32 deldir = 0;
00597 if (ll_frand() > 0.5f)
00598 {
00599 dir = -1;
00600 deldir = -1;
00601 }
00602
00603 S32 num_updates = 0;
00604 for (i = start; num_updates < count;)
00605 {
00606 if (i >= count)
00607 {
00608 i = 0;
00609 }
00610 if (i < 0)
00611 {
00612 i = count - 1;
00613 }
00614
00615 if (!mViewerPartSources[i]->isDead())
00616 {
00617 mViewerPartSources[i]->update(dt);
00618 }
00619
00620 if (mViewerPartSources[i]->isDead())
00621 {
00622 mViewerPartSources.erase(mViewerPartSources.begin() + i);
00623 count--;
00624 i+=deldir;
00625 }
00626 else
00627 {
00628 i += dir;
00629 }
00630 num_updates++;
00631 }
00632
00633
00634 count = (S32) mViewerPartGroups.size();
00635 for (i = 0; i < count; i++)
00636 {
00637 LLViewerObject* vobj = mViewerPartGroups[i]->mVOPartGroupp;
00638
00639 S32 visirate = 1;
00640 if (vobj)
00641 {
00642 LLSpatialGroup* group = vobj->mDrawable->getSpatialGroup();
00643 if (group && !group->isVisible())
00644 {
00645 visirate = 8;
00646 }
00647 }
00648
00649 if ((LLDrawable::getCurrentFrame()+mViewerPartGroups[i]->mID)%visirate == 0)
00650 {
00651 if (vobj)
00652 {
00653 gPipeline.markRebuild(vobj->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
00654 }
00655 mViewerPartGroups[i]->updateParticles(dt * visirate);
00656 mViewerPartGroups[i]->mSkippedTime=0.0f;
00657 if (!mViewerPartGroups[i]->getCount())
00658 {
00659 delete mViewerPartGroups[i];
00660 mViewerPartGroups.erase(mViewerPartGroups.begin() + i);
00661 i--;
00662 count--;
00663 }
00664 }
00665 else
00666 {
00667 mViewerPartGroups[i]->mSkippedTime+=dt;
00668 }
00669
00670 }
00671 if (LLDrawable::getCurrentFrame()%16==0)
00672 {
00673 if (sParticleCount > sMaxParticleCount * 0.875f
00674 && sParticleAdaptiveRate < 2.0f)
00675 {
00676 sParticleAdaptiveRate *= PART_ADAPT_RATE_MULT;
00677 }
00678 else
00679 {
00680 if (sParticleCount < sMaxParticleCount * 0.5f
00681 && sParticleAdaptiveRate > 0.03125f)
00682 {
00683 sParticleAdaptiveRate *= PART_ADAPT_RATE_MULT_RECIP;
00684 }
00685 }
00686 }
00687
00688 updatePartBurstRate() ;
00689
00690
00691 }
00692
00693 void LLViewerPartSim::updatePartBurstRate()
00694 {
00695 if (!(LLDrawable::getCurrentFrame() & 0xf))
00696 {
00697 if (sParticleCount >= MAX_PART_COUNT)
00698 {
00699 sParticleBurstRate = 0.0f ;
00700 }
00701 else if(sParticleCount > 0)
00702 {
00703 if(sParticleBurstRate > 0.0000001f)
00704 {
00705 F32 total_particles = sParticleCount / sParticleBurstRate ;
00706 F32 new_rate = llclamp(0.9f * sMaxParticleCount / total_particles, 0.0f, 1.0f) ;
00707 F32 delta_rate_threshold = llmin(0.1f * llmax(new_rate, sParticleBurstRate), 0.1f) ;
00708 F32 delta_rate = llclamp(new_rate - sParticleBurstRate, -1.0f * delta_rate_threshold, delta_rate_threshold) ;
00709
00710 sParticleBurstRate = llclamp(sParticleBurstRate + 0.5f * delta_rate, 0.0f, 1.0f) ;
00711 }
00712 else
00713 {
00714 sParticleBurstRate += 0.0000001f ;
00715 }
00716 }
00717 else
00718 {
00719 sParticleBurstRate += 0.00125f ;
00720 }
00721 }
00722 }
00723
00724 void LLViewerPartSim::addPartSource(LLPointer<LLViewerPartSource> sourcep)
00725 {
00726 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00727 if (!sourcep)
00728 {
00729 llwarns << "Null part source!" << llendl;
00730 return;
00731 }
00732 sourcep->setStart() ;
00733 mViewerPartSources.push_back(sourcep);
00734 }
00735
00736 void LLViewerPartSim::removeLastCreatedSource()
00737 {
00738 mViewerPartSources.pop_back();
00739 }
00740
00741 void LLViewerPartSim::cleanupRegion(LLViewerRegion *regionp)
00742 {
00743 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00744 for (group_list_t::iterator i = mViewerPartGroups.begin(); i != mViewerPartGroups.end(); )
00745 {
00746 group_list_t::iterator iter = i++;
00747
00748 if ((*iter)->getRegion() == regionp)
00749 {
00750 delete *iter;
00751 i = mViewerPartGroups.erase(iter);
00752 }
00753 }
00754 }
00755
00756 void LLViewerPartSim::clearParticlesByID(const U32 system_id)
00757 {
00758 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00759 for (group_list_t::iterator g = mViewerPartGroups.begin(); g != mViewerPartGroups.end(); ++g)
00760 {
00761 (*g)->removeParticlesByID(system_id);
00762 }
00763 for (source_list_t::iterator i = mViewerPartSources.begin(); i != mViewerPartSources.end(); ++i)
00764 {
00765 if ((*i)->getID() == system_id)
00766 {
00767 (*i)->setDead();
00768 break;
00769 }
00770 }
00771
00772 }
00773
00774 void LLViewerPartSim::clearParticlesByOwnerID(const LLUUID& task_id)
00775 {
00776 LLMemType mt(LLMemType::MTYPE_PARTICLES);
00777 for (source_list_t::iterator iter = mViewerPartSources.begin(); iter != mViewerPartSources.end(); ++iter)
00778 {
00779 if ((*iter)->getOwnerUUID() == task_id)
00780 {
00781 clearParticlesByID((*iter)->getID());
00782 }
00783 }
00784 }