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