b2ParticleSystem.h 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544
  1. /*
  2. * Copyright (c) 2013 Google, Inc.
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. * Permission is granted to anyone to use this software for any purpose,
  8. * including commercial applications, and to alter it and redistribute it
  9. * freely, subject to the following restrictions:
  10. * 1. The origin of this software must not be misrepresented; you must not
  11. * claim that you wrote the original software. If you use this software
  12. * in a product, an acknowledgment in the product documentation would be
  13. * appreciated but is not required.
  14. * 2. Altered source versions must be plainly marked as such, and must not be
  15. * misrepresented as being the original software.
  16. * 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #ifndef B2_PARTICLE_SYSTEM_H
  19. #define B2_PARTICLE_SYSTEM_H
  20. #include <Box2D/Common/b2SlabAllocator.h>
  21. #include <Box2D/Common/b2GrowableBuffer.h>
  22. #include <Box2D/Particle/b2Particle.h>
  23. #include <Box2D/Dynamics/b2TimeStep.h>
  24. #if LIQUIDFUN_UNIT_TESTS
  25. #include <gtest/gtest.h>
  26. #endif // LIQUIDFUN_UNIT_TESTS
  27. #if LIQUIDFUN_EXTERNAL_LANGUAGE_API
  28. #include <cstring>
  29. #endif // LIQUIDFUN_EXTERNAL_LANGUAGE_API
  30. class b2World;
  31. class b2Body;
  32. class b2Shape;
  33. class b2ParticleGroup;
  34. class b2BlockAllocator;
  35. class b2StackAllocator;
  36. class b2QueryCallback;
  37. class b2RayCastCallback;
  38. class b2Fixture;
  39. class b2ContactFilter;
  40. class b2ContactListener;
  41. class b2ParticlePairSet;
  42. class FixtureParticleSet;
  43. struct b2ParticleGroupDef;
  44. struct b2Vec2;
  45. struct b2AABB;
  46. struct FindContactInput;
  47. struct FindContactCheck;
  48. struct b2ParticleContact
  49. {
  50. private:
  51. // 16-bit particle indices consume less memory and thus improve
  52. // performance. We iterate through m_contactBuffer many times during
  53. // b2ParticleSystem::Solve, so reducing the amount of data we churn
  54. // through speeds things up. Also, FindContactsFromChecks_Simd takes
  55. // advantage of the reduced size for specific optimizations.
  56. #ifdef B2_USE_16_BIT_PARTICLE_INDICES
  57. typedef int16 b2ParticleIndex;
  58. #else
  59. typedef int32 b2ParticleIndex;
  60. #endif
  61. /// Indices of the respective particles making contact.
  62. b2ParticleIndex indexA, indexB;
  63. /// Weight of the contact. A value between 0.0f and 1.0f.
  64. /// 0.0f ==> particles are just barely touching
  65. /// 1.0f ==> particles are perfectly on top of each other
  66. float32 weight;
  67. /// The normalized direction from A to B.
  68. b2Vec2 normal;
  69. /// The logical sum of the particle behaviors that have been set.
  70. /// See the b2ParticleFlag enum.
  71. uint32 flags;
  72. public:
  73. void SetIndices(int32 a, int32 b);
  74. void SetWeight(float32 w) { weight = w; }
  75. void SetNormal(const b2Vec2& n) { normal = n; }
  76. void SetFlags(uint32 f) { flags = f; }
  77. int32 GetIndexA() const { return indexA; }
  78. int32 GetIndexB() const { return indexB; }
  79. float32 GetWeight() const { return weight; }
  80. const b2Vec2& GetNormal() const { return normal; }
  81. uint32 GetFlags() const { return flags; }
  82. bool operator==(const b2ParticleContact& rhs) const;
  83. bool operator!=(const b2ParticleContact& rhs) const { return !operator==(rhs); }
  84. bool ApproximatelyEqual(const b2ParticleContact& rhs) const;
  85. };
  86. struct b2ParticleBodyContact
  87. {
  88. /// Index of the particle making contact.
  89. int32 index;
  90. /// The body making contact.
  91. b2Body* body;
  92. /// The specific fixture making contact
  93. b2Fixture* fixture;
  94. /// Weight of the contact. A value between 0.0f and 1.0f.
  95. float32 weight;
  96. /// The normalized direction from the particle to the body.
  97. b2Vec2 normal;
  98. /// The effective mass used in calculating force.
  99. float32 mass;
  100. };
  101. /// Connection between two particles
  102. struct b2ParticlePair
  103. {
  104. /// Indices of the respective particles making pair.
  105. int32 indexA, indexB;
  106. /// The logical sum of the particle flags. See the b2ParticleFlag enum.
  107. uint32 flags;
  108. /// The strength of cohesion among the particles.
  109. float32 strength;
  110. /// The initial distance of the particles.
  111. float32 distance;
  112. };
  113. /// Connection between three particles
  114. struct b2ParticleTriad
  115. {
  116. /// Indices of the respective particles making triad.
  117. int32 indexA, indexB, indexC;
  118. /// The logical sum of the particle flags. See the b2ParticleFlag enum.
  119. uint32 flags;
  120. /// The strength of cohesion among the particles.
  121. float32 strength;
  122. /// Values used for calculation.
  123. b2Vec2 pa, pb, pc;
  124. float32 ka, kb, kc, s;
  125. };
  126. struct b2ParticleSystemDef
  127. {
  128. b2ParticleSystemDef()
  129. {
  130. strictContactCheck = false;
  131. density = 1.0f;
  132. gravityScale = 1.0f;
  133. radius = 1.0f;
  134. maxCount = 0;
  135. // Initialize physical coefficients to the maximum values that
  136. // maintain numerical stability.
  137. pressureStrength = 0.05f;
  138. dampingStrength = 1.0f;
  139. elasticStrength = 0.25f;
  140. springStrength = 0.25f;
  141. viscousStrength = 0.25f;
  142. surfaceTensionPressureStrength = 0.2f;
  143. surfaceTensionNormalStrength = 0.2f;
  144. repulsiveStrength = 1.0f;
  145. powderStrength = 0.5f;
  146. ejectionStrength = 0.5f;
  147. staticPressureStrength = 0.2f;
  148. staticPressureRelaxation = 0.2f;
  149. staticPressureIterations = 8;
  150. colorMixingStrength = 0.5f;
  151. destroyByAge = true;
  152. lifetimeGranularity = 1.0f / 60.0f;
  153. }
  154. /// Enable strict Particle/Body contact check.
  155. /// See SetStrictContactCheck for details.
  156. bool strictContactCheck;
  157. /// Set the particle density.
  158. /// See SetDensity for details.
  159. float32 density;
  160. /// Change the particle gravity scale. Adjusts the effect of the global
  161. /// gravity vector on particles. Default value is 1.0f.
  162. float32 gravityScale;
  163. /// Particles behave as circles with this radius. In Box2D units.
  164. float32 radius;
  165. /// Set the maximum number of particles.
  166. /// By default, there is no maximum. The particle buffers can continue to
  167. /// grow while b2World's block allocator still has memory.
  168. /// See SetMaxParticleCount for details.
  169. int32 maxCount;
  170. /// Increases pressure in response to compression
  171. /// Smaller values allow more compression
  172. float32 pressureStrength;
  173. /// Reduces velocity along the collision normal
  174. /// Smaller value reduces less
  175. float32 dampingStrength;
  176. /// Restores shape of elastic particle groups
  177. /// Larger values increase elastic particle velocity
  178. float32 elasticStrength;
  179. /// Restores length of spring particle groups
  180. /// Larger values increase spring particle velocity
  181. float32 springStrength;
  182. /// Reduces relative velocity of viscous particles
  183. /// Larger values slow down viscous particles more
  184. float32 viscousStrength;
  185. /// Produces pressure on tensile particles
  186. /// 0~0.2. Larger values increase the amount of surface tension.
  187. float32 surfaceTensionPressureStrength;
  188. /// Smoothes outline of tensile particles
  189. /// 0~0.2. Larger values result in rounder, smoother, water-drop-like
  190. /// clusters of particles.
  191. float32 surfaceTensionNormalStrength;
  192. /// Produces additional pressure on repulsive particles
  193. /// Larger values repulse more
  194. /// Negative values mean attraction. The range where particles behave
  195. /// stably is about -0.2 to 2.0.
  196. float32 repulsiveStrength;
  197. /// Produces repulsion between powder particles
  198. /// Larger values repulse more
  199. float32 powderStrength;
  200. /// Pushes particles out of solid particle group
  201. /// Larger values repulse more
  202. float32 ejectionStrength;
  203. /// Produces static pressure
  204. /// Larger values increase the pressure on neighboring partilces
  205. /// For a description of static pressure, see
  206. /// http://en.wikipedia.org/wiki/Static_pressure#Static_pressure_in_fluid_dynamics
  207. float32 staticPressureStrength;
  208. /// Reduces instability in static pressure calculation
  209. /// Larger values make stabilize static pressure with fewer iterations
  210. float32 staticPressureRelaxation;
  211. /// Computes static pressure more precisely
  212. /// See SetStaticPressureIterations for details
  213. int32 staticPressureIterations;
  214. /// Determines how fast colors are mixed
  215. /// 1.0f ==> mixed immediately
  216. /// 0.5f ==> mixed half way each simulation step (see b2World::Step())
  217. float32 colorMixingStrength;
  218. /// Whether to destroy particles by age when no more particles can be
  219. /// created. See #b2ParticleSystem::SetDestructionByAge() for
  220. /// more information.
  221. bool destroyByAge;
  222. /// Granularity of particle lifetimes in seconds. By default this is
  223. /// set to (1.0f / 60.0f) seconds. b2ParticleSystem uses a 32-bit signed
  224. /// value to track particle lifetimes so the maximum lifetime of a
  225. /// particle is (2^32 - 1) / (1.0f / lifetimeGranularity) seconds.
  226. /// With the value set to 1/60 the maximum lifetime or age of a particle is
  227. /// 2.27 years.
  228. float32 lifetimeGranularity;
  229. };
  230. class b2ParticleSystem
  231. {
  232. public:
  233. /// Create a particle whose properties have been defined.
  234. /// No reference to the definition is retained.
  235. /// A simulation step must occur before it's possible to interact with a
  236. /// newly created particle. For example, DestroyParticleInShape() will
  237. /// not destroy a particle until b2World::Step() has been called.
  238. /// @warning This function is locked during callbacks.
  239. /// @return the index of the particle.
  240. int32 CreateParticle(const b2ParticleDef& def);
  241. /// Retrieve a handle to the particle at the specified index.
  242. /// Please see #b2ParticleHandle for why you might want a handle.
  243. const b2ParticleHandle* GetParticleHandleFromIndex(const int32 index);
  244. /// Destroy a particle.
  245. /// The particle is removed after the next simulation step (see
  246. /// b2World::Step()).
  247. void DestroyParticle(int32 index)
  248. {
  249. DestroyParticle(index, false);
  250. }
  251. /// Destroy a particle.
  252. /// The particle is removed after the next step.
  253. /// @param Index of the particle to destroy.
  254. /// @param Whether to call the destruction listener just before the
  255. /// particle is destroyed.
  256. void DestroyParticle(int32 index, bool callDestructionListener);
  257. /// Destroy the Nth oldest particle in the system.
  258. /// The particle is removed after the next b2World::Step().
  259. /// @param Index of the Nth oldest particle to destroy, 0 will destroy the
  260. /// oldest particle in the system, 1 will destroy the next oldest
  261. /// particle etc.
  262. /// @param Whether to call the destruction listener just before the
  263. /// particle is destroyed.
  264. void DestroyOldestParticle(const int32 index,
  265. const bool callDestructionListener);
  266. /// Destroy particles inside a shape without enabling the destruction
  267. /// callback for destroyed particles.
  268. /// This function is locked during callbacks.
  269. /// For more information see
  270. /// DestroyParticleInShape(const b2Shape&, const b2Transform&,bool).
  271. /// @param Shape which encloses particles that should be destroyed.
  272. /// @param Transform applied to the shape.
  273. /// @warning This function is locked during callbacks.
  274. /// @return Number of particles destroyed.
  275. int32 DestroyParticlesInShape(const b2Shape& shape, const b2Transform& xf)
  276. {
  277. return DestroyParticlesInShape(shape, xf, false);
  278. }
  279. /// Destroy particles inside a shape.
  280. /// This function is locked during callbacks.
  281. /// In addition, this function immediately destroys particles in the shape
  282. /// in constrast to DestroyParticle() which defers the destruction until
  283. /// the next simulation step.
  284. /// @param Shape which encloses particles that should be destroyed.
  285. /// @param Transform applied to the shape.
  286. /// @param Whether to call the world b2DestructionListener for each
  287. /// particle destroyed.
  288. /// @warning This function is locked during callbacks.
  289. /// @return Number of particles destroyed.
  290. int32 DestroyParticlesInShape(const b2Shape& shape, const b2Transform& xf,
  291. bool callDestructionListener);
  292. /// Create a particle group whose properties have been defined. No
  293. /// reference to the definition is retained.
  294. /// @warning This function is locked during callbacks.
  295. b2ParticleGroup* CreateParticleGroup(const b2ParticleGroupDef& def);
  296. /// Join two particle groups.
  297. /// @param the first group. Expands to encompass the second group.
  298. /// @param the second group. It is destroyed.
  299. /// @warning This function is locked during callbacks.
  300. void JoinParticleGroups(b2ParticleGroup* groupA, b2ParticleGroup* groupB);
  301. /// Split particle group into multiple disconnected groups.
  302. /// @param the group to be split.
  303. /// @warning This function is locked during callbacks.
  304. void SplitParticleGroup(b2ParticleGroup* group);
  305. /// Get the world particle group list. With the returned group, use
  306. /// b2ParticleGroup::GetNext to get the next group in the world list.
  307. /// A NULL group indicates the end of the list.
  308. /// @return the head of the world particle group list.
  309. b2ParticleGroup* GetParticleGroupList();
  310. const b2ParticleGroup* GetParticleGroupList() const;
  311. /// Get the number of particle groups.
  312. int32 GetParticleGroupCount() const;
  313. /// Get the number of particles.
  314. int32 GetParticleCount() const;
  315. /// Get the maximum number of particles.
  316. int32 GetMaxParticleCount() const;
  317. /// Set the maximum number of particles.
  318. /// A value of 0 means there is no maximum. The particle buffers can
  319. /// continue to grow while b2World's block allocator still has memory.
  320. /// Note: If you try to CreateParticle() with more than this count,
  321. /// b2_invalidParticleIndex is returned unless
  322. /// SetDestructionByAge() is used to enable the destruction of the
  323. /// oldest particles in the system.
  324. void SetMaxParticleCount(int32 count);
  325. /// Get all existing particle flags.
  326. uint32 GetAllParticleFlags() const;
  327. /// Get all existing particle group flags.
  328. uint32 GetAllGroupFlags() const;
  329. /// Pause or unpause the particle system. When paused, b2World::Step()
  330. /// skips over this particle system. All b2ParticleSystem function calls
  331. /// still work.
  332. /// @param paused is true to pause, false to un-pause.
  333. void SetPaused(bool paused);
  334. /// @return true if the particle system is being updated in
  335. /// b2World::Step().
  336. /// Initially, true, then, the last value passed into SetPaused().
  337. bool GetPaused() const;
  338. /// Change the particle density.
  339. /// Particle density affects the mass of the particles, which in turn
  340. /// affects how the particles interact with b2Bodies. Note that the density
  341. /// does not affect how the particles interact with each other.
  342. void SetDensity(float32 density);
  343. /// Get the particle density.
  344. float32 GetDensity() const;
  345. /// Change the particle gravity scale. Adjusts the effect of the global
  346. /// gravity vector on particles.
  347. void SetGravityScale(float32 gravityScale);
  348. /// Get the particle gravity scale.
  349. float32 GetGravityScale() const;
  350. /// Damping is used to reduce the velocity of particles. The damping
  351. /// parameter can be larger than 1.0f but the damping effect becomes
  352. /// sensitive to the time step when the damping parameter is large.
  353. void SetDamping(float32 damping);
  354. /// Get damping for particles
  355. float32 GetDamping() const;
  356. /// Change the number of iterations when calculating the static pressure of
  357. /// particles. By default, 8 iterations. You can reduce the number of
  358. /// iterations down to 1 in some situations, but this may cause
  359. /// instabilities when many particles come together. If you see particles
  360. /// popping away from each other like popcorn, you may have to increase the
  361. /// number of iterations.
  362. /// For a description of static pressure, see
  363. /// http://en.wikipedia.org/wiki/Static_pressure#Static_pressure_in_fluid_dynamics
  364. void SetStaticPressureIterations(int32 iterations);
  365. /// Get the number of iterations for static pressure of particles.
  366. int32 GetStaticPressureIterations() const;
  367. /// Change the particle radius.
  368. /// You should set this only once, on world start.
  369. /// If you change the radius during execution, existing particles may
  370. /// explode, shrink, or behave unexpectedly.
  371. void SetRadius(float32 radius);
  372. /// Get the particle radius.
  373. float32 GetRadius() const;
  374. /// Get the position of each particle
  375. /// Array is length GetParticleCount()
  376. /// @return the pointer to the head of the particle positions array.
  377. b2Vec2* GetPositionBuffer();
  378. const b2Vec2* GetPositionBuffer() const;
  379. /// Get the velocity of each particle
  380. /// Array is length GetParticleCount()
  381. /// @return the pointer to the head of the particle velocities array.
  382. b2Vec2* GetVelocityBuffer();
  383. const b2Vec2* GetVelocityBuffer() const;
  384. /// Get the color of each particle
  385. /// Array is length GetParticleCount()
  386. /// @return the pointer to the head of the particle colors array.
  387. b2ParticleColor* GetColorBuffer();
  388. const b2ParticleColor* GetColorBuffer() const;
  389. /// Get the particle-group of each particle.
  390. /// Array is length GetParticleCount()
  391. /// @return the pointer to the head of the particle group array.
  392. b2ParticleGroup* const* GetGroupBuffer();
  393. const b2ParticleGroup* const* GetGroupBuffer() const;
  394. /// Get the weight of each particle
  395. /// Array is length GetParticleCount()
  396. /// @return the pointer to the head of the particle positions array.
  397. float32* GetWeightBuffer();
  398. const float32* GetWeightBuffer() const;
  399. /// Get the user-specified data of each particle.
  400. /// Array is length GetParticleCount()
  401. /// @return the pointer to the head of the particle user-data array.
  402. void** GetUserDataBuffer();
  403. void* const* GetUserDataBuffer() const;
  404. /// Get the flags for each particle. See the b2ParticleFlag enum.
  405. /// Array is length GetParticleCount()
  406. /// @return the pointer to the head of the particle-flags array.
  407. const uint32* GetFlagsBuffer() const;
  408. /// Set flags for a particle. See the b2ParticleFlag enum.
  409. void SetParticleFlags(int32 index, uint32 flags);
  410. /// Get flags for a particle. See the b2ParticleFlag enum.
  411. uint32 GetParticleFlags(const int32 index);
  412. /// Set an external buffer for particle data.
  413. /// Normally, the b2World's block allocator is used for particle data.
  414. /// However, sometimes you may have an OpenGL or Java buffer for particle
  415. /// data. To avoid data duplication, you may supply this external buffer.
  416. ///
  417. /// Note that, when b2World's block allocator is used, the particle data
  418. /// buffers can grow as required. However, when external buffers are used,
  419. /// the maximum number of particles is clamped to the size of the smallest
  420. /// external buffer.
  421. ///
  422. /// @param buffer is a pointer to a block of memory.
  423. /// @param size is the number of values in the block.
  424. void SetFlagsBuffer(uint32* buffer, int32 capacity);
  425. void SetPositionBuffer(b2Vec2* buffer, int32 capacity);
  426. void SetVelocityBuffer(b2Vec2* buffer, int32 capacity);
  427. void SetColorBuffer(b2ParticleColor* buffer, int32 capacity);
  428. void SetUserDataBuffer(void** buffer, int32 capacity);
  429. /// Get contacts between particles
  430. /// Contact data can be used for many reasons, for example to trigger
  431. /// rendering or audio effects.
  432. const b2ParticleContact* GetContacts() const;
  433. int32 GetContactCount() const;
  434. /// Get contacts between particles and bodies
  435. /// Contact data can be used for many reasons, for example to trigger
  436. /// rendering or audio effects.
  437. const b2ParticleBodyContact* GetBodyContacts() const;
  438. int32 GetBodyContactCount() const;
  439. /// Get array of particle pairs. The particles in a pair:
  440. /// (1) are contacting,
  441. /// (2) are in the same particle group,
  442. /// (3) are part of a rigid particle group, or are spring, elastic,
  443. /// or wall particles.
  444. /// (4) have at least one particle that is a spring or barrier
  445. /// particle (i.e. one of the types in k_pairFlags),
  446. /// (5) have at least one particle that returns true for
  447. /// ConnectionFilter::IsNecessary,
  448. /// (6) are not zombie particles.
  449. /// Essentially, this is an array of spring or barrier particles that
  450. /// are interacting. The array is sorted by b2ParticlePair's indexA,
  451. /// and then indexB. There are no duplicate entries.
  452. const b2ParticlePair* GetPairs() const;
  453. int32 GetPairCount() const;
  454. /// Get array of particle triads. The particles in a triad:
  455. /// (1) are in the same particle group,
  456. /// (2) are in a Voronoi triangle together,
  457. /// (3) are within b2_maxTriadDistance particle diameters of each
  458. /// other,
  459. /// (4) return true for ConnectionFilter::ShouldCreateTriad
  460. /// (5) have at least one particle of type elastic (i.e. one of the
  461. /// types in k_triadFlags),
  462. /// (6) are part of a rigid particle group, or are spring, elastic,
  463. /// or wall particles.
  464. /// (7) are not zombie particles.
  465. /// Essentially, this is an array of elastic particles that are
  466. /// interacting. The array is sorted by b2ParticleTriad's indexA,
  467. /// then indexB, then indexC. There are no duplicate entries.
  468. const b2ParticleTriad* GetTriads() const;
  469. int32 GetTriadCount() const;
  470. /// Set an optional threshold for the maximum number of
  471. /// consecutive particle iterations that a particle may contact
  472. /// multiple bodies before it is considered a candidate for being
  473. /// "stuck". Setting to zero or less disables.
  474. void SetStuckThreshold(int32 iterations);
  475. /// Get potentially stuck particles from the last step; the user must
  476. /// decide if they are stuck or not, and if so, delete or move them
  477. const int32* GetStuckCandidates() const;
  478. /// Get the number of stuck particle candidates from the last step.
  479. int32 GetStuckCandidateCount() const;
  480. /// Compute the kinetic energy that can be lost by damping force
  481. float32 ComputeCollisionEnergy() const;
  482. /// Set strict Particle/Body contact check.
  483. /// This is an option that will help ensure correct behavior if there are
  484. /// corners in the world model where Particle/Body contact is ambiguous.
  485. /// This option scales at n*log(n) of the number of Particle/Body contacts,
  486. /// so it is best to only enable if it is necessary for your geometry.
  487. /// Enable if you see strange particle behavior around b2Body
  488. /// intersections.
  489. void SetStrictContactCheck(bool enabled);
  490. /// Get the status of the strict contact check.
  491. bool GetStrictContactCheck() const;
  492. /// Set the lifetime (in seconds) of a particle relative to the current
  493. /// time. A lifetime of less than or equal to 0.0f results in the particle
  494. /// living forever until it's manually destroyed by the application.
  495. void SetParticleLifetime(const int32 index, const float32 lifetime);
  496. /// Get the lifetime (in seconds) of a particle relative to the current
  497. /// time. A value > 0.0f is returned if the particle is scheduled to be
  498. /// destroyed in the future, values <= 0.0f indicate the particle has an
  499. /// infinite lifetime.
  500. float32 GetParticleLifetime(const int32 index);
  501. /// Enable / disable destruction of particles in CreateParticle() when
  502. /// no more particles can be created due to a prior call to
  503. /// SetMaxParticleCount(). When this is enabled, the oldest particle is
  504. /// destroyed in CreateParticle() favoring the destruction of particles
  505. /// with a finite lifetime over particles with infinite lifetimes.
  506. /// This feature is enabled by default when particle lifetimes are
  507. /// tracked. Explicitly enabling this feature using this function enables
  508. /// particle lifetime tracking.
  509. void SetDestructionByAge(const bool enable);
  510. /// Get whether the oldest particle will be destroyed in CreateParticle()
  511. /// when the maximum number of particles are present in the system.
  512. bool GetDestructionByAge() const;
  513. /// Get the array of particle expiration times indexed by particle index.
  514. /// GetParticleCount() items are in the returned array.
  515. const int32* GetExpirationTimeBuffer();
  516. /// Convert a expiration time value in returned by
  517. /// GetExpirationTimeBuffer() to a time in seconds relative to the
  518. /// current simulation time.
  519. float32 ExpirationTimeToLifetime(const int32 expirationTime) const;
  520. /// Get the array of particle indices ordered by reverse lifetime.
  521. /// The oldest particle indexes are at the end of the array with the
  522. /// newest at the start. Particles with infinite lifetimes
  523. /// (i.e expiration times less than or equal to 0) are placed at the start
  524. /// of the array.
  525. /// ExpirationTimeToLifetime(GetExpirationTimeBuffer()[index])
  526. /// is equivalent to GetParticleLifetime(index).
  527. /// GetParticleCount() items are in the returned array.
  528. const int32* GetIndexByExpirationTimeBuffer();
  529. /// Apply an impulse to one particle. This immediately modifies the
  530. /// velocity. Similar to b2Body::ApplyLinearImpulse.
  531. /// @param index the particle that will be modified.
  532. /// @param impulse the world impulse vector, usually in N-seconds or
  533. /// kg-m/s.
  534. void ParticleApplyLinearImpulse(int32 index, const b2Vec2& impulse);
  535. /// Apply an impulse to all particles between 'firstIndex' and 'lastIndex'.
  536. /// This immediately modifies the velocity. Note that the impulse is
  537. /// applied to the total mass of all particles. So, calling
  538. /// ParticleApplyLinearImpulse(0, impulse) and
  539. /// ParticleApplyLinearImpulse(1, impulse) will impart twice as much
  540. /// velocity as calling just ApplyLinearImpulse(0, 1, impulse).
  541. /// @param firstIndex the first particle to be modified.
  542. /// @param lastIndex the last particle to be modified.
  543. /// @param impulse the world impulse vector, usually in N-seconds or
  544. /// kg-m/s.
  545. void ApplyLinearImpulse(int32 firstIndex, int32 lastIndex,
  546. const b2Vec2& impulse);
  547. /// Apply a force to the center of a particle.
  548. /// @param index the particle that will be modified.
  549. /// @param force the world force vector, usually in Newtons (N).
  550. void ParticleApplyForce(int32 index, const b2Vec2& force);
  551. /// Distribute a force across several particles. The particles must not be
  552. /// wall particles. Note that the force is distributed across all the
  553. /// particles, so calling this function for indices 0..N is not the same as
  554. /// calling ParticleApplyForce(i, force) for i in 0..N.
  555. /// @param firstIndex the first particle to be modified.
  556. /// @param lastIndex the last particle to be modified.
  557. /// @param force the world force vector, usually in Newtons (N).
  558. void ApplyForce(int32 firstIndex, int32 lastIndex, const b2Vec2& force);
  559. /// Get the next particle-system in the world's particle-system list.
  560. b2ParticleSystem* GetNext();
  561. const b2ParticleSystem* GetNext() const;
  562. /// Query the particle system for all particles that potentially overlap
  563. /// the provided AABB. b2QueryCallback::ShouldQueryParticleSystem is
  564. /// ignored.
  565. /// @param callback a user implemented callback class.
  566. /// @param aabb the query box.
  567. void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb) const;
  568. /// Query the particle system for all particles that potentially overlap
  569. /// the provided shape's AABB. Calls QueryAABB internally.
  570. /// b2QueryCallback::ShouldQueryParticleSystem is ignored.
  571. /// @param callback a user implemented callback class.
  572. /// @param shape the query shape
  573. /// @param xf the transform of the AABB
  574. void QueryShapeAABB(b2QueryCallback* callback, const b2Shape& shape,
  575. const b2Transform& xf) const;
  576. /// Ray-cast the particle system for all particles in the path of the ray.
  577. /// Your callback controls whether you get the closest point, any point, or
  578. /// n-points. The ray-cast ignores particles that contain the starting
  579. /// point. b2RayCastCallback::ShouldQueryParticleSystem is ignored.
  580. /// @param callback a user implemented callback class.
  581. /// @param point1 the ray starting point
  582. /// @param point2 the ray ending point
  583. void RayCast(b2RayCastCallback* callback, const b2Vec2& point1,
  584. const b2Vec2& point2) const;
  585. /// Compute the axis-aligned bounding box for all particles contained
  586. /// within this particle system.
  587. /// @param aabb Returns the axis-aligned bounding box of the system.
  588. void ComputeAABB(b2AABB* const aabb) const;
  589. #if LIQUIDFUN_EXTERNAL_LANGUAGE_API
  590. public:
  591. enum b2ExceptionType
  592. {
  593. b2_bufferTooSmall,
  594. b2_particleIndexOutOfBounds,
  595. b2_numErrors,
  596. b2_noExceptions,
  597. };
  598. /// Set the velocity of particle at index with direct floats.
  599. void SetParticleVelocity(int32 index, float32 vx, float32 vy);
  600. /// Get the x-coordinate of particle at index.
  601. float GetParticlePositionX(int32 index) const;
  602. /// Get the y-coordinate of particle at index.
  603. float GetParticlePositionY(int32 index) const;
  604. /// Copy position buffer into a specified buffer, starting from startIndex.
  605. int CopyPositionBuffer(int startIndex, int numParticles, void* outBuf,
  606. int size) const;
  607. /// Copy color buffer into a specified buffer, starting from startIndex.
  608. int CopyColorBuffer(int startIndex, int numParticles, void* outBuf,
  609. int size) const;
  610. /// Copy color buffer into a specified buffer, starting from startIndex.
  611. int CopyWeightBuffer(int startIndex, int numParticles, void* outBuf,
  612. int size) const;
  613. private:
  614. /// Helper function for buffer copies.
  615. int CopyBuffer(int startIndex, int numParticles, void* inBufWithOffset,
  616. void* outBuf, int outBufSize, int copySize) const;
  617. /// Check if buffer copy is valid for the Get*Buffer functions that have
  618. /// a user-supplied output buffer.
  619. b2ExceptionType IsBufCopyValid(int startIndex, int numParticles,
  620. int copySize, int bufSize) const;
  621. #endif // LIQUIDFUN_EXTERNAL_LANGUAGE_API
  622. private:
  623. friend class b2World;
  624. friend class b2ParticleGroup;
  625. friend class b2ParticleBodyContactRemovePredicate;
  626. friend class b2FixtureParticleQueryCallback;
  627. #ifdef LIQUIDFUN_UNIT_TESTS
  628. FRIEND_TEST(FunctionTests, GetParticleMass);
  629. FRIEND_TEST(FunctionTests, AreProxyBuffersTheSame);
  630. #endif // LIQUIDFUN_UNIT_TESTS
  631. template <typename T>
  632. struct UserOverridableBuffer
  633. {
  634. UserOverridableBuffer()
  635. {
  636. data = NULL;
  637. userSuppliedCapacity = 0;
  638. }
  639. T* data;
  640. int32 userSuppliedCapacity;
  641. };
  642. /// Used for detecting particle contacts
  643. struct Proxy
  644. {
  645. int32 index;
  646. uint32 tag;
  647. friend inline bool operator<(const Proxy &a, const Proxy &b)
  648. {
  649. return a.tag < b.tag;
  650. }
  651. friend inline bool operator<(uint32 a, const Proxy &b)
  652. {
  653. return a < b.tag;
  654. }
  655. friend inline bool operator<(const Proxy &a, uint32 b)
  656. {
  657. return a.tag < b;
  658. }
  659. };
  660. /// Class for filtering pairs or triads.
  661. class ConnectionFilter
  662. {
  663. public:
  664. virtual ~ConnectionFilter() {}
  665. /// Is the particle necessary for connection?
  666. /// A pair or a triad should contain at least one 'necessary' particle.
  667. virtual bool IsNecessary(int32 index) const
  668. {
  669. B2_NOT_USED(index);
  670. return true;
  671. }
  672. /// An additional condition for creating a pair.
  673. virtual bool ShouldCreatePair(int32 a, int32 b) const
  674. {
  675. B2_NOT_USED(a);
  676. B2_NOT_USED(b);
  677. return true;
  678. }
  679. /// An additional condition for creating a triad.
  680. virtual bool ShouldCreateTriad(int32 a, int32 b, int32 c) const
  681. {
  682. B2_NOT_USED(a);
  683. B2_NOT_USED(b);
  684. B2_NOT_USED(c);
  685. return true;
  686. }
  687. };
  688. /// InsideBoundsEnumerator enumerates all particles inside the given bounds.
  689. class InsideBoundsEnumerator
  690. {
  691. public:
  692. /// Construct an enumerator with bounds of tags and a range of proxies.
  693. InsideBoundsEnumerator(
  694. uint32 lower, uint32 upper,
  695. const Proxy* first, const Proxy* last);
  696. /// Get index of the next particle. Returns b2_invalidParticleIndex if
  697. /// there are no more particles.
  698. int32 GetNext();
  699. private:
  700. /// The lower and upper bound of x component in the tag.
  701. uint32 m_xLower, m_xUpper;
  702. /// The lower and upper bound of y component in the tag.
  703. uint32 m_yLower, m_yUpper;
  704. /// The range of proxies.
  705. const Proxy* m_first;
  706. const Proxy* m_last;
  707. };
  708. /// Node of linked lists of connected particles
  709. struct ParticleListNode
  710. {
  711. /// The head of the list.
  712. ParticleListNode* list;
  713. /// The next node in the list.
  714. ParticleListNode* next;
  715. /// Number of entries in the list. Valid only for the node at the head
  716. /// of the list.
  717. int32 count;
  718. /// Particle index.
  719. int32 index;
  720. };
  721. /// All particle types that require creating pairs
  722. static const int32 k_pairFlags =
  723. b2_springParticle |
  724. b2_barrierParticle;
  725. /// All particle types that require creating triads
  726. static const int32 k_triadFlags =
  727. b2_elasticParticle;
  728. /// All particle types that do not produce dynamic pressure
  729. static const int32 k_noPressureFlags =
  730. b2_powderParticle |
  731. b2_tensileParticle;
  732. /// All particle types that apply extra damping force with bodies
  733. static const int32 k_extraDampingFlags =
  734. b2_staticPressureParticle;
  735. b2ParticleSystem(const b2ParticleSystemDef* def, b2World* world);
  736. ~b2ParticleSystem();
  737. template <typename T> void FreeBuffer(T** b, int capacity);
  738. template <typename T> void FreeUserOverridableBuffer(
  739. UserOverridableBuffer<T>* b);
  740. template <typename T> T* ReallocateBuffer(T* buffer, int32 oldCapacity,
  741. int32 newCapacity);
  742. template <typename T> T* ReallocateBuffer(
  743. T* buffer, int32 userSuppliedCapacity, int32 oldCapacity,
  744. int32 newCapacity, bool deferred);
  745. template <typename T> T* ReallocateBuffer(
  746. UserOverridableBuffer<T>* buffer, int32 oldCapacity, int32 newCapacity,
  747. bool deferred);
  748. template <typename T> T* RequestBuffer(T* buffer);
  749. /// Reallocate the handle / index map and schedule the allocation of a new
  750. /// pool for handle allocation.
  751. void ReallocateHandleBuffers(int32 newCapacity);
  752. void ReallocateInternalAllocatedBuffers(int32 capacity);
  753. int32 CreateParticleForGroup(
  754. const b2ParticleGroupDef& groupDef,
  755. const b2Transform& xf, const b2Vec2& position);
  756. void CreateParticlesStrokeShapeForGroup(
  757. const b2Shape* shape,
  758. const b2ParticleGroupDef& groupDef, const b2Transform& xf);
  759. void CreateParticlesFillShapeForGroup(
  760. const b2Shape* shape,
  761. const b2ParticleGroupDef& groupDef, const b2Transform& xf);
  762. void CreateParticlesWithShapeForGroup(
  763. const b2Shape* shape,
  764. const b2ParticleGroupDef& groupDef, const b2Transform& xf);
  765. void CreateParticlesWithShapesForGroup(
  766. const b2Shape* const* shapes, int32 shapeCount,
  767. const b2ParticleGroupDef& groupDef, const b2Transform& xf);
  768. int32 CloneParticle(int32 index, b2ParticleGroup* group);
  769. void DestroyParticleGroup(b2ParticleGroup* group);
  770. void UpdatePairsAndTriads(
  771. int32 firstIndex, int32 lastIndex, const ConnectionFilter& filter);
  772. void UpdatePairsAndTriadsWithReactiveParticles();
  773. static bool ComparePairIndices(const b2ParticlePair& a, const b2ParticlePair& b);
  774. static bool MatchPairIndices(const b2ParticlePair& a, const b2ParticlePair& b);
  775. static bool CompareTriadIndices(const b2ParticleTriad& a, const b2ParticleTriad& b);
  776. static bool MatchTriadIndices(const b2ParticleTriad& a, const b2ParticleTriad& b);
  777. static void InitializeParticleLists(
  778. const b2ParticleGroup* group, ParticleListNode* nodeBuffer);
  779. void MergeParticleListsInContact(
  780. const b2ParticleGroup* group, ParticleListNode* nodeBuffer) const;
  781. static void MergeParticleLists(
  782. ParticleListNode* listA, ParticleListNode* listB);
  783. static ParticleListNode* FindLongestParticleList(
  784. const b2ParticleGroup* group, ParticleListNode* nodeBuffer);
  785. void MergeZombieParticleListNodes(
  786. const b2ParticleGroup* group, ParticleListNode* nodeBuffer,
  787. ParticleListNode* survivingList) const;
  788. static void MergeParticleListAndNode(
  789. ParticleListNode* list, ParticleListNode* node);
  790. void CreateParticleGroupsFromParticleList(
  791. const b2ParticleGroup* group, ParticleListNode* nodeBuffer,
  792. const ParticleListNode* survivingList);
  793. void UpdatePairsAndTriadsWithParticleList(
  794. const b2ParticleGroup* group, const ParticleListNode* nodeBuffer);
  795. void ComputeDepth();
  796. InsideBoundsEnumerator GetInsideBoundsEnumerator(const b2AABB& aabb) const;
  797. void UpdateAllParticleFlags();
  798. void UpdateAllGroupFlags();
  799. void AddContact(int32 a, int32 b,
  800. b2GrowableBuffer<b2ParticleContact>& contacts) const;
  801. void FindContacts_Reference(
  802. b2GrowableBuffer<b2ParticleContact>& contacts) const;
  803. void ReorderForFindContact(FindContactInput* reordered,
  804. int alignedCount) const;
  805. void GatherChecksOneParticle(
  806. const uint32 bound,
  807. const int startIndex,
  808. const int particleIndex,
  809. int* nextUncheckedIndex,
  810. b2GrowableBuffer<FindContactCheck>& checks) const;
  811. void GatherChecks(b2GrowableBuffer<FindContactCheck>& checks) const;
  812. void FindContacts_Simd(
  813. b2GrowableBuffer<b2ParticleContact>& contacts) const;
  814. void FindContacts(
  815. b2GrowableBuffer<b2ParticleContact>& contacts) const;
  816. static void UpdateProxyTags(
  817. const uint32* const tags,
  818. b2GrowableBuffer<Proxy>& proxies);
  819. static bool ProxyBufferHasIndex(
  820. int32 index, const Proxy* const a, int count);
  821. static int NumProxiesWithSameTag(
  822. const Proxy* const a, const Proxy* const b, int count);
  823. static bool AreProxyBuffersTheSame(const b2GrowableBuffer<Proxy>& a,
  824. const b2GrowableBuffer<Proxy>& b);
  825. void UpdateProxies_Reference(b2GrowableBuffer<Proxy>& proxies) const;
  826. void UpdateProxies_Simd(b2GrowableBuffer<Proxy>& proxies) const;
  827. void UpdateProxies(b2GrowableBuffer<Proxy>& proxies) const;
  828. void SortProxies(b2GrowableBuffer<Proxy>& proxies) const;
  829. void FilterContacts(b2GrowableBuffer<b2ParticleContact>& contacts);
  830. void NotifyContactListenerPreContact(
  831. b2ParticlePairSet* particlePairs) const;
  832. void NotifyContactListenerPostContact(b2ParticlePairSet& particlePairs);
  833. void UpdateContacts(bool exceptZombie);
  834. void NotifyBodyContactListenerPreContact(
  835. FixtureParticleSet* fixtureSet) const;
  836. void NotifyBodyContactListenerPostContact(FixtureParticleSet& fixtureSet);
  837. void UpdateBodyContacts();
  838. void Solve(const b2TimeStep& step);
  839. void SolveCollision(const b2TimeStep& step);
  840. void LimitVelocity(const b2TimeStep& step);
  841. void SolveGravity(const b2TimeStep& step);
  842. void SolveBarrier(const b2TimeStep& step);
  843. void SolveStaticPressure(const b2TimeStep& step);
  844. void ComputeWeight();
  845. void SolvePressure(const b2TimeStep& step);
  846. void SolveDamping(const b2TimeStep& step);
  847. void SolveRigidDamping();
  848. void SolveExtraDamping();
  849. void SolveWall();
  850. void SolveRigid(const b2TimeStep& step);
  851. void SolveElastic(const b2TimeStep& step);
  852. void SolveSpring(const b2TimeStep& step);
  853. void SolveTensile(const b2TimeStep& step);
  854. void SolveViscous();
  855. void SolveRepulsive(const b2TimeStep& step);
  856. void SolvePowder(const b2TimeStep& step);
  857. void SolveSolid(const b2TimeStep& step);
  858. void SolveForce(const b2TimeStep& step);
  859. void SolveColorMixing();
  860. void SolveZombie();
  861. /// Destroy all particles which have outlived their lifetimes set by
  862. /// SetParticleLifetime().
  863. void SolveLifetimes(const b2TimeStep& step);
  864. void RotateBuffer(int32 start, int32 mid, int32 end);
  865. float32 GetCriticalVelocity(const b2TimeStep& step) const;
  866. float32 GetCriticalVelocitySquared(const b2TimeStep& step) const;
  867. float32 GetCriticalPressure(const b2TimeStep& step) const;
  868. float32 GetParticleStride() const;
  869. float32 GetParticleMass() const;
  870. float32 GetParticleInvMass() const;
  871. // Get the world's contact filter if any particles with the
  872. // b2_contactFilterParticle flag are present in the system.
  873. b2ContactFilter* GetFixtureContactFilter() const;
  874. // Get the world's contact filter if any particles with the
  875. // b2_particleContactFilterParticle flag are present in the system.
  876. b2ContactFilter* GetParticleContactFilter() const;
  877. // Get the world's contact listener if any particles with the
  878. // b2_fixtureContactListenerParticle flag are present in the system.
  879. b2ContactListener* GetFixtureContactListener() const;
  880. // Get the world's contact listener if any particles with the
  881. // b2_particleContactListenerParticle flag are present in the system.
  882. b2ContactListener* GetParticleContactListener() const;
  883. template <typename T> void SetUserOverridableBuffer(
  884. UserOverridableBuffer<T>* buffer, T* newBufferData, int32 newCapacity);
  885. void SetGroupFlags(b2ParticleGroup* group, uint32 flags);
  886. void RemoveSpuriousBodyContacts();
  887. static bool BodyContactCompare(const b2ParticleBodyContact& lhs,
  888. const b2ParticleBodyContact& rhs);
  889. void DetectStuckParticle(int32 particle);
  890. /// Determine whether a particle index is valid.
  891. bool ValidateParticleIndex(const int32 index) const;
  892. /// Get the time elapsed in b2ParticleSystemDef::lifetimeGranularity.
  893. int32 GetQuantizedTimeElapsed() const;
  894. /// Convert a lifetime in seconds to an expiration time.
  895. int64 LifetimeToExpirationTime(const float32 lifetime) const;
  896. bool ForceCanBeApplied(uint32 flags) const;
  897. void PrepareForceBuffer();
  898. bool IsRigidGroup(b2ParticleGroup *group) const;
  899. b2Vec2 GetLinearVelocity(
  900. b2ParticleGroup *group, int32 particleIndex,
  901. const b2Vec2 &point) const;
  902. void InitDampingParameter(
  903. float32* invMass, float32* invInertia, float32* tangentDistance,
  904. float32 mass, float32 inertia, const b2Vec2& center,
  905. const b2Vec2& point, const b2Vec2& normal) const;
  906. void InitDampingParameterWithRigidGroupOrParticle(
  907. float32* invMass, float32* invInertia, float32* tangentDistance,
  908. bool isRigidGroup, b2ParticleGroup* group, int32 particleIndex,
  909. const b2Vec2& point, const b2Vec2& normal) const;
  910. float32 ComputeDampingImpulse(
  911. float32 invMassA, float32 invInertiaA, float32 tangentDistanceA,
  912. float32 invMassB, float32 invInertiaB, float32 tangentDistanceB,
  913. float32 normalVelocity) const;
  914. void ApplyDamping(
  915. float32 invMass, float32 invInertia, float32 tangentDistance,
  916. bool isRigidGroup, b2ParticleGroup* group, int32 particleIndex,
  917. float32 impulse, const b2Vec2& normal);
  918. bool m_paused;
  919. int32 m_timestamp;
  920. int32 m_allParticleFlags;
  921. bool m_needsUpdateAllParticleFlags;
  922. int32 m_allGroupFlags;
  923. bool m_needsUpdateAllGroupFlags;
  924. bool m_hasForce;
  925. int32 m_iterationIndex;
  926. float32 m_inverseDensity;
  927. float32 m_particleDiameter;
  928. float32 m_inverseDiameter;
  929. float32 m_squaredDiameter;
  930. int32 m_count;
  931. int32 m_internalAllocatedCapacity;
  932. /// Allocator for b2ParticleHandle instances.
  933. b2SlabAllocator<b2ParticleHandle> m_handleAllocator;
  934. /// Maps particle indicies to handles.
  935. UserOverridableBuffer<b2ParticleHandle*> m_handleIndexBuffer;
  936. UserOverridableBuffer<uint32> m_flagsBuffer;
  937. UserOverridableBuffer<b2Vec2> m_positionBuffer;
  938. UserOverridableBuffer<b2Vec2> m_velocityBuffer;
  939. b2Vec2* m_forceBuffer;
  940. /// m_weightBuffer is populated in ComputeWeight and used in
  941. /// ComputeDepth(), SolveStaticPressure() and SolvePressure().
  942. float32* m_weightBuffer;
  943. /// When any particles have the flag b2_staticPressureParticle,
  944. /// m_staticPressureBuffer is first allocated and used in
  945. /// SolveStaticPressure() and SolvePressure(). It will be reallocated on
  946. /// subsequent CreateParticle() calls.
  947. float32* m_staticPressureBuffer;
  948. /// m_accumulationBuffer is used in many functions as a temporary buffer
  949. /// for scalar values.
  950. float32* m_accumulationBuffer;
  951. /// When any particles have the flag b2_tensileParticle,
  952. /// m_accumulation2Buffer is first allocated and used in SolveTensile()
  953. /// as a temporary buffer for vector values. It will be reallocated on
  954. /// subsequent CreateParticle() calls.
  955. b2Vec2* m_accumulation2Buffer;
  956. /// When any particle groups have the flag b2_solidParticleGroup,
  957. /// m_depthBuffer is first allocated and populated in ComputeDepth() and
  958. /// used in SolveSolid(). It will be reallocated on subsequent
  959. /// CreateParticle() calls.
  960. float32* m_depthBuffer;
  961. UserOverridableBuffer<b2ParticleColor> m_colorBuffer;
  962. b2ParticleGroup** m_groupBuffer;
  963. UserOverridableBuffer<void*> m_userDataBuffer;
  964. /// Stuck particle detection parameters and record keeping
  965. int32 m_stuckThreshold;
  966. UserOverridableBuffer<int32> m_lastBodyContactStepBuffer;
  967. UserOverridableBuffer<int32> m_bodyContactCountBuffer;
  968. UserOverridableBuffer<int32> m_consecutiveContactStepsBuffer;
  969. b2GrowableBuffer<int32> m_stuckParticleBuffer;
  970. b2GrowableBuffer<Proxy> m_proxyBuffer;
  971. b2GrowableBuffer<b2ParticleContact> m_contactBuffer;
  972. b2GrowableBuffer<b2ParticleBodyContact> m_bodyContactBuffer;
  973. b2GrowableBuffer<b2ParticlePair> m_pairBuffer;
  974. b2GrowableBuffer<b2ParticleTriad> m_triadBuffer;
  975. /// Time each particle should be destroyed relative to the last time
  976. /// m_timeElapsed was initialized. Each unit of time corresponds to
  977. /// b2ParticleSystemDef::lifetimeGranularity seconds.
  978. UserOverridableBuffer<int32> m_expirationTimeBuffer;
  979. /// List of particle indices sorted by expiration time.
  980. UserOverridableBuffer<int32> m_indexByExpirationTimeBuffer;
  981. /// Time elapsed in 32:32 fixed point. Each non-fractional unit of time
  982. /// corresponds to b2ParticleSystemDef::lifetimeGranularity seconds.
  983. int64 m_timeElapsed;
  984. /// Whether the expiration time buffer has been modified and needs to be
  985. /// resorted.
  986. bool m_expirationTimeBufferRequiresSorting;
  987. int32 m_groupCount;
  988. b2ParticleGroup* m_groupList;
  989. b2ParticleSystemDef m_def;
  990. b2World* m_world;
  991. b2ParticleSystem* m_prev;
  992. b2ParticleSystem* m_next;
  993. };
  994. inline void b2ParticleContact::SetIndices(int32 a, int32 b)
  995. {
  996. b2Assert(a <= b2_maxParticleIndex && b <= b2_maxParticleIndex);
  997. indexA = (b2ParticleIndex)a;
  998. indexB = (b2ParticleIndex)b;
  999. }
  1000. inline bool b2ParticleContact::operator==(
  1001. const b2ParticleContact& rhs) const
  1002. {
  1003. return indexA == rhs.indexA
  1004. && indexB == rhs.indexB
  1005. && flags == rhs.flags
  1006. && weight == rhs.weight
  1007. && normal == rhs.normal;
  1008. }
  1009. // The reciprocal sqrt function differs between SIMD and non-SIMD, but they
  1010. // should create approximately equal results.
  1011. inline bool b2ParticleContact::ApproximatelyEqual(
  1012. const b2ParticleContact& rhs) const
  1013. {
  1014. static const float MAX_WEIGHT_DIFF = 0.01f; // Weight 0 ~ 1, so about 1%
  1015. static const float MAX_NORMAL_DIFF = 0.01f; // Normal length = 1, so 1%
  1016. return indexA == rhs.indexA
  1017. && indexB == rhs.indexB
  1018. && flags == rhs.flags
  1019. && b2Abs(weight - rhs.weight) < MAX_WEIGHT_DIFF
  1020. && (normal - rhs.normal).Length() < MAX_NORMAL_DIFF;
  1021. }
  1022. inline b2ParticleGroup* b2ParticleSystem::GetParticleGroupList()
  1023. {
  1024. return m_groupList;
  1025. }
  1026. inline const b2ParticleGroup* b2ParticleSystem::GetParticleGroupList() const
  1027. {
  1028. return m_groupList;
  1029. }
  1030. inline int32 b2ParticleSystem::GetParticleGroupCount() const
  1031. {
  1032. return m_groupCount;
  1033. }
  1034. inline int32 b2ParticleSystem::GetParticleCount() const
  1035. {
  1036. return m_count;
  1037. }
  1038. inline void b2ParticleSystem::SetPaused(bool paused)
  1039. {
  1040. m_paused = paused;
  1041. }
  1042. inline bool b2ParticleSystem::GetPaused() const
  1043. {
  1044. return m_paused;
  1045. }
  1046. inline const b2ParticleContact* b2ParticleSystem::GetContacts() const
  1047. {
  1048. return m_contactBuffer.Data();
  1049. }
  1050. inline int32 b2ParticleSystem::GetContactCount() const
  1051. {
  1052. return m_contactBuffer.GetCount();
  1053. }
  1054. inline const b2ParticleBodyContact* b2ParticleSystem::GetBodyContacts() const
  1055. {
  1056. return m_bodyContactBuffer.Data();
  1057. }
  1058. inline int32 b2ParticleSystem::GetBodyContactCount() const
  1059. {
  1060. return m_bodyContactBuffer.GetCount();
  1061. }
  1062. inline const b2ParticlePair* b2ParticleSystem::GetPairs() const
  1063. {
  1064. return m_pairBuffer.Data();
  1065. }
  1066. inline int32 b2ParticleSystem::GetPairCount() const
  1067. {
  1068. return m_pairBuffer.GetCount();
  1069. }
  1070. inline const b2ParticleTriad* b2ParticleSystem::GetTriads() const
  1071. {
  1072. return m_triadBuffer.Data();
  1073. }
  1074. inline int32 b2ParticleSystem::GetTriadCount() const
  1075. {
  1076. return m_triadBuffer.GetCount();
  1077. }
  1078. inline b2ParticleSystem* b2ParticleSystem::GetNext()
  1079. {
  1080. return m_next;
  1081. }
  1082. inline const b2ParticleSystem* b2ParticleSystem::GetNext() const
  1083. {
  1084. return m_next;
  1085. }
  1086. inline const int32* b2ParticleSystem::GetStuckCandidates() const
  1087. {
  1088. return m_stuckParticleBuffer.Data();
  1089. }
  1090. inline int32 b2ParticleSystem::GetStuckCandidateCount() const
  1091. {
  1092. return m_stuckParticleBuffer.GetCount();
  1093. }
  1094. inline void b2ParticleSystem::SetStrictContactCheck(bool enabled)
  1095. {
  1096. m_def.strictContactCheck = enabled;
  1097. }
  1098. inline bool b2ParticleSystem::GetStrictContactCheck() const
  1099. {
  1100. return m_def.strictContactCheck;
  1101. }
  1102. inline void b2ParticleSystem::SetRadius(float32 radius)
  1103. {
  1104. m_particleDiameter = 2 * radius;
  1105. m_squaredDiameter = m_particleDiameter * m_particleDiameter;
  1106. m_inverseDiameter = 1 / m_particleDiameter;
  1107. }
  1108. inline void b2ParticleSystem::SetDensity(float32 density)
  1109. {
  1110. m_def.density = density;
  1111. m_inverseDensity = 1 / m_def.density;
  1112. }
  1113. inline float32 b2ParticleSystem::GetDensity() const
  1114. {
  1115. return m_def.density;
  1116. }
  1117. inline void b2ParticleSystem::SetGravityScale(float32 gravityScale)
  1118. {
  1119. m_def.gravityScale = gravityScale;
  1120. }
  1121. inline float32 b2ParticleSystem::GetGravityScale() const
  1122. {
  1123. return m_def.gravityScale;
  1124. }
  1125. inline void b2ParticleSystem::SetDamping(float32 damping)
  1126. {
  1127. m_def.dampingStrength = damping;
  1128. }
  1129. inline float32 b2ParticleSystem::GetDamping() const
  1130. {
  1131. return m_def.dampingStrength;
  1132. }
  1133. inline void b2ParticleSystem::SetStaticPressureIterations(int32 iterations)
  1134. {
  1135. m_def.staticPressureIterations = iterations;
  1136. }
  1137. inline int32 b2ParticleSystem::GetStaticPressureIterations() const
  1138. {
  1139. return m_def.staticPressureIterations;
  1140. }
  1141. inline float32 b2ParticleSystem::GetRadius() const
  1142. {
  1143. return m_particleDiameter / 2;
  1144. }
  1145. inline float32 b2ParticleSystem::GetCriticalVelocity(const b2TimeStep& step) const
  1146. {
  1147. return m_particleDiameter * step.inv_dt;
  1148. }
  1149. inline float32 b2ParticleSystem::GetCriticalVelocitySquared(
  1150. const b2TimeStep& step) const
  1151. {
  1152. float32 velocity = GetCriticalVelocity(step);
  1153. return velocity * velocity;
  1154. }
  1155. inline float32 b2ParticleSystem::GetCriticalPressure(const b2TimeStep& step) const
  1156. {
  1157. return m_def.density * GetCriticalVelocitySquared(step);
  1158. }
  1159. inline float32 b2ParticleSystem::GetParticleStride() const
  1160. {
  1161. return b2_particleStride * m_particleDiameter;
  1162. }
  1163. inline float32 b2ParticleSystem::GetParticleMass() const
  1164. {
  1165. float32 stride = GetParticleStride();
  1166. return m_def.density * stride * stride;
  1167. }
  1168. inline float32 b2ParticleSystem::GetParticleInvMass() const
  1169. {
  1170. // mass = density * stride^2, so we take the inverse of this.
  1171. float32 inverseStride = m_inverseDiameter * (1.0f / b2_particleStride);
  1172. return m_inverseDensity * inverseStride * inverseStride;
  1173. }
  1174. inline b2Vec2* b2ParticleSystem::GetPositionBuffer()
  1175. {
  1176. return m_positionBuffer.data;
  1177. }
  1178. inline b2Vec2* b2ParticleSystem::GetVelocityBuffer()
  1179. {
  1180. return m_velocityBuffer.data;
  1181. }
  1182. inline float32* b2ParticleSystem::GetWeightBuffer()
  1183. {
  1184. return m_weightBuffer;
  1185. }
  1186. inline int32 b2ParticleSystem::GetMaxParticleCount() const
  1187. {
  1188. return m_def.maxCount;
  1189. }
  1190. inline void b2ParticleSystem::SetMaxParticleCount(int32 count)
  1191. {
  1192. b2Assert(m_count <= count);
  1193. m_def.maxCount = count;
  1194. }
  1195. inline uint32 b2ParticleSystem::GetAllParticleFlags() const
  1196. {
  1197. return m_allParticleFlags;
  1198. }
  1199. inline uint32 b2ParticleSystem::GetAllGroupFlags() const
  1200. {
  1201. return m_allGroupFlags;
  1202. }
  1203. inline const uint32* b2ParticleSystem::GetFlagsBuffer() const
  1204. {
  1205. return m_flagsBuffer.data;
  1206. }
  1207. inline const b2Vec2* b2ParticleSystem::GetPositionBuffer() const
  1208. {
  1209. return m_positionBuffer.data;
  1210. }
  1211. inline const b2Vec2* b2ParticleSystem::GetVelocityBuffer() const
  1212. {
  1213. return m_velocityBuffer.data;
  1214. }
  1215. inline const b2ParticleColor* b2ParticleSystem::GetColorBuffer() const
  1216. {
  1217. return ((b2ParticleSystem*) this)->GetColorBuffer();
  1218. }
  1219. inline const b2ParticleGroup* const* b2ParticleSystem::GetGroupBuffer() const
  1220. {
  1221. return m_groupBuffer;
  1222. }
  1223. inline const float32* b2ParticleSystem::GetWeightBuffer() const
  1224. {
  1225. return m_weightBuffer;
  1226. }
  1227. inline void* const* b2ParticleSystem::GetUserDataBuffer() const
  1228. {
  1229. return ((b2ParticleSystem*) this)->GetUserDataBuffer();
  1230. }
  1231. inline b2ParticleGroup* const* b2ParticleSystem::GetGroupBuffer()
  1232. {
  1233. return m_groupBuffer;
  1234. }
  1235. inline uint32 b2ParticleSystem::GetParticleFlags(int32 index)
  1236. {
  1237. return GetFlagsBuffer()[index];
  1238. }
  1239. inline bool b2ParticleSystem::ValidateParticleIndex(const int32 index) const
  1240. {
  1241. return index >= 0 && index < GetParticleCount() &&
  1242. index != b2_invalidParticleIndex;
  1243. }
  1244. inline bool b2ParticleSystem::GetDestructionByAge() const
  1245. {
  1246. return m_def.destroyByAge;
  1247. }
  1248. inline void b2ParticleSystem::ParticleApplyLinearImpulse(int32 index,
  1249. const b2Vec2& impulse)
  1250. {
  1251. ApplyLinearImpulse(index, index + 1, impulse);
  1252. }
  1253. // Note: These functions must go in the header so the unit tests will compile
  1254. // them. b2ParticleSystem.cpp does not compile with this #define.
  1255. #if LIQUIDFUN_EXTERNAL_LANGUAGE_API
  1256. inline void b2ParticleSystem::SetParticleVelocity(int32 index,
  1257. float32 vx,
  1258. float32 vy)
  1259. {
  1260. b2Vec2& v = GetVelocityBuffer()[index];
  1261. v.x = vx;
  1262. v.y = vy;
  1263. }
  1264. inline float b2ParticleSystem::GetParticlePositionX(int32 index) const
  1265. {
  1266. return GetPositionBuffer()[index].x;
  1267. }
  1268. inline float b2ParticleSystem::GetParticlePositionY(int32 index) const
  1269. {
  1270. return GetPositionBuffer()[index].y;
  1271. }
  1272. inline int b2ParticleSystem::CopyPositionBuffer(int startIndex,
  1273. int numParticles,
  1274. void* outBuf,
  1275. int size) const
  1276. {
  1277. int copySize = numParticles * sizeof(b2Vec2);
  1278. void* inBufWithOffset = (void*) (GetPositionBuffer() + startIndex);
  1279. return CopyBuffer(startIndex, numParticles, inBufWithOffset, outBuf, size,
  1280. copySize);
  1281. }
  1282. inline int b2ParticleSystem::CopyColorBuffer(int startIndex,
  1283. int numParticles,
  1284. void* outBuf,
  1285. int size) const
  1286. {
  1287. int copySize = numParticles * sizeof(b2ParticleColor);
  1288. void* inBufWithOffset = (void*) (GetColorBuffer() + startIndex);
  1289. return CopyBuffer(startIndex, numParticles, inBufWithOffset, outBuf, size,
  1290. copySize);
  1291. }
  1292. inline int b2ParticleSystem::CopyWeightBuffer(int startIndex,
  1293. int numParticles,
  1294. void* outBuf,
  1295. int size) const
  1296. {
  1297. int copySize = numParticles * sizeof(float32);
  1298. void* inBufWithOffset = (void*) (GetWeightBuffer() + startIndex);
  1299. return CopyBuffer(startIndex, numParticles, inBufWithOffset, outBuf, size,
  1300. copySize);
  1301. }
  1302. inline int b2ParticleSystem::CopyBuffer(int startIndex, int numParticles,
  1303. void* inBufWithOffset, void* outBuf,
  1304. int outBufSize, int copySize) const
  1305. {
  1306. b2ExceptionType exception = IsBufCopyValid(startIndex, numParticles,
  1307. copySize, outBufSize);
  1308. if (exception != b2_noExceptions)
  1309. {
  1310. return exception;
  1311. }
  1312. memcpy(outBuf, inBufWithOffset, copySize);
  1313. return b2_noExceptions;
  1314. }
  1315. #endif // LIQUIDFUN_EXTERNAL_LANGUAGE_API
  1316. #endif