| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | FXparticleSystem.cpp | ||
| 3 | |||
| 4 | Particle system with functions for particle generation, particle movement and particle rendering to RGB matrix. | ||
| 5 | by DedeHai (Damian Schneider) 2013-2024 | ||
| 6 | |||
| 7 | Copyright (c) 2024 Damian Schneider | ||
| 8 | Licensed under the EUPL v. 1.2 or later | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifdef WLED_DISABLE_2D | ||
| 12 | #define WLED_DISABLE_PARTICLESYSTEM2D | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #if !(defined(WLED_DISABLE_PARTICLESYSTEM2D) && defined(WLED_DISABLE_PARTICLESYSTEM1D)) // not both disabled | ||
| 16 | |||
| 17 | #include <stdint.h> | ||
| 18 | #include "wled.h" | ||
| 19 | |||
| 20 | #define PS_P_MAXSPEED 120 // maximum speed a particle can have (vx/vy is int8) | ||
| 21 | #define MAX_MEMIDLE 10 // max idle time (in frames) before memory is deallocated (if deallocated during an effect, it will crash!) | ||
| 22 | |||
| 23 | //#define WLED_DEBUG_PS // note: enabling debug uses ~3k of flash | ||
| 24 | |||
| 25 | #ifdef WLED_DEBUG_PS | ||
| 26 | #define PSPRINT(x) Serial.print(x) | ||
| 27 | #define PSPRINTLN(x) Serial.println(x) | ||
| 28 | #else | ||
| 29 | #define PSPRINT(x) | ||
| 30 | #define PSPRINTLN(x) | ||
| 31 | #endif | ||
| 32 | |||
| 33 | // limit speed of particles (used in 1D and 2D) | ||
| 34 | 53050 | static inline int32_t limitSpeed(const int32_t speed) { | |
| 35 |
2/2✓ Branch 0 taken 53046 times.
✓ Branch 1 taken 4 times.
|
53050 | return speed > PS_P_MAXSPEED ? PS_P_MAXSPEED : (speed < -PS_P_MAXSPEED ? -PS_P_MAXSPEED : speed); // note: this is slightly faster than using min/max at the cost of 50bytes of flash |
| 36 | } | ||
| 37 | #endif | ||
| 38 | |||
| 39 | #ifndef WLED_DISABLE_PARTICLESYSTEM2D | ||
| 40 | // memory allocation | ||
| 41 | #define ESP8266_MAXPARTICLES 256 // enough up to 16x16 pixels | ||
| 42 | #define ESP8266_MAXSOURCES 24 | ||
| 43 | #define ESP32S2_MAXPARTICLES 1024 // enough up to 32x32 pixels | ||
| 44 | #define ESP32S2_MAXSOURCES 64 | ||
| 45 | #define ESP32_MAXPARTICLES 2048 // enough up to 64x32 pixels | ||
| 46 | #define ESP32_MAXSOURCES 128 | ||
| 47 | |||
| 48 | // particle dimensions (subpixel division) | ||
| 49 | #define PS_P_RADIUS 64 // subpixel size, each pixel is divided by this for particle movement (must be a power of 2) | ||
| 50 | #define PS_P_HALFRADIUS (PS_P_RADIUS >> 1) | ||
| 51 | #define PS_P_RADIUS_SHIFT 6 // shift for RADIUS | ||
| 52 | #define PS_P_SURFACE 12 // shift: 2^PS_P_SURFACE = (PS_P_RADIUS)^2 | ||
| 53 | #define PS_P_MINHARDRADIUS 64 // minimum hard surface radius for collisions | ||
| 54 | #define PS_P_MINSURFACEHARDNESS 128 // minimum hardness used in collision impulse calculation, below this hardness, particles become sticky | ||
| 55 | |||
| 56 | // struct for PS settings (shared for 1D and 2D class) | ||
| 57 | typedef union { | ||
| 58 | struct{ // one byte bit field for 2D settings | ||
| 59 | bool wrapX : 1; | ||
| 60 | bool wrapY : 1; | ||
| 61 | bool bounceX : 1; | ||
| 62 | bool bounceY : 1; | ||
| 63 | bool killoutofbounds : 1; // if set, out of bound particles are killed immediately | ||
| 64 | bool useGravity : 1; // set to 1 if gravity is used, disables bounceY at the top | ||
| 65 | bool useCollisions : 1; | ||
| 66 | bool colorByAge : 1; // if set, particle hue is set by ttl value in render function | ||
| 67 | }; | ||
| 68 | byte asByte; // access as a byte, order is: LSB is first entry in the list above | ||
| 69 | } PSsettings2D; | ||
| 70 | |||
| 71 | //struct for a single particle | ||
| 72 | typedef struct { // 10 bytes | ||
| 73 | int16_t x; // x position in particle system | ||
| 74 | int16_t y; // y position in particle system | ||
| 75 | uint16_t ttl; // time to live in frames | ||
| 76 | int8_t vx; // horizontal velocity | ||
| 77 | int8_t vy; // vertical velocity | ||
| 78 | uint8_t hue; // color hue | ||
| 79 | uint8_t sat; // particle color saturation | ||
| 80 | } PSparticle; | ||
| 81 | |||
| 82 | //struct for particle flags note: this is separate from the particle struct to save memory (ram alignment) | ||
| 83 | typedef union { | ||
| 84 | struct { // 1 byte | ||
| 85 | bool outofbounds : 1; // out of bounds flag, set to true if particle is outside of display area | ||
| 86 | bool collide : 1; // if set, particle takes part in collisions | ||
| 87 | bool perpetual : 1; // if set, particle does not age (TTL is not decremented in move function, it still dies from killoutofbounds) | ||
| 88 | bool custom1 : 1; // unused custom flags, can be used by FX to track particle states | ||
| 89 | bool custom2 : 1; | ||
| 90 | bool custom3 : 1; | ||
| 91 | bool custom4 : 1; | ||
| 92 | bool custom5 : 1; | ||
| 93 | }; | ||
| 94 | byte asByte; // access as a byte, order is: LSB is first entry in the list above | ||
| 95 | } PSparticleFlags; | ||
| 96 | |||
| 97 | // struct for additional particle settings (option) | ||
| 98 | typedef struct { // 2 bytes | ||
| 99 | uint8_t size; // particle size, 255 means 10 pixels in diameter, 0 means use global size (including single pixel rendering) | ||
| 100 | uint8_t forcecounter; // counter for applying forces to individual particles | ||
| 101 | } PSadvancedParticle; | ||
| 102 | |||
| 103 | // struct for advanced particle size control (option) | ||
| 104 | typedef struct { // 8 bytes | ||
| 105 | uint8_t asymmetry; // asymmetrical size (0=symmetrical, 255 fully asymmetric) | ||
| 106 | uint8_t asymdir; // direction of asymmetry, 64 is x, 192 is y (0 and 128 is symmetrical) | ||
| 107 | uint8_t maxsize; // target size for growing | ||
| 108 | uint8_t minsize; // target size for shrinking | ||
| 109 | uint8_t sizecounter : 4; // counters used for size contol (grow/shrink/wobble) | ||
| 110 | uint8_t wobblecounter : 4; | ||
| 111 | uint8_t growspeed : 4; | ||
| 112 | uint8_t shrinkspeed : 4; | ||
| 113 | uint8_t wobblespeed : 4; | ||
| 114 | bool grow : 1; // flags | ||
| 115 | bool shrink : 1; | ||
| 116 | bool pulsate : 1; // grows & shrinks & grows & ... | ||
| 117 | bool wobble : 1; // alternate x and y size | ||
| 118 | } PSsizeControl; | ||
| 119 | |||
| 120 | |||
| 121 | //struct for a particle source (20 bytes) | ||
| 122 | typedef struct { | ||
| 123 | uint16_t minLife; // minimum ttl of emittet particles | ||
| 124 | uint16_t maxLife; // maximum ttl of emitted particles | ||
| 125 | PSparticle source; // use a particle as the emitter source (speed, position, color) | ||
| 126 | PSparticleFlags sourceFlags; // flags for the source particle | ||
| 127 | int8_t var; // variation of emitted speed (adds random(+/- var) to speed) | ||
| 128 | int8_t vx; // emitting speed | ||
| 129 | int8_t vy; | ||
| 130 | uint8_t size; // particle size (advanced property), global size is added on top to this size | ||
| 131 | } PSsource; | ||
| 132 | |||
| 133 | // class uses approximately 60 bytes | ||
| 134 | class ParticleSystem2D { | ||
| 135 | public: | ||
| 136 | ParticleSystem2D(const uint32_t width, const uint32_t height, const uint32_t numberofparticles, const uint32_t numberofsources, const bool isadvanced = false, const bool sizecontrol = false); // constructor | ||
| 137 | // note: memory is allcated in the FX function, no deconstructor needed | ||
| 138 | void update(void); //update the particles according to set options and render to the matrix | ||
| 139 | void updateFire(const uint8_t intensity, const bool renderonly); // update function for fire, if renderonly is set, particles are not updated (required to fix transitions with frameskips) | ||
| 140 | void updateSystem(void); // call at the beginning of every FX, updates pointers and dimensions | ||
| 141 | void particleMoveUpdate(PSparticle &part, PSparticleFlags &partFlags, PSsettings2D *options = NULL, PSadvancedParticle *advancedproperties = NULL); // move function | ||
| 142 | // particle emitters | ||
| 143 | int32_t sprayEmit(const PSsource &emitter); | ||
| 144 | void flameEmit(const PSsource &emitter); | ||
| 145 | int32_t angleEmit(PSsource& emitter, const uint16_t angle, const int32_t speed); | ||
| 146 | //particle physics | ||
| 147 | void applyGravity(PSparticle &part); // applies gravity to single particle (use this for sources) | ||
| 148 | [[gnu::hot]] void applyForce(PSparticle &part, const int8_t xforce, const int8_t yforce, uint8_t &counter); | ||
| 149 | [[gnu::hot]] void applyForce(const uint32_t particleindex, const int8_t xforce, const int8_t yforce); // use this for advanced property particles | ||
| 150 | void applyForce(const int8_t xforce, const int8_t yforce); // apply a force to all particles | ||
| 151 | void applyAngleForce(PSparticle &part, const int8_t force, const uint16_t angle, uint8_t &counter); | ||
| 152 | void applyAngleForce(const uint32_t particleindex, const int8_t force, const uint16_t angle); // use this for advanced property particles | ||
| 153 | void applyAngleForce(const int8_t force, const uint16_t angle); // apply angular force to all particles | ||
| 154 | void applyFriction(PSparticle &part, const int32_t coefficient); // apply friction to specific particle | ||
| 155 | void applyFriction(const int32_t coefficient); // apply friction to all used particles | ||
| 156 | void pointAttractor(const uint32_t particleindex, PSparticle &attractor, const uint8_t strength, const bool swallow); | ||
| 157 | // set options note: inlining the set function uses more flash so dont optimize | ||
| 158 | void setUsedParticles(const uint8_t percentage); // set the percentage of particles used in the system, 255=100% | ||
| 159 | void setCollisionHardness(const uint8_t hardness); // hardness for particle collisions (255 means full hard) | ||
| 160 | void setWallHardness(const uint8_t hardness); // hardness for bouncing on the wall if bounceXY is set | ||
| 161 | void setWallRoughness(const uint8_t roughness); // wall roughness randomizes wall collisions | ||
| 162 | void setMatrixSize(const uint32_t x, const uint32_t y); | ||
| 163 | void setWrapX(const bool enable); | ||
| 164 | void setWrapY(const bool enable); | ||
| 165 | void setBounceX(const bool enable); | ||
| 166 | void setBounceY(const bool enable); | ||
| 167 | void setKillOutOfBounds(const bool enable); // if enabled, particles outside of matrix instantly die | ||
| 168 | void setSaturation(const uint8_t sat); // set global color saturation | ||
| 169 | void setColorByAge(const bool enable); | ||
| 170 | void setMotionBlur(const uint8_t bluramount); // note: motion blur can only be used if 'particlesize' is set to zero | ||
| 171 | void setSmearBlur(const uint8_t bluramount); // enable 2D smeared blurring of full frame | ||
| 172 | void setParticleSize(const uint8_t size); | ||
| 173 | void setGravity(const int8_t force = 8); | ||
| 174 | void enableParticleCollisions(const bool enable, const uint8_t hardness = 255); | ||
| 175 | |||
| 176 | PSparticle *particles; // pointer to particle array | ||
| 177 | PSparticleFlags *particleFlags; // pointer to particle flags array | ||
| 178 | PSsource *sources; // pointer to sources | ||
| 179 | PSadvancedParticle *advPartProps; // pointer to advanced particle properties (can be NULL) | ||
| 180 | PSsizeControl *advPartSize; // pointer to advanced particle size control (can be NULL) | ||
| 181 | uint8_t* PSdataEnd; // points to first available byte after the PSmemory, is set in setPointers(). use this for FX custom data | ||
| 182 | int32_t maxX, maxY; // particle system size i.e. width-1 / height-1 in subpixels, Note: all "max" variables must be signed to compare to coordinates (which are signed) | ||
| 183 | int32_t maxXpixel, maxYpixel; // last physical pixel that can be drawn to (FX can read this to read segment size if required), equal to width-1 / height-1 | ||
| 184 | uint32_t numSources; // number of sources | ||
| 185 | uint32_t usedParticles; // number of particles used in animation, is relative to 'numParticles' | ||
| 186 | //note: some variables are 32bit for speed and code size at the cost of ram | ||
| 187 | |||
| 188 | private: | ||
| 189 | //rendering functions | ||
| 190 | void render(); | ||
| 191 | [[gnu::hot]] void renderParticle(const uint32_t particleindex, const uint8_t brightness, const CRGB& color, const bool wrapX, const bool wrapY); | ||
| 192 | //paricle physics applied by system if flags are set | ||
| 193 | void applyGravity(); // applies gravity to all particles | ||
| 194 | void handleCollisions(); | ||
| 195 | [[gnu::hot]] void collideParticles(PSparticle &particle1, PSparticle &particle2, const int32_t dx, const int32_t dy, const uint32_t collDistSq); | ||
| 196 | void fireParticleupdate(); | ||
| 197 | //utility functions | ||
| 198 | void updatePSpointers(const bool isadvanced, const bool sizecontrol); // update the data pointers to current segment data space | ||
| 199 | bool updateSize(PSadvancedParticle *advprops, PSsizeControl *advsize); // advanced size control | ||
| 200 | void getParticleXYsize(PSadvancedParticle *advprops, PSsizeControl *advsize, uint32_t &xsize, uint32_t &ysize); | ||
| 201 | [[gnu::hot]] void bounce(int8_t &incomingspeed, int8_t ¶llelspeed, int32_t &position, const uint32_t maxposition); // bounce on a wall | ||
| 202 | // note: variables that are accessed often are 32bit for speed | ||
| 203 | CRGB *framebuffer; // local frame buffer for rendering | ||
| 204 | PSsettings2D particlesettings; // settings used when updating particles (can also used by FX to move sources), do not edit properties directly, use functions above | ||
| 205 | uint32_t numParticles; // total number of particles allocated by this system | ||
| 206 | uint32_t emitIndex; // index to count through particles to emit so searching for dead pixels is faster | ||
| 207 | int32_t collisionHardness; | ||
| 208 | uint32_t wallHardness; | ||
| 209 | uint32_t wallRoughness; // randomizes wall collisions | ||
| 210 | uint32_t particleHardRadius; // hard surface radius of a particle, used for collision detection (32bit for speed) | ||
| 211 | uint16_t collisionStartIdx; // particle array start index for collision detection | ||
| 212 | uint8_t fireIntesity = 0; // fire intensity, used for fire mode (flash use optimization, better than passing an argument to render function) | ||
| 213 | uint8_t forcecounter; // counter for globally applied forces | ||
| 214 | uint8_t gforcecounter; // counter for global gravity | ||
| 215 | int8_t gforce; // gravity strength, default is 8 (negative is allowed, positive is downwards) | ||
| 216 | // global particle properties for basic particles | ||
| 217 | uint8_t particlesize; // global particle size, 0 = 1 pixel, 1 = 2 pixels, 255 = 10 pixels (note: this is also added to individual sized particles, set to 0 or 1 for standard advanced particle rendering) | ||
| 218 | uint8_t motionBlur; // motion blur, values > 100 gives smoother animations. Note: motion blurring does not work if particlesize is > 0 | ||
| 219 | uint8_t smearBlur; // 2D smeared blurring of full frame | ||
| 220 | }; | ||
| 221 | |||
| 222 | void blur2D(CRGB *colorbuffer, const uint32_t xsize, uint32_t ysize, const uint32_t xblur, const uint32_t yblur, const uint32_t xstart = 0, uint32_t ystart = 0, const bool isparticle = false); | ||
| 223 | // initialization functions (not part of class) | ||
| 224 | bool initParticleSystem2D(ParticleSystem2D *&PartSys, const uint32_t requestedsources, const uint32_t additionalbytes = 0, const bool advanced = false, const bool sizecontrol = false); | ||
| 225 | uint32_t calculateNumberOfParticles2D(const uint32_t pixels, const bool advanced, const bool sizecontrol); | ||
| 226 | uint32_t calculateNumberOfSources2D(const uint32_t pixels, const uint32_t requestedsources); | ||
| 227 | bool allocateParticleSystemMemory2D(const uint32_t numparticles, const uint32_t numsources, const bool advanced, const bool sizecontrol, const uint32_t additionalbytes); | ||
| 228 | #endif // WLED_DISABLE_PARTICLESYSTEM2D | ||
| 229 | |||
| 230 | //////////////////////// | ||
| 231 | // 1D Particle System // | ||
| 232 | //////////////////////// | ||
| 233 | #ifndef WLED_DISABLE_PARTICLESYSTEM1D | ||
| 234 | // memory allocation | ||
| 235 | #define ESP8266_MAXPARTICLES_1D 320 | ||
| 236 | #define ESP8266_MAXSOURCES_1D 16 | ||
| 237 | #define ESP32S2_MAXPARTICLES_1D 1300 | ||
| 238 | #define ESP32S2_MAXSOURCES_1D 32 | ||
| 239 | #define ESP32_MAXPARTICLES_1D 2600 | ||
| 240 | #define ESP32_MAXSOURCES_1D 64 | ||
| 241 | |||
| 242 | // particle dimensions (subpixel division) | ||
| 243 | #define PS_P_RADIUS_1D 32 // subpixel size, each pixel is divided by this for particle movement, if this value is changed, also change the shift defines (next two lines) | ||
| 244 | #define PS_P_HALFRADIUS_1D (PS_P_RADIUS_1D >> 1) | ||
| 245 | #define PS_P_RADIUS_SHIFT_1D 5 // 1 << PS_P_RADIUS_SHIFT = PS_P_RADIUS | ||
| 246 | #define PS_P_SURFACE_1D 5 // shift: 2^PS_P_SURFACE = PS_P_RADIUS_1D | ||
| 247 | #define PS_P_MINHARDRADIUS_1D 32 // minimum hard surface radius note: do not change or hourglass effect will be broken | ||
| 248 | #define PS_P_MINSURFACEHARDNESS_1D 120 // minimum hardness used in collision impulse calculation | ||
| 249 | |||
| 250 | // struct for PS settings (shared for 1D and 2D class) | ||
| 251 | typedef union { | ||
| 252 | struct{ | ||
| 253 | // one byte bit field for 1D settings | ||
| 254 | bool wrap : 1; | ||
| 255 | bool bounce : 1; | ||
| 256 | bool killoutofbounds : 1; // if set, out of bound particles are killed immediately | ||
| 257 | bool useGravity : 1; // set to 1 if gravity is used, disables bounceY at the top | ||
| 258 | bool useCollisions : 1; | ||
| 259 | bool colorByAge : 1; // if set, particle hue is set by ttl value in render function | ||
| 260 | bool colorByPosition : 1; // if set, particle hue is set by its position in the strip segment | ||
| 261 | bool unused : 1; | ||
| 262 | }; | ||
| 263 | byte asByte; // access as a byte, order is: LSB is first entry in the list above | ||
| 264 | } PSsettings1D; | ||
| 265 | |||
| 266 | //struct for a single particle (8 bytes) | ||
| 267 | typedef struct { | ||
| 268 | int32_t x; // x position in particle system | ||
| 269 | uint16_t ttl; // time to live in frames | ||
| 270 | int8_t vx; // horizontal velocity | ||
| 271 | uint8_t hue; // color hue | ||
| 272 | } PSparticle1D; | ||
| 273 | |||
| 274 | //struct for particle flags | ||
| 275 | typedef union { | ||
| 276 | struct { // 1 byte | ||
| 277 | bool outofbounds : 1; // out of bounds flag, set to true if particle is outside of display area | ||
| 278 | bool collide : 1; // if set, particle takes part in collisions | ||
| 279 | bool perpetual : 1; // if set, particle does not age (TTL is not decremented in move function, it still dies from killoutofbounds) | ||
| 280 | bool reversegrav : 1; // if set, gravity is reversed on this particle | ||
| 281 | bool forcedirection : 1; // direction the force was applied, 1 is positive x-direction (used for collision stacking, similar to reversegrav) TODO: not used anymore, can be removed | ||
| 282 | bool fixed : 1; // if set, particle does not move (and collisions make other particles revert direction), | ||
| 283 | bool custom1 : 1; // unused custom flags, can be used by FX to track particle states | ||
| 284 | bool custom2 : 1; | ||
| 285 | }; | ||
| 286 | byte asByte; // access as a byte, order is: LSB is first entry in the list above | ||
| 287 | } PSparticleFlags1D; | ||
| 288 | |||
| 289 | // struct for additional particle settings (optional) | ||
| 290 | typedef struct { | ||
| 291 | uint8_t sat; //color saturation | ||
| 292 | uint8_t size; // particle size, 255 means 10 pixels in diameter, this overrides global size setting | ||
| 293 | uint8_t forcecounter; | ||
| 294 | } PSadvancedParticle1D; | ||
| 295 | |||
| 296 | //struct for a particle source (20 bytes) | ||
| 297 | typedef struct { | ||
| 298 | uint16_t minLife; // minimum ttl of emittet particles | ||
| 299 | uint16_t maxLife; // maximum ttl of emitted particles | ||
| 300 | PSparticle1D source; // use a particle as the emitter source (speed, position, color) | ||
| 301 | PSparticleFlags1D sourceFlags; // flags for the source particle | ||
| 302 | int8_t var; // variation of emitted speed (adds random(+/- var) to speed) | ||
| 303 | int8_t v; // emitting speed | ||
| 304 | uint8_t sat; // color saturation (advanced property) | ||
| 305 | uint8_t size; // particle size (advanced property) | ||
| 306 | // note: there is 3 bytes of padding added here | ||
| 307 | } PSsource1D; | ||
| 308 | |||
| 309 | class ParticleSystem1D | ||
| 310 | { | ||
| 311 | public: | ||
| 312 | ParticleSystem1D(const uint32_t length, const uint32_t numberofparticles, const uint32_t numberofsources, const bool isadvanced = false); // constructor | ||
| 313 | // note: memory is allcated in the FX function, no deconstructor needed | ||
| 314 | void update(void); //update the particles according to set options and render to the matrix | ||
| 315 | void updateSystem(void); // call at the beginning of every FX, updates pointers and dimensions | ||
| 316 | // particle emitters | ||
| 317 | int32_t sprayEmit(const PSsource1D &emitter); | ||
| 318 | void particleMoveUpdate(PSparticle1D &part, PSparticleFlags1D &partFlags, PSsettings1D *options = NULL, PSadvancedParticle1D *advancedproperties = NULL); // move function | ||
| 319 | //particle physics | ||
| 320 | [[gnu::hot]] void applyForce(PSparticle1D &part, const int8_t xforce, uint8_t &counter); //apply a force to a single particle | ||
| 321 | void applyForce(const int8_t xforce); // apply a force to all particles | ||
| 322 | void applyGravity(PSparticle1D &part, PSparticleFlags1D &partFlags); // applies gravity to single particle (use this for sources) | ||
| 323 | void applyFriction(const int32_t coefficient); // apply friction to all used particles | ||
| 324 | // set options | ||
| 325 | void setUsedParticles(const uint8_t percentage); // set the percentage of particles used in the system, 255=100% | ||
| 326 | void setWallHardness(const uint8_t hardness); // hardness for bouncing on the wall if bounceXY is set | ||
| 327 | void setSize(const uint32_t x); //set particle system size (= strip length) | ||
| 328 | void setWrap(const bool enable); | ||
| 329 | void setBounce(const bool enable); | ||
| 330 | void setKillOutOfBounds(const bool enable); // if enabled, particles outside of matrix instantly die | ||
| 331 | // void setSaturation(uint8_t sat); // set global color saturation | ||
| 332 | void setColorByAge(const bool enable); | ||
| 333 | void setColorByPosition(const bool enable); | ||
| 334 | void setMotionBlur(const uint8_t bluramount); // note: motion blur can only be used if 'particlesize' is set to zero | ||
| 335 | void setSmearBlur(const uint8_t bluramount); // enable 1D smeared blurring of full frame | ||
| 336 | void setParticleSize(const uint8_t size); //size 0 = 1 pixel, size 1 = 2 pixels, is overruled if advanced particle is used | ||
| 337 | void setGravity(int8_t force = 8); | ||
| 338 | void enableParticleCollisions(bool enable, const uint8_t hardness = 255); | ||
| 339 | |||
| 340 | PSparticle1D *particles; // pointer to particle array | ||
| 341 | PSparticleFlags1D *particleFlags; // pointer to particle flags array | ||
| 342 | PSsource1D *sources; // pointer to sources | ||
| 343 | PSadvancedParticle1D *advPartProps; // pointer to advanced particle properties (can be NULL) | ||
| 344 | //PSsizeControl *advPartSize; // pointer to advanced particle size control (can be NULL) | ||
| 345 | uint8_t* PSdataEnd; // points to first available byte after the PSmemory, is set in setPointers(). use this for FX custom data | ||
| 346 | int32_t maxX; // particle system size i.e. width-1, Note: all "max" variables must be signed to compare to coordinates (which are signed) | ||
| 347 | int32_t maxXpixel; // last physical pixel that can be drawn to (FX can read this to read segment size if required), equal to width-1 | ||
| 348 | uint32_t numSources; // number of sources | ||
| 349 | uint32_t usedParticles; // number of particles used in animation, is relative to 'numParticles' | ||
| 350 | |||
| 351 | private: | ||
| 352 | //rendering functions | ||
| 353 | void render(void); | ||
| 354 | [[gnu::hot]] void renderParticle(const uint32_t particleindex, const uint8_t brightness, const CRGB &color, const bool wrap); | ||
| 355 | |||
| 356 | //paricle physics applied by system if flags are set | ||
| 357 | void applyGravity(); // applies gravity to all particles | ||
| 358 | void handleCollisions(); | ||
| 359 | [[gnu::hot]] void collideParticles(PSparticle1D &particle1, const PSparticleFlags1D &particle1flags, PSparticle1D &particle2, const PSparticleFlags1D &particle2flags, const int32_t dx, const uint32_t dx_abs, const uint32_t collisiondistance); | ||
| 360 | |||
| 361 | //utility functions | ||
| 362 | void updatePSpointers(const bool isadvanced); // update the data pointers to current segment data space | ||
| 363 | //void updateSize(PSadvancedParticle *advprops, PSsizeControl *advsize); // advanced size control | ||
| 364 | [[gnu::hot]] void bounce(int8_t &incomingspeed, int8_t ¶llelspeed, int32_t &position, const uint32_t maxposition); // bounce on a wall | ||
| 365 | // note: variables that are accessed often are 32bit for speed | ||
| 366 | #ifndef ESP8266 | ||
| 367 | CRGB *framebuffer; // local frame buffer for rendering | ||
| 368 | #endif | ||
| 369 | PSsettings1D particlesettings; // settings used when updating particles | ||
| 370 | uint32_t numParticles; // total number of particles allocated by this system | ||
| 371 | uint32_t emitIndex; // index to count through particles to emit so searching for dead pixels is faster | ||
| 372 | int32_t collisionHardness; | ||
| 373 | uint32_t particleHardRadius; // hard surface radius of a particle, used for collision detection | ||
| 374 | uint32_t wallHardness; | ||
| 375 | uint8_t gforcecounter; // counter for global gravity | ||
| 376 | int8_t gforce; // gravity strength, default is 8 (negative is allowed, positive is downwards) | ||
| 377 | uint8_t forcecounter; // counter for globally applied forces | ||
| 378 | uint16_t collisionStartIdx; // particle array start index for collision detection | ||
| 379 | //global particle properties for basic particles | ||
| 380 | uint8_t particlesize; // global particle size, 0 = 1 pixel, 1 = 2 pixels, is overruled by advanced particle size | ||
| 381 | uint8_t motionBlur; // enable motion blur, values > 100 gives smoother animations | ||
| 382 | uint8_t smearBlur; // smeared blurring of full frame | ||
| 383 | }; | ||
| 384 | |||
| 385 | bool initParticleSystem1D(ParticleSystem1D *&PartSys, const uint32_t requestedsources, const uint8_t fractionofparticles = 255, const uint32_t additionalbytes = 0, const bool advanced = false); | ||
| 386 | uint32_t calculateNumberOfParticles1D(const uint32_t fraction, const bool isadvanced); | ||
| 387 | uint32_t calculateNumberOfSources1D(const uint32_t requestedsources); | ||
| 388 | bool allocateParticleSystemMemory1D(const uint32_t numparticles, const uint32_t numsources, const bool isadvanced, const uint32_t additionalbytes); | ||
| 389 | void blur1D(CRGB *colorbuffer, uint32_t size, uint32_t blur, uint32_t start); | ||
| 390 | #endif // WLED_DISABLE_PARTICLESYSTEM1D | ||
| 391 |