llviewerpartsim.cpp

Go to the documentation of this file.
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 //static
00053 S32 LLViewerPartSim::sMaxParticleCount = 0;
00054 S32 LLViewerPartSim::sParticleCount = 0;
00055 // This controls how greedy individual particle burst sources are allowed to be, and adapts according to how near the particle-count limit we are.
00056 F32 LLViewerPartSim::sParticleAdaptiveRate = 0.0625f;
00057 F32 LLViewerPartSim::sParticleBurstRate = 0.5f;
00058 
00059 //static
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 //static
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 // LLViewerPartGroup implementation
00114 //
00115 //
00116 
00117 
00118 LLViewerPartGroup::LLViewerPartGroup(const LLVector3 &center_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                 //llwarns << "No region at position, using agent region!" << llendl;
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                 // Not sure what else to set the obj bounds to when the drawable has no spatial group.
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                 // Update current time
00259                 const F32 cur_time = part.mLastUpdateTime + dt;
00260                 const F32 frac = cur_time/part.mMaxAge;
00261 
00262                 // "Drift" the object based on the source object
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                 // Do a custom callback if we have one...
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                 // Now do interpolation towards a target
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                         // we want a velocity that will result in reaching the target in the 
00291                         // Interpolate towards the target.
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                         // Do velocity interpolation
00311                         part.mPosAgent += dt*part.mVelocity;
00312                         part.mPosAgent += 0.5f*dt*dt*part.mAccel;
00313                         part.mVelocity += part.mAccel*dt;
00314                 }
00315 
00316                 // Do a bounce test
00317                 if (part.mFlags & LLPartData::LL_PART_BOUNCE_MASK)
00318                 {
00319                         // Need to do point vs. plane check...
00320                         // For now, just check relative to object height...
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                 // Reset the offset from the source position
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                 // Do color interpolation
00338                 if (part.mFlags & LLPartData::LL_PART_INTERP_COLOR_MASK)
00339                 {
00340                         part.mColor.setVec(part.mStartColor);
00341                         // note: LLColor4's v%k means multiply-alpha-only,
00342                         //       LLColor4's v*k means multiply-rgb-only
00343                         part.mColor *= 1.f - frac; // rgb*k
00344                         part.mColor %= 1.f - frac; // alpha*k
00345                         part.mColor += frac%(frac*part.mEndColor); // rgb,alpha
00346                 }
00347 
00348                 // Do scale interpolation
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                 // Set the last update time to now.
00357                 part.mLastUpdateTime = cur_time;
00358 
00359 
00360                 // Kill dead particles (either flagged dead, or too old)
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                         // be sure to process the particle we just swapped-in
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                                 // Transfer particles between groups
00374                                 LLViewerPartSim::getInstance()->put(&part);
00375                                 end--;
00376                                 LLPointer<LLViewerPart>::swap(mParticles[i], mParticles[end]);
00377                                 // be sure to process the particle we just swapped-in
00378                                 i--;
00379                         }
00380                 }
00381         }
00382 
00383         S32 removed = (S32)mParticles.size() - end;
00384         if (removed > 0)
00385         {
00386                 // we removed one or more particles, so flag this group for update
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         // Kill the viewer object if this particle group is empty
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 // LLViewerPartSim implementation
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         // Kill all of the groups (and particles)
00455         count = (S32) mViewerPartGroups.size();
00456         for (i = 0; i < count; i++)
00457         {
00458                 delete mViewerPartGroups[i];
00459         }
00460         mViewerPartGroups.clear();
00461 
00462         // Kill all of the sources 
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                         // Skip...
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; // 1 million
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                         // We found a spatial group that we fit into, add us and exit
00520                         return mViewerPartGroups[i];
00521                 }
00522         }
00523 
00524         // Hmm, we didn't fit in any of the existing spatial groups
00525         // Create a new one...
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         //find a box that has a center position divisible by PART_SIM_BOX_SIDE that encompasses
00545         //pos_agent
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         // Start at a random particle system so the same
00588         // particle system doesn't always get first pick at the
00589         // particles.  Theoretically we'd want to do this in distance
00590         // order or something, but sorting particle sources will be a big
00591         // pain.
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()) // && !group->isState(LLSpatialGroup::OBJECT_DIRTY))
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         //llinfos << "Particles: " << sParticleCount << " Adaptive Rate: " << sParticleAdaptiveRate << llendl;
00691 }
00692 
00693 void LLViewerPartSim::updatePartBurstRate()
00694 {
00695         if (!(LLDrawable::getCurrentFrame() & 0xf))
00696         {
00697                 if (sParticleCount >= MAX_PART_COUNT) //set rate to zero
00698                 {
00699                         sParticleBurstRate = 0.0f ;
00700                 }
00701                 else if(sParticleCount > 0)
00702                 {
00703                         if(sParticleBurstRate > 0.0000001f)
00704                         {                               
00705                                 F32 total_particles = sParticleCount / sParticleBurstRate ; //estimated
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 }

Generated on Fri May 16 08:34:16 2008 for SecondLife by  doxygen 1.5.5