PageRenderTime 68ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llviewerpartsim.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 861 lines | 657 code | 126 blank | 78 comment | 113 complexity | 2bced8a9d42519346dc8d83dc1935d5a MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llviewerpartsim.cpp
  3. * @brief LLViewerPart class implementation
  4. *
  5. * $LicenseInfo:firstyear=2003&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llviewerpartsim.h"
  28. #include "llviewercontrol.h"
  29. #include "llagent.h"
  30. #include "llviewercamera.h"
  31. #include "llviewerobjectlist.h"
  32. #include "llviewerpartsource.h"
  33. #include "llviewerregion.h"
  34. #include "llvopartgroup.h"
  35. #include "llworld.h"
  36. #include "pipeline.h"
  37. #include "llspatialpartition.h"
  38. #include "llvovolume.h"
  39. const F32 PART_SIM_BOX_SIDE = 16.f;
  40. const F32 PART_SIM_BOX_OFFSET = 0.5f*PART_SIM_BOX_SIDE;
  41. const F32 PART_SIM_BOX_RAD = 0.5f*F_SQRT3*PART_SIM_BOX_SIDE;
  42. //static
  43. S32 LLViewerPartSim::sMaxParticleCount = 0;
  44. S32 LLViewerPartSim::sParticleCount = 0;
  45. S32 LLViewerPartSim::sParticleCount2 = 0;
  46. // This controls how greedy individual particle burst sources are allowed to be, and adapts according to how near the particle-count limit we are.
  47. F32 LLViewerPartSim::sParticleAdaptiveRate = 0.0625f;
  48. F32 LLViewerPartSim::sParticleBurstRate = 0.5f;
  49. //static
  50. const S32 LLViewerPartSim::MAX_PART_COUNT = 8192;
  51. const F32 LLViewerPartSim::PART_THROTTLE_THRESHOLD = 0.9f;
  52. const F32 LLViewerPartSim::PART_ADAPT_RATE_MULT = 2.0f;
  53. //static
  54. const F32 LLViewerPartSim::PART_THROTTLE_RESCALE = PART_THROTTLE_THRESHOLD / (1.0f-PART_THROTTLE_THRESHOLD);
  55. const F32 LLViewerPartSim::PART_ADAPT_RATE_MULT_RECIP = 1.0f/PART_ADAPT_RATE_MULT;
  56. U32 LLViewerPart::sNextPartID = 1;
  57. F32 calc_desired_size(LLViewerCamera* camera, LLVector3 pos, LLVector2 scale)
  58. {
  59. F32 desired_size = (pos - camera->getOrigin()).magVec();
  60. desired_size /= 4;
  61. return llclamp(desired_size, scale.magVec()*0.5f, PART_SIM_BOX_SIDE*2);
  62. }
  63. LLViewerPart::LLViewerPart() :
  64. mPartID(0),
  65. mLastUpdateTime(0.f),
  66. mSkipOffset(0.f),
  67. mVPCallback(NULL),
  68. mImagep(NULL)
  69. {
  70. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  71. mPartSourcep = NULL;
  72. ++LLViewerPartSim::sParticleCount2 ;
  73. }
  74. LLViewerPart::~LLViewerPart()
  75. {
  76. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  77. mPartSourcep = NULL;
  78. --LLViewerPartSim::sParticleCount2 ;
  79. }
  80. void LLViewerPart::init(LLPointer<LLViewerPartSource> sourcep, LLViewerTexture *imagep, LLVPCallback cb)
  81. {
  82. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  83. mPartID = LLViewerPart::sNextPartID;
  84. LLViewerPart::sNextPartID++;
  85. mFlags = 0x00f;
  86. mLastUpdateTime = 0.f;
  87. mMaxAge = 10.f;
  88. mSkipOffset = 0.0f;
  89. mVPCallback = cb;
  90. mPartSourcep = sourcep;
  91. mImagep = imagep;
  92. }
  93. /////////////////////////////
  94. //
  95. // LLViewerPartGroup implementation
  96. //
  97. //
  98. LLViewerPartGroup::LLViewerPartGroup(const LLVector3 &center_agent, const F32 box_side, bool hud)
  99. : mHud(hud)
  100. {
  101. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  102. mVOPartGroupp = NULL;
  103. mUniformParticles = TRUE;
  104. mRegionp = LLWorld::getInstance()->getRegionFromPosAgent(center_agent);
  105. llassert_always(center_agent.isFinite());
  106. if (!mRegionp)
  107. {
  108. //llwarns << "No region at position, using agent region!" << llendl;
  109. mRegionp = gAgent.getRegion();
  110. }
  111. mCenterAgent = center_agent;
  112. mBoxRadius = F_SQRT3*box_side*0.5f;
  113. if (mHud)
  114. {
  115. mVOPartGroupp = (LLVOPartGroup *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_HUD_PART_GROUP, getRegion());
  116. }
  117. else
  118. {
  119. mVOPartGroupp = (LLVOPartGroup *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_PART_GROUP, getRegion());
  120. }
  121. mVOPartGroupp->setViewerPartGroup(this);
  122. mVOPartGroupp->setPositionAgent(getCenterAgent());
  123. F32 scale = box_side * 0.5f;
  124. mVOPartGroupp->setScale(LLVector3(scale,scale,scale));
  125. //gPipeline.addObject(mVOPartGroupp);
  126. gPipeline.createObject(mVOPartGroupp);
  127. LLSpatialGroup* group = mVOPartGroupp->mDrawable->getSpatialGroup();
  128. if (group != NULL)
  129. {
  130. LLVector3 center(group->mOctreeNode->getCenter().getF32ptr());
  131. LLVector3 size(group->mOctreeNode->getSize().getF32ptr());
  132. size += LLVector3(0.01f, 0.01f, 0.01f);
  133. mMinObjPos = center - size;
  134. mMaxObjPos = center + size;
  135. }
  136. else
  137. {
  138. // Not sure what else to set the obj bounds to when the drawable has no spatial group.
  139. LLVector3 extents(mBoxRadius, mBoxRadius, mBoxRadius);
  140. mMinObjPos = center_agent - extents;
  141. mMaxObjPos = center_agent + extents;
  142. }
  143. mSkippedTime = 0.f;
  144. static U32 id_seed = 0;
  145. mID = ++id_seed;
  146. }
  147. LLViewerPartGroup::~LLViewerPartGroup()
  148. {
  149. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  150. cleanup();
  151. S32 count = (S32) mParticles.size();
  152. for(S32 i = 0 ; i < count ; i++)
  153. {
  154. delete mParticles[i] ;
  155. }
  156. mParticles.clear();
  157. LLViewerPartSim::decPartCount(count);
  158. }
  159. void LLViewerPartGroup::cleanup()
  160. {
  161. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  162. if (mVOPartGroupp)
  163. {
  164. if (!mVOPartGroupp->isDead())
  165. {
  166. gObjectList.killObject(mVOPartGroupp);
  167. }
  168. mVOPartGroupp = NULL;
  169. }
  170. }
  171. BOOL LLViewerPartGroup::posInGroup(const LLVector3 &pos, const F32 desired_size)
  172. {
  173. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  174. if ((pos.mV[VX] < mMinObjPos.mV[VX])
  175. || (pos.mV[VY] < mMinObjPos.mV[VY])
  176. || (pos.mV[VZ] < mMinObjPos.mV[VZ]))
  177. {
  178. return FALSE;
  179. }
  180. if ((pos.mV[VX] > mMaxObjPos.mV[VX])
  181. || (pos.mV[VY] > mMaxObjPos.mV[VY])
  182. || (pos.mV[VZ] > mMaxObjPos.mV[VZ]))
  183. {
  184. return FALSE;
  185. }
  186. if (desired_size > 0 &&
  187. (desired_size < mBoxRadius*0.5f ||
  188. desired_size > mBoxRadius*2.f))
  189. {
  190. return FALSE;
  191. }
  192. return TRUE;
  193. }
  194. BOOL LLViewerPartGroup::addPart(LLViewerPart* part, F32 desired_size)
  195. {
  196. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  197. if (part->mFlags & LLPartData::LL_PART_HUD && !mHud)
  198. {
  199. return FALSE;
  200. }
  201. BOOL uniform_part = part->mScale.mV[0] == part->mScale.mV[1] &&
  202. !(part->mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK);
  203. if (!posInGroup(part->mPosAgent, desired_size) ||
  204. (mUniformParticles && !uniform_part) ||
  205. (!mUniformParticles && uniform_part))
  206. {
  207. return FALSE;
  208. }
  209. gPipeline.markRebuild(mVOPartGroupp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
  210. mParticles.push_back(part);
  211. part->mSkipOffset=mSkippedTime;
  212. LLViewerPartSim::incPartCount(1);
  213. return TRUE;
  214. }
  215. void LLViewerPartGroup::updateParticles(const F32 lastdt)
  216. {
  217. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  218. F32 dt;
  219. LLVector3 gravity(0.f, 0.f, GRAVITY);
  220. LLViewerPartSim::checkParticleCount(mParticles.size());
  221. LLViewerCamera* camera = LLViewerCamera::getInstance();
  222. LLViewerRegion *regionp = getRegion();
  223. S32 end = (S32) mParticles.size();
  224. for (S32 i = 0 ; i < (S32)mParticles.size();)
  225. {
  226. LLVector3 a(0.f, 0.f, 0.f);
  227. LLViewerPart* part = mParticles[i] ;
  228. dt = lastdt + mSkippedTime - part->mSkipOffset;
  229. part->mSkipOffset = 0.f;
  230. // Update current time
  231. const F32 cur_time = part->mLastUpdateTime + dt;
  232. const F32 frac = cur_time / part->mMaxAge;
  233. // "Drift" the object based on the source object
  234. if (part->mFlags & LLPartData::LL_PART_FOLLOW_SRC_MASK)
  235. {
  236. part->mPosAgent = part->mPartSourcep->mPosAgent;
  237. part->mPosAgent += part->mPosOffset;
  238. }
  239. // Do a custom callback if we have one...
  240. if (part->mVPCallback)
  241. {
  242. (*part->mVPCallback)(*part, dt);
  243. }
  244. if (part->mFlags & LLPartData::LL_PART_WIND_MASK)
  245. {
  246. LLVector3 tempVel(part->mVelocity);
  247. part->mVelocity *= 1.f - 0.1f*dt;
  248. part->mVelocity += 0.1f*dt*regionp->mWind.getVelocity(regionp->getPosRegionFromAgent(part->mPosAgent));
  249. }
  250. // Now do interpolation towards a target
  251. if (part->mFlags & LLPartData::LL_PART_TARGET_POS_MASK)
  252. {
  253. F32 remaining = part->mMaxAge - part->mLastUpdateTime;
  254. F32 step = dt / remaining;
  255. step = llclamp(step, 0.f, 0.1f);
  256. step *= 5.f;
  257. // we want a velocity that will result in reaching the target in the
  258. // Interpolate towards the target.
  259. LLVector3 delta_pos = part->mPartSourcep->mTargetPosAgent - part->mPosAgent;
  260. delta_pos /= remaining;
  261. part->mVelocity *= (1.f - step);
  262. part->mVelocity += step*delta_pos;
  263. }
  264. if (part->mFlags & LLPartData::LL_PART_TARGET_LINEAR_MASK)
  265. {
  266. LLVector3 delta_pos = part->mPartSourcep->mTargetPosAgent - part->mPartSourcep->mPosAgent;
  267. part->mPosAgent = part->mPartSourcep->mPosAgent;
  268. part->mPosAgent += frac*delta_pos;
  269. part->mVelocity = delta_pos;
  270. }
  271. else
  272. {
  273. // Do velocity interpolation
  274. part->mPosAgent += dt*part->mVelocity;
  275. part->mPosAgent += 0.5f*dt*dt*part->mAccel;
  276. part->mVelocity += part->mAccel*dt;
  277. }
  278. // Do a bounce test
  279. if (part->mFlags & LLPartData::LL_PART_BOUNCE_MASK)
  280. {
  281. // Need to do point vs. plane check...
  282. // For now, just check relative to object height...
  283. F32 dz = part->mPosAgent.mV[VZ] - part->mPartSourcep->mPosAgent.mV[VZ];
  284. if (dz < 0)
  285. {
  286. part->mPosAgent.mV[VZ] += -2.f*dz;
  287. part->mVelocity.mV[VZ] *= -0.75f;
  288. }
  289. }
  290. // Reset the offset from the source position
  291. if (part->mFlags & LLPartData::LL_PART_FOLLOW_SRC_MASK)
  292. {
  293. part->mPosOffset = part->mPosAgent;
  294. part->mPosOffset -= part->mPartSourcep->mPosAgent;
  295. }
  296. // Do color interpolation
  297. if (part->mFlags & LLPartData::LL_PART_INTERP_COLOR_MASK)
  298. {
  299. part->mColor.setVec(part->mStartColor);
  300. // note: LLColor4's v%k means multiply-alpha-only,
  301. // LLColor4's v*k means multiply-rgb-only
  302. part->mColor *= 1.f - frac; // rgb*k
  303. part->mColor %= 1.f - frac; // alpha*k
  304. part->mColor += frac%(frac*part->mEndColor); // rgb,alpha
  305. }
  306. // Do scale interpolation
  307. if (part->mFlags & LLPartData::LL_PART_INTERP_SCALE_MASK)
  308. {
  309. part->mScale.setVec(part->mStartScale);
  310. part->mScale *= 1.f - frac;
  311. part->mScale += frac*part->mEndScale;
  312. }
  313. // Set the last update time to now.
  314. part->mLastUpdateTime = cur_time;
  315. // Kill dead particles (either flagged dead, or too old)
  316. if ((part->mLastUpdateTime > part->mMaxAge) || (LLViewerPart::LL_PART_DEAD_MASK == part->mFlags))
  317. {
  318. mParticles[i] = mParticles.back() ;
  319. mParticles.pop_back() ;
  320. delete part ;
  321. }
  322. else
  323. {
  324. F32 desired_size = calc_desired_size(camera, part->mPosAgent, part->mScale);
  325. if (!posInGroup(part->mPosAgent, desired_size))
  326. {
  327. // Transfer particles between groups
  328. LLViewerPartSim::getInstance()->put(part) ;
  329. mParticles[i] = mParticles.back() ;
  330. mParticles.pop_back() ;
  331. }
  332. else
  333. {
  334. i++ ;
  335. }
  336. }
  337. }
  338. S32 removed = end - (S32)mParticles.size();
  339. if (removed > 0)
  340. {
  341. // we removed one or more particles, so flag this group for update
  342. if (mVOPartGroupp.notNull())
  343. {
  344. gPipeline.markRebuild(mVOPartGroupp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
  345. }
  346. LLViewerPartSim::decPartCount(removed);
  347. }
  348. // Kill the viewer object if this particle group is empty
  349. if (mParticles.empty())
  350. {
  351. gObjectList.killObject(mVOPartGroupp);
  352. mVOPartGroupp = NULL;
  353. }
  354. LLViewerPartSim::checkParticleCount() ;
  355. }
  356. void LLViewerPartGroup::shift(const LLVector3 &offset)
  357. {
  358. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  359. mCenterAgent += offset;
  360. mMinObjPos += offset;
  361. mMaxObjPos += offset;
  362. for (S32 i = 0 ; i < (S32)mParticles.size(); i++)
  363. {
  364. mParticles[i]->mPosAgent += offset;
  365. }
  366. }
  367. void LLViewerPartGroup::removeParticlesByID(const U32 source_id)
  368. {
  369. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  370. for (S32 i = 0; i < (S32)mParticles.size(); i++)
  371. {
  372. if(mParticles[i]->mPartSourcep->getID() == source_id)
  373. {
  374. mParticles[i]->mFlags = LLViewerPart::LL_PART_DEAD_MASK;
  375. }
  376. }
  377. }
  378. //////////////////////////////////
  379. //
  380. // LLViewerPartSim implementation
  381. //
  382. //
  383. //static
  384. void LLViewerPartSim::checkParticleCount(U32 size)
  385. {
  386. if(LLViewerPartSim::sParticleCount2 != LLViewerPartSim::sParticleCount)
  387. {
  388. llerrs << "sParticleCount: " << LLViewerPartSim::sParticleCount << " ; sParticleCount2: " << LLViewerPartSim::sParticleCount2 << llendl ;
  389. }
  390. if(size > (U32)LLViewerPartSim::sParticleCount2)
  391. {
  392. llerrs << "curren particle size: " << LLViewerPartSim::sParticleCount2 << " array size: " << size << llendl ;
  393. }
  394. }
  395. LLViewerPartSim::LLViewerPartSim()
  396. {
  397. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  398. sMaxParticleCount = gSavedSettings.getS32("RenderMaxPartCount");
  399. static U32 id_seed = 0;
  400. mID = ++id_seed;
  401. }
  402. void LLViewerPartSim::destroyClass()
  403. {
  404. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  405. S32 i;
  406. S32 count;
  407. // Kill all of the groups (and particles)
  408. count = (S32) mViewerPartGroups.size();
  409. for (i = 0; i < count; i++)
  410. {
  411. delete mViewerPartGroups[i];
  412. }
  413. mViewerPartGroups.clear();
  414. // Kill all of the sources
  415. mViewerPartSources.clear();
  416. }
  417. BOOL LLViewerPartSim::shouldAddPart()
  418. {
  419. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  420. if (sParticleCount > PART_THROTTLE_THRESHOLD*sMaxParticleCount)
  421. {
  422. F32 frac = (F32)sParticleCount/(F32)sMaxParticleCount;
  423. frac -= PART_THROTTLE_THRESHOLD;
  424. frac *= PART_THROTTLE_RESCALE;
  425. if (ll_frand() < frac)
  426. {
  427. // Skip...
  428. return FALSE;
  429. }
  430. }
  431. if (sParticleCount >= MAX_PART_COUNT)
  432. {
  433. return FALSE;
  434. }
  435. return TRUE;
  436. }
  437. void LLViewerPartSim::addPart(LLViewerPart* part)
  438. {
  439. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  440. if (sParticleCount < MAX_PART_COUNT)
  441. {
  442. put(part);
  443. }
  444. else
  445. {
  446. //delete the particle if can not add it in
  447. delete part ;
  448. part = NULL ;
  449. }
  450. }
  451. LLViewerPartGroup *LLViewerPartSim::put(LLViewerPart* part)
  452. {
  453. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  454. const F32 MAX_MAG = 1000000.f*1000000.f; // 1 million
  455. LLViewerPartGroup *return_group = NULL ;
  456. if (part->mPosAgent.magVecSquared() > MAX_MAG || !part->mPosAgent.isFinite())
  457. {
  458. #if 0 && !LL_RELEASE_FOR_DOWNLOAD
  459. llwarns << "LLViewerPartSim::put Part out of range!" << llendl;
  460. llwarns << part->mPosAgent << llendl;
  461. #endif
  462. }
  463. else
  464. {
  465. LLViewerCamera* camera = LLViewerCamera::getInstance();
  466. F32 desired_size = calc_desired_size(camera, part->mPosAgent, part->mScale);
  467. S32 count = (S32) mViewerPartGroups.size();
  468. for (S32 i = 0; i < count; i++)
  469. {
  470. if (mViewerPartGroups[i]->addPart(part, desired_size))
  471. {
  472. // We found a spatial group that we fit into, add us and exit
  473. return_group = mViewerPartGroups[i];
  474. break ;
  475. }
  476. }
  477. // Hmm, we didn't fit in any of the existing spatial groups
  478. // Create a new one...
  479. if(!return_group)
  480. {
  481. llassert_always(part->mPosAgent.isFinite());
  482. LLViewerPartGroup *groupp = createViewerPartGroup(part->mPosAgent, desired_size, part->mFlags & LLPartData::LL_PART_HUD);
  483. groupp->mUniformParticles = (part->mScale.mV[0] == part->mScale.mV[1] &&
  484. !(part->mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK));
  485. if (!groupp->addPart(part))
  486. {
  487. llwarns << "LLViewerPartSim::put - Particle didn't go into its box!" << llendl;
  488. llinfos << groupp->getCenterAgent() << llendl;
  489. llinfos << part->mPosAgent << llendl;
  490. mViewerPartGroups.pop_back() ;
  491. delete groupp;
  492. groupp = NULL ;
  493. }
  494. return_group = groupp;
  495. }
  496. }
  497. if(!return_group) //failed to insert the particle
  498. {
  499. delete part ;
  500. part = NULL ;
  501. }
  502. return return_group ;
  503. }
  504. LLViewerPartGroup *LLViewerPartSim::createViewerPartGroup(const LLVector3 &pos_agent, const F32 desired_size, bool hud)
  505. {
  506. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  507. //find a box that has a center position divisible by PART_SIM_BOX_SIDE that encompasses
  508. //pos_agent
  509. LLViewerPartGroup *groupp = new LLViewerPartGroup(pos_agent, desired_size, hud);
  510. mViewerPartGroups.push_back(groupp);
  511. return groupp;
  512. }
  513. void LLViewerPartSim::shift(const LLVector3 &offset)
  514. {
  515. S32 i;
  516. S32 count;
  517. count = (S32) mViewerPartSources.size();
  518. for (i = 0; i < count; i++)
  519. {
  520. mViewerPartSources[i]->mPosAgent += offset;
  521. mViewerPartSources[i]->mTargetPosAgent += offset;
  522. mViewerPartSources[i]->mLastUpdatePosAgent += offset;
  523. }
  524. count = (S32) mViewerPartGroups.size();
  525. for (i = 0; i < count; i++)
  526. {
  527. mViewerPartGroups[i]->shift(offset);
  528. }
  529. }
  530. static LLFastTimer::DeclareTimer FTM_SIMULATE_PARTICLES("Simulate Particles");
  531. void LLViewerPartSim::updateSimulation()
  532. {
  533. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  534. static LLFrameTimer update_timer;
  535. const F32 dt = llmin(update_timer.getElapsedTimeAndResetF32(), 0.1f);
  536. if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES)))
  537. {
  538. return;
  539. }
  540. LLFastTimer ftm(FTM_SIMULATE_PARTICLES);
  541. // Start at a random particle system so the same
  542. // particle system doesn't always get first pick at the
  543. // particles. Theoretically we'd want to do this in distance
  544. // order or something, but sorting particle sources will be a big
  545. // pain.
  546. S32 i;
  547. S32 count = (S32) mViewerPartSources.size();
  548. S32 start = (S32)ll_frand((F32)count);
  549. S32 dir = 1;
  550. S32 deldir = 0;
  551. if (ll_frand() > 0.5f)
  552. {
  553. dir = -1;
  554. deldir = -1;
  555. }
  556. S32 num_updates = 0;
  557. for (i = start; num_updates < count;)
  558. {
  559. if (i >= count)
  560. {
  561. i = 0;
  562. }
  563. if (i < 0)
  564. {
  565. i = count - 1;
  566. }
  567. if (!mViewerPartSources[i]->isDead())
  568. {
  569. BOOL upd = TRUE;
  570. if (!LLPipeline::sRenderAttachedParticles)
  571. {
  572. LLViewerObject* vobj = mViewerPartSources[i]->mSourceObjectp;
  573. if (vobj && (vobj->getPCode() == LL_PCODE_VOLUME))
  574. {
  575. LLVOVolume* vvo = (LLVOVolume *)vobj;
  576. if (vvo && vvo->isAttachment())
  577. {
  578. upd = FALSE;
  579. }
  580. }
  581. }
  582. if (upd)
  583. {
  584. mViewerPartSources[i]->update(dt);
  585. }
  586. }
  587. if (mViewerPartSources[i]->isDead())
  588. {
  589. mViewerPartSources.erase(mViewerPartSources.begin() + i);
  590. count--;
  591. i+=deldir;
  592. }
  593. else
  594. {
  595. i += dir;
  596. }
  597. num_updates++;
  598. }
  599. count = (S32) mViewerPartGroups.size();
  600. for (i = 0; i < count; i++)
  601. {
  602. LLViewerObject* vobj = mViewerPartGroups[i]->mVOPartGroupp;
  603. S32 visirate = 1;
  604. if (vobj)
  605. {
  606. LLSpatialGroup* group = vobj->mDrawable->getSpatialGroup();
  607. if (group && !group->isVisible()) // && !group->isState(LLSpatialGroup::OBJECT_DIRTY))
  608. {
  609. visirate = 8;
  610. }
  611. }
  612. if ((LLDrawable::getCurrentFrame()+mViewerPartGroups[i]->mID)%visirate == 0)
  613. {
  614. if (vobj)
  615. {
  616. gPipeline.markRebuild(vobj->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
  617. }
  618. mViewerPartGroups[i]->updateParticles(dt * visirate);
  619. mViewerPartGroups[i]->mSkippedTime=0.0f;
  620. if (!mViewerPartGroups[i]->getCount())
  621. {
  622. delete mViewerPartGroups[i];
  623. mViewerPartGroups.erase(mViewerPartGroups.begin() + i);
  624. i--;
  625. count--;
  626. }
  627. }
  628. else
  629. {
  630. mViewerPartGroups[i]->mSkippedTime+=dt;
  631. }
  632. }
  633. if (LLDrawable::getCurrentFrame()%16==0)
  634. {
  635. if (sParticleCount > sMaxParticleCount * 0.875f
  636. && sParticleAdaptiveRate < 2.0f)
  637. {
  638. sParticleAdaptiveRate *= PART_ADAPT_RATE_MULT;
  639. }
  640. else
  641. {
  642. if (sParticleCount < sMaxParticleCount * 0.5f
  643. && sParticleAdaptiveRate > 0.03125f)
  644. {
  645. sParticleAdaptiveRate *= PART_ADAPT_RATE_MULT_RECIP;
  646. }
  647. }
  648. }
  649. updatePartBurstRate() ;
  650. //llinfos << "Particles: " << sParticleCount << " Adaptive Rate: " << sParticleAdaptiveRate << llendl;
  651. }
  652. void LLViewerPartSim::updatePartBurstRate()
  653. {
  654. if (!(LLDrawable::getCurrentFrame() & 0xf))
  655. {
  656. if (sParticleCount >= MAX_PART_COUNT) //set rate to zero
  657. {
  658. sParticleBurstRate = 0.0f ;
  659. }
  660. else if(sParticleCount > 0)
  661. {
  662. if(sParticleBurstRate > 0.0000001f)
  663. {
  664. F32 total_particles = sParticleCount / sParticleBurstRate ; //estimated
  665. F32 new_rate = llclamp(0.9f * sMaxParticleCount / total_particles, 0.0f, 1.0f) ;
  666. F32 delta_rate_threshold = llmin(0.1f * llmax(new_rate, sParticleBurstRate), 0.1f) ;
  667. F32 delta_rate = llclamp(new_rate - sParticleBurstRate, -1.0f * delta_rate_threshold, delta_rate_threshold) ;
  668. sParticleBurstRate = llclamp(sParticleBurstRate + 0.5f * delta_rate, 0.0f, 1.0f) ;
  669. }
  670. else
  671. {
  672. sParticleBurstRate += 0.0000001f ;
  673. }
  674. }
  675. else
  676. {
  677. sParticleBurstRate += 0.00125f ;
  678. }
  679. }
  680. }
  681. void LLViewerPartSim::addPartSource(LLPointer<LLViewerPartSource> sourcep)
  682. {
  683. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  684. if (!sourcep)
  685. {
  686. llwarns << "Null part source!" << llendl;
  687. return;
  688. }
  689. sourcep->setStart() ;
  690. mViewerPartSources.push_back(sourcep);
  691. }
  692. void LLViewerPartSim::removeLastCreatedSource()
  693. {
  694. mViewerPartSources.pop_back();
  695. }
  696. void LLViewerPartSim::cleanupRegion(LLViewerRegion *regionp)
  697. {
  698. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  699. for (group_list_t::iterator i = mViewerPartGroups.begin(); i != mViewerPartGroups.end(); )
  700. {
  701. group_list_t::iterator iter = i++;
  702. if ((*iter)->getRegion() == regionp)
  703. {
  704. delete *iter;
  705. i = mViewerPartGroups.erase(iter);
  706. }
  707. }
  708. }
  709. void LLViewerPartSim::clearParticlesByID(const U32 system_id)
  710. {
  711. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  712. for (group_list_t::iterator g = mViewerPartGroups.begin(); g != mViewerPartGroups.end(); ++g)
  713. {
  714. (*g)->removeParticlesByID(system_id);
  715. }
  716. for (source_list_t::iterator i = mViewerPartSources.begin(); i != mViewerPartSources.end(); ++i)
  717. {
  718. if ((*i)->getID() == system_id)
  719. {
  720. (*i)->setDead();
  721. break;
  722. }
  723. }
  724. }
  725. void LLViewerPartSim::clearParticlesByOwnerID(const LLUUID& task_id)
  726. {
  727. LLMemType mt(LLMemType::MTYPE_PARTICLES);
  728. for (source_list_t::iterator iter = mViewerPartSources.begin(); iter != mViewerPartSources.end(); ++iter)
  729. {
  730. if ((*iter)->getOwnerUUID() == task_id)
  731. {
  732. clearParticlesByID((*iter)->getID());
  733. }
  734. }
  735. }