llviewerpartsim.cpp 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070
  1. /**
  2. * @file llviewerpartsim.cpp
  3. * @brief LLViewerPart class implementation
  4. *
  5. * $LicenseInfo:firstyear=2003&license=viewergpl$
  6. *
  7. * Copyright (c) 2003-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include <utility>
  34. #include "llviewerpartsim.h"
  35. #include "llfasttimer.h"
  36. #include "llagent.h"
  37. #include "llappviewer.h" // gFPSClamped
  38. #include "llpipeline.h"
  39. //MK
  40. #include "mkrlinterface.h"
  41. //mk
  42. #include "llspatialpartition.h"
  43. #include "llviewercamera.h"
  44. #include "llviewercontrol.h"
  45. #include "llviewerobjectlist.h"
  46. #include "llviewerpartsource.h"
  47. #include "llviewerregion.h"
  48. #include "llvoavatar.h"
  49. #include "llvopartgroup.h"
  50. #include "llvovolume.h"
  51. #include "llworld.h"
  52. constexpr F32 PART_SIM_BOX_SIDE = 16.f;
  53. // Global
  54. LLViewerPartSim gViewerPartSim;
  55. //static
  56. U32 LLViewerPart::sNextPartID = 1;
  57. S32 LLViewerPartSim::sMaxParticleCount = 0;
  58. S32 LLViewerPartSim::sParticleCount = 0;
  59. #if LL_DEBUG
  60. S32 LLViewerPartSim::sParticleCount2 = 0;
  61. #endif
  62. // This controls how greedy individual particle burst sources are allowed to
  63. // be, and adapts according to how near the particle-count limit we are.
  64. F32 LLViewerPartSim::sParticleAdaptiveRate = 0.0625f;
  65. F32 LLViewerPartSim::sParticleBurstRate = 0.5f;
  66. F32 calc_desired_size(LLVector3 pos, LLVector2 scale)
  67. {
  68. F32 desired_size = (pos - gViewerCamera.getOrigin()).length() * 0.25f;
  69. return llclamp(desired_size, scale.length() * 0.5f,
  70. PART_SIM_BOX_SIDE * 2.f);
  71. }
  72. ///////////////////////////////////////////////////////////////////////////////
  73. // LLViewerPart class
  74. ///////////////////////////////////////////////////////////////////////////////
  75. LLViewerPart::LLViewerPart()
  76. : mPartID(0),
  77. mLastUpdateTime(0.f),
  78. mSkipOffset(0.f),
  79. mVPCallback(NULL),
  80. mParent(NULL),
  81. mChild(NULL)
  82. {
  83. #if LL_DEBUG
  84. ++LLViewerPartSim::sParticleCount2;
  85. #endif
  86. }
  87. LLViewerPart::~LLViewerPart()
  88. {
  89. if (mPartSourcep.notNull() && mPartSourcep->mLastPart == this)
  90. {
  91. mPartSourcep->mLastPart = NULL;
  92. }
  93. // Patch up holes in the ribbon
  94. if (mParent)
  95. {
  96. llassert(mParent->mChild == this);
  97. mParent->mChild = mChild;
  98. }
  99. if (mChild)
  100. {
  101. llassert (mChild->mParent == this);
  102. mChild->mParent = mParent;
  103. }
  104. mPartSourcep = NULL;
  105. #if LL_DEBUG
  106. --LLViewerPartSim::sParticleCount2;
  107. #endif
  108. }
  109. void LLViewerPart::init(LLPointer<LLViewerPartSource> sourcep,
  110. LLViewerTexture* imagep, LLVPCallback cb)
  111. {
  112. mPartID = sNextPartID++;
  113. mFlags = 0x00f;
  114. mLastUpdateTime = mSkipOffset = 0.f;
  115. mMaxAge = 10.f;
  116. mVPCallback = cb;
  117. mPartSourcep = std::move(sourcep);
  118. mImagep = imagep;
  119. if (mImagep.notNull())
  120. {
  121. mImagep->setBoostLevel(LLGLTexture::BOOST_SUPER_HIGH);
  122. // Do not allow to discard the texture: fast changing particle systems
  123. // often see their cycling textures de-rez if we do. *TODO: only apply
  124. // to fast changing particle systems ? HB
  125. LLViewerFetchedTexture* texp = mImagep->asFetched();
  126. if (texp)
  127. {
  128. texp->setMinDiscardLevel(1);
  129. }
  130. mImagep->dontDiscard();
  131. #if !LL_IMPLICIT_SETNODELETE
  132. // Also set NO_DELETE since the changing textures might otherwise get
  133. // removed from memory. HB
  134. mImagep->setNoDelete();
  135. #endif
  136. }
  137. }
  138. ///////////////////////////////////////////////////////////////////////////////
  139. // LLViewerPartGroup class
  140. ///////////////////////////////////////////////////////////////////////////////
  141. LLViewerPartGroup::LLViewerPartGroup(const LLVector3& center_agent,
  142. F32 box_side, bool hud)
  143. : mVOPartGroupp(NULL),
  144. mHud(hud),
  145. mUniformParticles(true),
  146. mCenterAgent(center_agent),
  147. mBoxSide(box_side),
  148. mBoxRadius(F_SQRT3 * 0.5f * box_side),
  149. mSkippedTime(0.f)
  150. {
  151. static U32 id_seed = 0;
  152. mID = ++id_seed;
  153. llassert_always(center_agent.isFinite());
  154. mRegionp = gWorld.getRegionFromPosAgent(center_agent);
  155. if (!mRegionp)
  156. {
  157. LL_DEBUGS("Particles") << "No region at position, using agent region"
  158. << LL_ENDL;
  159. mRegionp = gAgent.getRegion();
  160. }
  161. if (mHud)
  162. {
  163. mVOPartGroupp =
  164. (LLVOPartGroup*)gObjectList.createObjectViewer(LLViewerObject::LL_VO_HUD_PART_GROUP,
  165. getRegion());
  166. }
  167. else
  168. {
  169. mVOPartGroupp =
  170. (LLVOPartGroup*)gObjectList.createObjectViewer(LLViewerObject::LL_VO_PART_GROUP,
  171. getRegion());
  172. }
  173. mVOPartGroupp->setViewerPartGroup(this);
  174. mVOPartGroupp->setPositionAgent(getCenterAgent());
  175. F32 scale = box_side * 0.5f;
  176. mVOPartGroupp->setScale(LLVector3(scale, scale, scale));
  177. gPipeline.createObject(mVOPartGroupp);
  178. LLSpatialGroup* group = mVOPartGroupp->mDrawable->getSpatialGroup();
  179. if (group)
  180. {
  181. LLVector3 center(group->getOctreeNode()->getCenter().getF32ptr());
  182. LLVector3 size(group->getOctreeNode()->getSize().getF32ptr());
  183. size += LLVector3(0.01f, 0.01f, 0.01f);
  184. mMinObjPos = center - size;
  185. mMaxObjPos = center + size;
  186. }
  187. else
  188. {
  189. // Not sure what else to set the obj bounds to when the drawable has no
  190. // spatial group.
  191. LLVector3 extents(mBoxRadius, mBoxRadius, mBoxRadius);
  192. mMinObjPos = center_agent - extents;
  193. mMaxObjPos = center_agent + extents;
  194. }
  195. }
  196. LLViewerPartGroup::~LLViewerPartGroup()
  197. {
  198. cleanup();
  199. S32 count = (S32)mParticles.size();
  200. for (S32 i = 0; i < count; ++i)
  201. {
  202. delete mParticles[i];
  203. }
  204. mParticles.clear();
  205. LLViewerPartSim::decPartCount(count);
  206. }
  207. void LLViewerPartGroup::cleanup()
  208. {
  209. if (mVOPartGroupp)
  210. {
  211. if (!mVOPartGroupp->isDead())
  212. {
  213. gObjectList.killObject(mVOPartGroupp);
  214. }
  215. mVOPartGroupp = NULL;
  216. }
  217. }
  218. bool LLViewerPartGroup::posInGroup(const LLVector3& pos, F32 desired_size)
  219. {
  220. if (pos.mV[VX] < mMinObjPos.mV[VX] || pos.mV[VY] < mMinObjPos.mV[VY] ||
  221. pos.mV[VZ] < mMinObjPos.mV[VZ])
  222. {
  223. return false;
  224. }
  225. if (pos.mV[VX] > mMaxObjPos.mV[VX] || pos.mV[VY] > mMaxObjPos.mV[VY] ||
  226. pos.mV[VZ] > mMaxObjPos.mV[VZ])
  227. {
  228. return false;
  229. }
  230. if (desired_size > 0 &&
  231. (desired_size < mBoxRadius * 0.5f || desired_size > mBoxRadius * 2.f))
  232. {
  233. return false;
  234. }
  235. return true;
  236. }
  237. bool LLViewerPartGroup::addPart(LLViewerPart* part, F32 desired_size)
  238. {
  239. if (!mHud && (part->mFlags & LLPartData::LL_PART_HUD))
  240. {
  241. return false;
  242. }
  243. bool uniform_part = part->mScale.mV[0] == part->mScale.mV[1] &&
  244. !(part->mFlags &
  245. LLPartData::LL_PART_FOLLOW_VELOCITY_MASK);
  246. if (mUniformParticles != uniform_part ||
  247. !posInGroup(part->mPosAgent, desired_size))
  248. {
  249. return false;
  250. }
  251. gPipeline.markRebuild(mVOPartGroupp->mDrawable);
  252. mParticles.push_back(part);
  253. part->mSkipOffset = mSkippedTime;
  254. LLViewerPartSim::incPartCount(1);
  255. return true;
  256. }
  257. void LLViewerPartGroup::updateParticles(F32 lastdt)
  258. {
  259. F32 dt;
  260. LLVector3 gravity(0.f, 0.f, GRAVITY);
  261. #if LL_DEBUG
  262. LLViewerPartSim::checkParticleCount(mParticles.size());
  263. #endif
  264. S32 end = (S32)mParticles.size();
  265. for (S32 i = 0, count = mParticles.size(); i < count; )
  266. {
  267. LLVector3 a;
  268. LLViewerPart* part = mParticles[i];
  269. dt = lastdt + mSkippedTime - part->mSkipOffset;
  270. part->mSkipOffset = 0.f;
  271. // Update current time
  272. const F32 cur_time = part->mLastUpdateTime + dt;
  273. const F32 frac = cur_time / part->mMaxAge;
  274. // "Drift" the object based on the source object
  275. if (part->mFlags & LLPartData::LL_PART_FOLLOW_SRC_MASK)
  276. {
  277. part->mPosAgent = part->mPartSourcep->mPosAgent;
  278. part->mPosAgent += part->mPosOffset;
  279. }
  280. // Do a custom callback if we have one...
  281. if (part->mVPCallback)
  282. {
  283. (*part->mVPCallback)(*part, dt);
  284. }
  285. if (part->mFlags & LLPartData::LL_PART_WIND_MASK)
  286. {
  287. part->mVelocity *= 1.f - 0.1f * dt;
  288. part->mVelocity += 0.1f * dt *
  289. mRegionp->mWind.getVelocity(mRegionp->getPosRegionFromAgent(part->mPosAgent));
  290. }
  291. // Now do interpolation towards a target
  292. if (part->mFlags & LLPartData::LL_PART_TARGET_POS_MASK)
  293. {
  294. F32 remaining = part->mMaxAge - part->mLastUpdateTime;
  295. F32 step = dt / remaining;
  296. step = llclamp(step, 0.f, 0.1f);
  297. step *= 5.f;
  298. // we want a velocity that will result in reaching the target in the
  299. // Interpolate towards the target.
  300. LLVector3 delta_pos = part->mPartSourcep->mTargetPosAgent -
  301. part->mPosAgent;
  302. delta_pos /= remaining;
  303. part->mVelocity *= 1.f - step;
  304. part->mVelocity += step * delta_pos;
  305. }
  306. if (part->mFlags & LLPartData::LL_PART_TARGET_LINEAR_MASK)
  307. {
  308. LLVector3 delta_pos = part->mPartSourcep->mTargetPosAgent -
  309. part->mPartSourcep->mPosAgent;
  310. part->mPosAgent = part->mPartSourcep->mPosAgent;
  311. part->mPosAgent += frac * delta_pos;
  312. part->mVelocity = delta_pos;
  313. }
  314. else
  315. {
  316. // Do velocity interpolation
  317. part->mPosAgent += dt * part->mVelocity;
  318. part->mPosAgent += 0.5f * dt * dt * part->mAccel;
  319. part->mVelocity += part->mAccel * dt;
  320. }
  321. // Do a bounce test
  322. if (part->mFlags & LLPartData::LL_PART_BOUNCE_MASK)
  323. {
  324. // Need to do point vs. plane check...
  325. // For now, just check relative to object height...
  326. F32 dz = part->mPosAgent.mV[VZ] -
  327. part->mPartSourcep->mPosAgent.mV[VZ];
  328. if (dz < 0)
  329. {
  330. part->mPosAgent.mV[VZ] += -2.f * dz;
  331. part->mVelocity.mV[VZ] *= -0.75f;
  332. }
  333. }
  334. // Reset the offset from the source position
  335. if (part->mFlags & LLPartData::LL_PART_FOLLOW_SRC_MASK)
  336. {
  337. part->mPosOffset = part->mPosAgent;
  338. part->mPosOffset -= part->mPartSourcep->mPosAgent;
  339. }
  340. // Do color interpolation
  341. if (part->mFlags & LLPartData::LL_PART_INTERP_COLOR_MASK)
  342. {
  343. part->mColor.set(part->mStartColor);
  344. // Note: LLColor4's v%k means multiply-alpha-only,
  345. // LLColor4's v*k means multiply-rgb-only
  346. part->mColor *= 1.f - frac; // rgb*k
  347. part->mColor %= 1.f - frac; // alpha*k
  348. part->mColor += frac % (frac * part->mEndColor); // rgb,alpha
  349. }
  350. // Do scale interpolation
  351. if (part->mFlags & LLPartData::LL_PART_INTERP_SCALE_MASK)
  352. {
  353. part->mScale.set(part->mStartScale);
  354. part->mScale *= 1.f - frac;
  355. part->mScale += frac * part->mEndScale;
  356. }
  357. // Do glow interpolation
  358. part->mGlow.mV[3] = (U8)ll_roundp(lerp(part->mStartGlow,
  359. part->mEndGlow, frac) * 255.f);
  360. // Set the last update time to now.
  361. part->mLastUpdateTime = cur_time;
  362. // Kill dead particles (either flagged dead, or too old)
  363. if (part->mLastUpdateTime > part->mMaxAge ||
  364. LLViewerPart::LL_PART_DEAD_MASK == part->mFlags)
  365. {
  366. delete part;
  367. if (i < --count)
  368. {
  369. mParticles[i] = mParticles.back();
  370. }
  371. mParticles.pop_back();
  372. }
  373. else
  374. {
  375. // Increment the active particles count for the source
  376. part->mPartSourcep->incPartCount();
  377. F32 desired_size = calc_desired_size(part->mPosAgent,
  378. part->mScale);
  379. if (!posInGroup(part->mPosAgent, desired_size))
  380. {
  381. // Transfer particles between groups
  382. gViewerPartSim.put(part);
  383. if (i < --count)
  384. {
  385. mParticles[i] = mParticles.back();
  386. }
  387. mParticles.pop_back();
  388. }
  389. else
  390. {
  391. ++i;
  392. }
  393. }
  394. }
  395. S32 removed = end - (S32)mParticles.size();
  396. if (removed > 0)
  397. {
  398. // We removed one or more particles, so flag this group for update
  399. if (mVOPartGroupp.notNull())
  400. {
  401. gPipeline.markRebuild(mVOPartGroupp->mDrawable);
  402. }
  403. LLViewerPartSim::decPartCount(removed);
  404. }
  405. // Kill the viewer object if this particle group is empty
  406. if (mParticles.empty())
  407. {
  408. gObjectList.killObject(mVOPartGroupp);
  409. mVOPartGroupp = NULL;
  410. }
  411. #if LL_DEBUG
  412. LLViewerPartSim::checkParticleCount(mParticles.size());
  413. #endif
  414. }
  415. void LLViewerPartGroup::shift(const LLVector3& offset)
  416. {
  417. mCenterAgent += offset;
  418. mMinObjPos += offset;
  419. mMaxObjPos += offset;
  420. for (S32 i = 0, count = mParticles.size(); i < count; ++i)
  421. {
  422. mParticles[i]->mPosAgent += offset;
  423. }
  424. }
  425. void LLViewerPartGroup::removeParticlesByID(U32 source_id)
  426. {
  427. for (S32 i = 0, count = mParticles.size(); i < count; ++i)
  428. {
  429. if (mParticles[i]->mPartSourcep->getID() == source_id)
  430. {
  431. mParticles[i]->mFlags = LLViewerPart::LL_PART_DEAD_MASK;
  432. }
  433. }
  434. }
  435. ///////////////////////////////////////////////////////////////////////////////
  436. // LLViewerPartSim class
  437. ///////////////////////////////////////////////////////////////////////////////
  438. void LLViewerPartSim::initClass()
  439. {
  440. setMaxPartCount(gSavedSettings.getS32("RenderMaxPartCount"));
  441. }
  442. void LLViewerPartSim::cleanupClass()
  443. {
  444. // Kill all of the groups (and particles)
  445. llinfos << "Destroying all particle groups..." << llendl;
  446. for (S32 i = 0, count = mViewerPartGroups.size(); i < count; ++i)
  447. {
  448. delete mViewerPartGroups[i];
  449. }
  450. mViewerPartGroups.clear();
  451. // Kill all of the sources
  452. llinfos << "Destroying all particle sources..." << llendl;
  453. mViewerPartSources.clear();
  454. llinfos << "Particles destroyed." << llendl;
  455. }
  456. //static
  457. void LLViewerPartSim::setMaxPartCount(S32 max)
  458. {
  459. sMaxParticleCount = llclamp(max, 2, 8192);
  460. }
  461. #if LL_DEBUG
  462. //static
  463. void LLViewerPartSim::checkParticleCount(U32 size)
  464. {
  465. if (sParticleCount2 != sParticleCount)
  466. {
  467. llerrs << "sParticleCount: " << sParticleCount
  468. << " - sParticleCount2: " << sParticleCount2 << llendl;
  469. }
  470. if (size > (U32)sParticleCount2)
  471. {
  472. llerrs << "Current particle size: " << sParticleCount2
  473. << " - array size: " << size << llendl;
  474. }
  475. }
  476. #endif
  477. //static
  478. bool LLViewerPartSim::shouldAddPart()
  479. {
  480. if (sParticleCount >= MAX_PART_COUNT)
  481. {
  482. return false;
  483. }
  484. if (sParticleCount > PART_THROTTLE_THRESHOLD * sMaxParticleCount)
  485. {
  486. F32 frac = (F32)sParticleCount / (F32)sMaxParticleCount;
  487. frac -= PART_THROTTLE_THRESHOLD;
  488. frac *= PART_THROTTLE_RESCALE;
  489. if (ll_frand() < frac)
  490. {
  491. // Skip...
  492. return false;
  493. }
  494. }
  495. // Check frame rate, and do not add more if the viewer is really slow
  496. constexpr F32 MIN_FRAME_RATE_FOR_NEW_PARTICLES = 5.f;
  497. return gFPSClamped >= MIN_FRAME_RATE_FOR_NEW_PARTICLES;
  498. }
  499. void LLViewerPartSim::addPart(LLViewerPart* part)
  500. {
  501. if (sParticleCount < MAX_PART_COUNT)
  502. {
  503. put(part);
  504. }
  505. else
  506. {
  507. // Delete the particle if we cannot add it in
  508. delete part;
  509. part = NULL;
  510. }
  511. }
  512. LLViewerPartGroup* LLViewerPartSim::put(LLViewerPart* part)
  513. {
  514. constexpr F32 MAX_MAG = 1000000.f * 1000000.f;
  515. LLViewerPartGroup* return_group = NULL;
  516. if (part->mPosAgent.lengthSquared() > MAX_MAG ||
  517. !part->mPosAgent.isFinite())
  518. {
  519. LL_DEBUGS("Particles") << "Particle out of range ! Position: "
  520. << part->mPosAgent << LL_ENDL;
  521. }
  522. else
  523. {
  524. F32 desired_size = calc_desired_size(part->mPosAgent, part->mScale);
  525. for (S32 i = 0, count = mViewerPartGroups.size(); i < count; ++i)
  526. {
  527. if (mViewerPartGroups[i]->addPart(part, desired_size))
  528. {
  529. // We found a spatial group that we fit into, add us and exit
  530. return_group = mViewerPartGroups[i];
  531. break;
  532. }
  533. }
  534. // Hmm, we did not fit in any of the existing spatial groups
  535. // Create a new one...
  536. if (!return_group)
  537. {
  538. llassert_always(part->mPosAgent.isFinite());
  539. LLViewerPartGroup* groupp =
  540. createViewerPartGroup(part->mPosAgent, desired_size,
  541. part->mFlags & LLPartData::LL_PART_HUD);
  542. groupp->mUniformParticles =
  543. part->mScale.mV[0] == part->mScale.mV[1] &&
  544. !(part->mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK);
  545. if (!groupp->addPart(part))
  546. {
  547. llwarns << "Particle did not go into its box ! Particle group center: "
  548. << groupp->getCenterAgent() << " - mPosAgent = "
  549. << part->mPosAgent << llendl;
  550. mViewerPartGroups.pop_back();
  551. delete groupp;
  552. groupp = NULL;
  553. }
  554. return_group = groupp;
  555. }
  556. }
  557. if (!return_group) // Failed to insert the particle
  558. {
  559. delete part;
  560. }
  561. return return_group;
  562. }
  563. LLViewerPartGroup* LLViewerPartSim::createViewerPartGroup(const LLVector3& pos_agent,
  564. F32 desired_size,
  565. bool hud)
  566. {
  567. // Find a box that has a center position divisible by PART_SIM_BOX_SIDE
  568. // that encompasses pos_agent
  569. LLViewerPartGroup* groupp = new LLViewerPartGroup(pos_agent, desired_size,
  570. hud);
  571. mViewerPartGroups.push_back(groupp);
  572. return groupp;
  573. }
  574. void LLViewerPartSim::shift(const LLVector3& offset)
  575. {
  576. for (S32 i = 0, count = mViewerPartSources.size(); i < count; ++i)
  577. {
  578. mViewerPartSources[i]->mPosAgent += offset;
  579. mViewerPartSources[i]->mTargetPosAgent += offset;
  580. mViewerPartSources[i]->mLastUpdatePosAgent += offset;
  581. }
  582. for (S32 i = 0, count = mViewerPartGroups.size(); i < count; ++i)
  583. {
  584. mViewerPartGroups[i]->shift(offset);
  585. }
  586. }
  587. void LLViewerPartSim::updateSimulation()
  588. {
  589. static LLFrameTimer update_timer;
  590. const F32 dt = llmin(update_timer.getElapsedTimeAndResetF32(), 0.1f);
  591. if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES))
  592. {
  593. return;
  594. }
  595. LL_FAST_TIMER(FTM_SIMULATE_PARTICLES);
  596. //MK
  597. // ref_joint will also be used as a flag for restricted vision in the loop
  598. // (when NULL, there is no restriction in force).
  599. LLJoint* ref_joint = NULL;
  600. LLVector3 joint_pos;
  601. if (gRLenabled && gRLInterface.mVisionRestricted)
  602. {
  603. ref_joint = gRLInterface.getCamDistDrawFromJoint();
  604. joint_pos = ref_joint->getWorldPosition();
  605. }
  606. //mk
  607. // Note: to avoid starvation of the particles allotment by high particle
  608. // count sources, the sources are updated in growing order of active
  609. // (rezzed) particles. The sorting is done at the end of this method. HB
  610. for (S32 i = 0, count = mViewerPartSources.size(); i < count; )
  611. {
  612. LLViewerPartSource* psrc = mViewerPartSources[i].get();
  613. if (psrc && !psrc->isDead())
  614. {
  615. bool upd = true;
  616. LLViewerObject* vobj = psrc->mSourceObjectp;
  617. bool is_volume = vobj && vobj->getPCode() == LL_PCODE_VOLUME;
  618. if (is_volume && !LLPipeline::sRenderAttachedParticles &&
  619. ((LLVOVolume*)vobj)->isAttachment())
  620. {
  621. upd = false;
  622. }
  623. if (upd && vobj && vobj->isAvatar() &&
  624. ((LLVOAvatar*)vobj)->isInMuteList())
  625. {
  626. upd = false;
  627. }
  628. if (upd && is_volume)
  629. {
  630. LLVOAvatar* avatar = vobj->getAvatar();
  631. if (avatar && avatar->isInMuteList())
  632. {
  633. upd = false;
  634. }
  635. }
  636. //MK
  637. // If our vision is obscured enough, particles in world and worn by
  638. // other avatars may give away their position (because of a
  639. // rendering issue) => hide them if their source object is too far.
  640. if (upd && is_volume && ref_joint)
  641. {
  642. LLVector3 offset = ((LLVOVolume*)vobj)->getPositionRegion() -
  643. joint_pos;
  644. if (offset.length() > gRLInterface.mCamDistDrawMax)
  645. {
  646. upd = false;
  647. }
  648. }
  649. //mk
  650. if (upd)
  651. {
  652. psrc->update(dt);
  653. }
  654. else
  655. {
  656. // Pretend the source is too far away (used in sorting)
  657. psrc->mDistFromCamera = 1024.f;
  658. }
  659. // Increment the updates count for this source
  660. psrc->incPartUpdates();
  661. }
  662. if (!psrc || psrc->isDead())
  663. {
  664. if (i < --count)
  665. {
  666. mViewerPartSources[i] = mViewerPartSources.back();
  667. }
  668. mViewerPartSources.pop_back();
  669. }
  670. else
  671. {
  672. ++i;
  673. }
  674. }
  675. S32 current_frame = LLViewerOctreeEntryData::getCurrentFrame();
  676. for (S32 i = 0, count = mViewerPartGroups.size(); i < count; ++i)
  677. {
  678. LLViewerPartGroup* pgroup = mViewerPartGroups[i];
  679. if (!pgroup) continue; // Paranoia !
  680. LLViewerObject* vobj = pgroup->mVOPartGroupp;
  681. LLDrawable* drawable = NULL;
  682. if (vobj && !vobj->isDead())
  683. {
  684. drawable = vobj->mDrawable;
  685. if (drawable && drawable->isDead())
  686. {
  687. drawable = NULL;
  688. }
  689. }
  690. S32 visirate = 1;
  691. if (drawable)
  692. {
  693. LLSpatialGroup* group = drawable->getSpatialGroup();
  694. if (group && !group->isVisible() /* &&
  695. !group->isState(LLSpatialGroup::OBJECT_DIRTY)*/)
  696. {
  697. if (!vobj || vobj->getPCode() != LL_PCODE_VOLUME ||
  698. !(LLPipeline::sRenderAttachedParticles &&
  699. ((LLVOVolume*)vobj)->isAttachment()))
  700. {
  701. visirate = 8;
  702. if (vobj)
  703. {
  704. LL_DEBUGS("Particles") << "Object " << vobj->getID()
  705. << " gets its particles refresh sparsed because its group is not visible."
  706. << LL_ENDL;
  707. }
  708. }
  709. }
  710. }
  711. if ((current_frame + pgroup->mID) % visirate == 0)
  712. {
  713. if (drawable)
  714. {
  715. gPipeline.markRebuild(drawable);
  716. }
  717. pgroup->updateParticles(dt * visirate);
  718. pgroup->mSkippedTime = 0.f;
  719. if (!pgroup->getCount())
  720. {
  721. delete pgroup;
  722. mViewerPartGroups[i--] = mViewerPartGroups.back();
  723. mViewerPartGroups.pop_back();
  724. --count;
  725. }
  726. }
  727. else
  728. {
  729. pgroup->mSkippedTime += dt;
  730. }
  731. }
  732. if (current_frame % 16 == 0)
  733. {
  734. if (sParticleCount > sMaxParticleCount * 0.875f &&
  735. sParticleAdaptiveRate < 2.f)
  736. {
  737. sParticleAdaptiveRate *= PART_ADAPT_RATE_MULT;
  738. }
  739. else
  740. {
  741. if (sParticleCount < sMaxParticleCount * 0.5f &&
  742. sParticleAdaptiveRate > 0.03125f)
  743. {
  744. sParticleAdaptiveRate *= PART_ADAPT_RATE_MULT_RECIP;
  745. }
  746. }
  747. #if 0 // Way too spammy...
  748. LL_DEBUGS("Particles") << "Particles: " << sParticleCount
  749. << " Adaptive Rate: " << sParticleAdaptiveRate
  750. << LL_ENDL;
  751. #endif
  752. }
  753. updatePartBurstRate();
  754. // Let's now sort the particle sources following the average number of
  755. // active (rezzed) particles they got per update, so that the sources
  756. // with less particles are updated first on next updateSimulation() run.
  757. // We also take into account the distance to the camera in our priorizing.
  758. // We use a std::map with a long integer as the key to perform a quick
  759. // sorting, by using the averaged particles count multiplied by a distance
  760. // factor as the MSLW of the key with a counter as the LSLW of the key, and
  761. // the source object address as the map data. We then std::move the smart
  762. // pointers to the sources from that map back into the sources vector. HB
  763. {
  764. LL_FAST_TIMER(FTM_SIM_PART_SORT);
  765. // Using an union to avoid costly bit shifting...
  766. union key_value
  767. {
  768. U64 key;
  769. U32 word[2];
  770. } kv;
  771. #if LL_BIG_ENDIAN
  772. # define LSW 1
  773. # define MSW 0
  774. #else
  775. # define LSW 0
  776. # define MSW 1
  777. #endif
  778. constexpr F32 ONE32TH = 1.f / 32.f;
  779. U32 count = (U32)mViewerPartSources.size();
  780. llassert(count < 1 << 24);
  781. typedef std::map<U64, LLPointer<LLViewerPartSource> > sorting_map_t;
  782. sorting_map_t sources;
  783. for (U32 i = 0; i < count; ++i)
  784. {
  785. LLViewerPartSource* psrc = mViewerPartSources[i].get();
  786. // Compute the key we will sort the particles with
  787. U64 dist_ratio = psrc->mDistFromCamera * ONE32TH;
  788. if (dist_ratio == 0)
  789. {
  790. dist_ratio = 1;
  791. }
  792. kv.word[LSW] = i;
  793. kv.word[MSW] = psrc->getAveragePartCount() * dist_ratio;
  794. LL_DEBUGS("Particles") << "Particle source #" << i << " "
  795. << psrc->getID();
  796. LLViewerObject* vobj = psrc->mSourceObjectp;
  797. if (vobj)
  798. {
  799. LL_CONT << " on object " << vobj->getID();
  800. if (vobj && vobj->getPCode() == LL_PCODE_VOLUME)
  801. {
  802. LLVOVolume* vvo = (LLVOVolume*)vobj;
  803. if (vvo && vvo->isAttachment())
  804. {
  805. LL_CONT << " (attachment)";
  806. }
  807. }
  808. }
  809. LL_CONT << " got an average particles count * distance factor of: "
  810. << kv.word[MSW] << " - Resulting key: 0x" << std::hex
  811. << kv.key << std::dec << LL_ENDL;
  812. // Do this last in the loop since mViewerPartSources[i] gets
  813. // invalidated (NULLed) by the move constructor of LLPointer.
  814. sources[kv.key] = std::move(mViewerPartSources[i]);
  815. }
  816. llassert_always(sources.size() == count);
  817. sorting_map_t::iterator it = sources.begin();
  818. for (U32 i = 0; i < count; ++i, ++it)
  819. {
  820. mViewerPartSources[i] = std::move(it->second);
  821. }
  822. LL_DEBUGS("Particles") << "Sorted particles sources:";
  823. for (U32 i = 0; i < count; ++i, ++it)
  824. {
  825. LL_CONT << "\n #" << i + 1 << ", source "
  826. << mViewerPartSources[i]->getID();
  827. }
  828. LL_CONT << LL_ENDL;
  829. }
  830. }
  831. void LLViewerPartSim::updatePartBurstRate()
  832. {
  833. if (LLViewerOctreeEntryData::getCurrentFrame() & 0xf)
  834. {
  835. return;
  836. }
  837. if (sParticleCount >= MAX_PART_COUNT)
  838. {
  839. // Set rate to zero if above max particles count
  840. sParticleBurstRate = 0.f;
  841. return;
  842. }
  843. if (sParticleCount <= 0)
  844. {
  845. sParticleBurstRate += 0.00125f;
  846. return;
  847. }
  848. if (sParticleBurstRate <= 0.0000001f)
  849. {
  850. sParticleBurstRate += 0.0000001f;
  851. return;
  852. }
  853. F32 total_particles = sParticleCount / sParticleBurstRate; // Estimated
  854. F32 new_rate = llmin(0.9f * sMaxParticleCount / total_particles, 1.f);
  855. F32 delta_rate_threshold =
  856. llmin(0.1f * llmax(new_rate, sParticleBurstRate), 0.1f);
  857. F32 delta_rate = llclamp(new_rate - sParticleBurstRate,
  858. -delta_rate_threshold, delta_rate_threshold);
  859. sParticleBurstRate = llclamp(sParticleBurstRate + 0.5f * delta_rate,
  860. 0.f, 1.f);
  861. }
  862. void LLViewerPartSim::addPartSource(LLPointer<LLViewerPartSource> sourcep)
  863. {
  864. if (sourcep.isNull())
  865. {
  866. llwarns << "Null particle source !" << llendl;
  867. return;
  868. }
  869. sourcep->setStart();
  870. // Do this last since sourcep gets invalidated (NULLed) by the move
  871. // constructor of LLPointer. HB
  872. mViewerPartSources.emplace_back(std::move(sourcep));
  873. }
  874. void LLViewerPartSim::removeLastCreatedSource()
  875. {
  876. mViewerPartSources.pop_back();
  877. }
  878. void LLViewerPartSim::cleanupRegion(LLViewerRegion* regionp)
  879. {
  880. for (U32 i = 0, count = mViewerPartGroups.size(); i < count; )
  881. {
  882. if (mViewerPartGroups[i]->getRegion() == regionp)
  883. {
  884. delete mViewerPartGroups[i];
  885. if (i < --count)
  886. {
  887. mViewerPartGroups[i] = mViewerPartGroups.back();
  888. }
  889. mViewerPartGroups.pop_back();
  890. }
  891. else
  892. {
  893. ++i;
  894. }
  895. }
  896. }
  897. void LLViewerPartSim::clearParticlesByID(U32 system_id)
  898. {
  899. for (group_list_t::iterator g = mViewerPartGroups.begin(),
  900. end = mViewerPartGroups.end();
  901. g != end; ++g)
  902. {
  903. (*g)->removeParticlesByID(system_id);
  904. }
  905. for (source_list_t::iterator i = mViewerPartSources.begin(),
  906. end = mViewerPartSources.end();
  907. i != end; ++i)
  908. {
  909. if ((*i)->getID() == system_id)
  910. {
  911. (*i)->setDead();
  912. break;
  913. }
  914. }
  915. }
  916. void LLViewerPartSim::clearParticlesByOwnerID(const LLUUID& task_id)
  917. {
  918. for (source_list_t::iterator iter = mViewerPartSources.begin(),
  919. end = mViewerPartSources.end();
  920. iter != end; ++iter)
  921. {
  922. if ((*iter)->getOwnerUUID() == task_id)
  923. {
  924. clearParticlesByID((*iter)->getID());
  925. }
  926. }
  927. }
  928. void LLViewerPartSim::clearParticlesByRootObjectID(const LLUUID& object_id)
  929. {
  930. LLViewerObject* objectp = gObjectList.findObject(object_id);
  931. if (!objectp)
  932. {
  933. llwarns << "Tried to clear particles for non-existent object "
  934. << object_id << llendl;
  935. }
  936. else if (objectp->isAvatar())
  937. {
  938. clearParticlesByOwnerID(object_id);
  939. }
  940. else
  941. {
  942. if (objectp->getPartSource())
  943. {
  944. clearParticlesByID(objectp->getPartSource()->getID());
  945. }
  946. for (LLViewerObject::child_list_t::const_iterator
  947. it = objectp->getChildren().begin(),
  948. end = objectp->getChildren().end();
  949. it != end; ++it)
  950. {
  951. LLViewerObject* childp = *it;
  952. if (childp && childp->getPartSource())
  953. {
  954. clearParticlesByID(childp->getPartSource()->getID());
  955. }
  956. }
  957. }
  958. }