/* * Copyright (c) 2013 Google, Inc. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_PARTICLE #define B2_PARTICLE #include "b2_math.h" #include "b2_settings.h" #include "b2_intrusive_list.h" struct b2Color; class b2ParticleGroup; /// @file /// The particle type. Can be combined with the | operator. enum b2ParticleFlag { /// Water particle. b2_waterParticle = 0, /// Removed after next simulation step. b2_zombieParticle = 1 << 1, /// Zero velocity. b2_wallParticle = 1 << 2, /// With restitution from stretching. b2_springParticle = 1 << 3, /// With restitution from deformation. b2_elasticParticle = 1 << 4, /// With viscosity. b2_viscousParticle = 1 << 5, /// Without isotropic pressure. b2_powderParticle = 1 << 6, /// With surface tension. b2_tensileParticle = 1 << 7, /// Mix color between contacting particles. b2_colorMixingParticle = 1 << 8, /// Call b2DestructionListener on destruction. b2_destructionListenerParticle = 1 << 9, /// Prevents other particles from leaking. b2_barrierParticle = 1 << 10, /// Less compressibility. b2_staticPressureParticle = 1 << 11, /// Makes pairs or triads with other particles. b2_reactiveParticle = 1 << 12, /// With high repulsive force. b2_repulsiveParticle = 1 << 13, /// Call b2ContactListener when this particle is about to interact with /// a rigid body or stops interacting with a rigid body. /// This results in an expensive operation compared to using /// b2_fixtureContactFilterParticle to detect collisions between /// particles. b2_fixtureContactListenerParticle = 1 << 14, /// Call b2ContactListener when this particle is about to interact with /// another particle or stops interacting with another particle. /// This results in an expensive operation compared to using /// b2_particleContactFilterParticle to detect collisions between /// particles. b2_particleContactListenerParticle = 1 << 15, /// Call b2ContactFilter when this particle interacts with rigid bodies. b2_fixtureContactFilterParticle = 1 << 16, /// Call b2ContactFilter when this particle interacts with other /// particles. b2_particleContactFilterParticle = 1 << 17, }; /// Small color object for each particle class b2ParticleColor { public: b2ParticleColor() {} /// Constructor with four elements: r (red), g (green), b (blue), and a /// (opacity). /// Each element can be specified 0 to 255. b2Inline b2ParticleColor(uint8 r, uint8 g, uint8 b, uint8 a) { Set(r, g, b, a); } /// Constructor that initializes the above four elements with the value of /// the b2Color object. b2ParticleColor(const b2Color& color); /// True when all four color elements equal 0. When true, a particle color /// buffer isn't allocated by CreateParticle(). /// bool IsZero() const { return !r && !g && !b && !a; } /// Used internally to convert the value of b2Color. /// b2Color GetColor() const; /// Sets color for current object using the four elements described above. /// b2Inline void Set(uint8 r_, uint8 g_, uint8 b_, uint8 a_) { r = r_; g = g_; b = b_; a = a_; } /// Initializes the object with the value of the b2Color. /// void Set(const b2Color& color); /// Multiplies r, g, b, a members by s where s is a value between 0.0 /// and 1.0. b2ParticleColor& operator *= (float32 s) { Set((uint8)(r * s), (uint8)(g * s), (uint8)(b * s), (uint8)(a * s)); return *this; } /// Scales r, g, b, a members by s where s is a value between 0 and 255. b2ParticleColor& operator *= (uint8 s) { // 1..256 to maintain the complete dynamic range. const int32 scale = (int32)s + 1; Set((uint8)(((int32)r * scale) >> k_bitsPerComponent), (uint8)(((int32)g * scale) >> k_bitsPerComponent), (uint8)(((int32)b * scale) >> k_bitsPerComponent), (uint8)(((int32)a * scale) >> k_bitsPerComponent)); return *this; } /// Scales r, g, b, a members by s returning the modified b2ParticleColor. b2ParticleColor operator * (float32 s) const { return MultiplyByScalar(s); } /// Scales r, g, b, a members by s returning the modified b2ParticleColor. b2ParticleColor operator * (uint8 s) const { return MultiplyByScalar(s); } /// Add two colors. This is a non-saturating addition so values /// overflows will wrap. b2Inline b2ParticleColor& operator += (const b2ParticleColor &color) { r += color.r; g += color.g; b += color.b; a += color.a; return *this; } /// Add two colors. This is a non-saturating addition so values /// overflows will wrap. b2ParticleColor operator + (const b2ParticleColor &color) const { b2ParticleColor newColor(*this); newColor += color; return newColor; } /// Subtract a color from this color. This is a subtraction without /// saturation so underflows will wrap. b2Inline b2ParticleColor& operator -= (const b2ParticleColor &color) { r -= color.r; g -= color.g; b -= color.b; a -= color.a; return *this; } /// Subtract a color from this color returning the result. This is a /// subtraction without saturation so underflows will wrap. b2ParticleColor operator - (const b2ParticleColor &color) const { b2ParticleColor newColor(*this); newColor -= color; return newColor; } /// Compare this color with the specified color. bool operator == (const b2ParticleColor &color) const { return r == color.r && g == color.g && b == color.b && a == color.a; } /// Mix mixColor with this color using strength to control how much of /// mixColor is mixed with this color and vice versa. The range of /// strength is 0..128 where 0 results in no color mixing and 128 results /// in an equal mix of both colors. strength 0..128 is analogous to an /// alpha channel value between 0.0f..0.5f. b2Inline void Mix(b2ParticleColor * const mixColor, const int32 strength) { MixColors(this, mixColor, strength); } /// Mix colorA with colorB using strength to control how much of /// colorA is mixed with colorB and vice versa. The range of /// strength is 0..128 where 0 results in no color mixing and 128 results /// in an equal mix of both colors. strength 0..128 is analogous to an /// alpha channel value between 0.0f..0.5f. static b2Inline void MixColors(b2ParticleColor * const colorA, b2ParticleColor * const colorB, const int32 strength) { const uint8 dr = (uint8)((strength * (colorB->r - colorA->r)) >> k_bitsPerComponent); const uint8 dg = (uint8)((strength * (colorB->g - colorA->g)) >> k_bitsPerComponent); const uint8 db = (uint8)((strength * (colorB->b - colorA->b)) >> k_bitsPerComponent); const uint8 da = (uint8)((strength * (colorB->a - colorA->a)) >> k_bitsPerComponent); colorA->r += dr; colorA->g += dg; colorA->b += db; colorA->a += da; colorB->r -= dr; colorB->g -= dg; colorB->b -= db; colorB->a -= da; } private: /// Generalization of the multiply operator using a scalar in-place /// multiplication. template b2ParticleColor MultiplyByScalar(T s) const { b2ParticleColor color(*this); color *= s; return color; } public: uint8 r, g, b, a; protected: /// Maximum value of a b2ParticleColor component. static const float32 k_maxValue; /// 1.0 / k_maxValue. static const float32 k_inverseMaxValue; /// Number of bits used to store each b2ParticleColor component. static const uint8 k_bitsPerComponent; }; extern b2ParticleColor b2ParticleColor_zero; /// A particle definition holds all the data needed to construct a particle. /// You can safely re-use these definitions. struct b2ParticleDef { b2ParticleDef() { flags = 0; position = b2Vec2_zero; velocity = b2Vec2_zero; color = b2ParticleColor_zero; lifetime = 0.0f; userData = NULL; group = NULL; } #if LIQUIDFUN_EXTERNAL_LANGUAGE_API /// Set position with direct floats void SetPosition(float32 x, float32 y); /// Set color with direct ints. void SetColor(int32 r, int32 g, int32 b, int32 a); #endif // LIQUIDFUN_EXTERNAL_LANGUAGE_API /// \brief Specifies the type of particle (see #b2ParticleFlag). /// /// A particle may be more than one type. /// Multiple types are chained by logical sums, for example: /// pd.flags = b2_elasticParticle | b2_viscousParticle uint32 flags; /// The world position of the particle. b2Vec2 position; /// The linear velocity of the particle in world co-ordinates. b2Vec2 velocity; /// The color of the particle. b2ParticleColor color; /// Lifetime of the particle in seconds. A value <= 0.0f indicates a /// particle with infinite lifetime. float32 lifetime; /// Use this to store application-specific body data. void* userData; /// An existing particle group to which the particle will be added. b2ParticleGroup* group; }; /// A helper function to calculate the optimal number of iterations. int32 b2CalculateParticleIterations( float32 gravity, float32 radius, float32 timeStep); /// Handle to a particle. Particle indices are ephemeral: the same index might /// refer to a different particle, from frame-to-frame. If you need to keep a /// reference to a particular particle across frames, you should acquire a /// b2ParticleHandle. Use #b2ParticleSystem::GetParticleHandleFromIndex() to /// retrieve the b2ParticleHandle of a particle from the particle system. class b2ParticleHandle : public b2TypedIntrusiveListNode { // Allow b2ParticleSystem to use SetIndex() to associate particle handles // with particle indices. friend class b2ParticleSystem; public: /// Initialize the index associated with the handle to an invalid index. b2ParticleHandle() : m_index(b2_invalidParticleIndex) { } /// Empty destructor. ~b2ParticleHandle() { } /// Get the index of the particle associated with this handle. int32 GetIndex() const { return m_index; } private: /// Set the index of the particle associated with this handle. void SetIndex(int32 index) { m_index = index; } private: // Index of the particle within the particle system. int32 m_index; }; #if LIQUIDFUN_EXTERNAL_LANGUAGE_API inline void b2ParticleDef::SetPosition(float32 x, float32 y) { position.Set(x, y); } inline void b2ParticleDef::SetColor(int32 r, int32 g, int32 b, int32 a) { color.Set((uint8)r, (uint8)g, (uint8)b, (uint8)a); } #endif // LIQUIDFUN_EXTERNAL_LANGUAGE_API #endif