llviewerpartsim.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:21k
源码类别:

游戏引擎

开发平台:

C++ Builder

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