mirror of
https://github.com/wled/WLED.git
synced 2025-04-19 12:27:17 +00:00

* added Sonic Boom AR FX, some tweaks to Sonic Stream * added white color option to Sonic Stream * improvements to collisions (speed look-ahead) * code prettified * added "playful" mode to PS Chase plus some minor speed optimizations * Adding new FX: PS Springy with many config options
419 lines
25 KiB
C++
419 lines
25 KiB
C++
/*
|
|
FXparticleSystem.cpp
|
|
|
|
Particle system with functions for particle generation, particle movement and particle rendering to RGB matrix.
|
|
by DedeHai (Damian Schneider) 2013-2024
|
|
|
|
Copyright (c) 2024 Damian Schneider
|
|
Licensed under the EUPL v. 1.2 or later
|
|
*/
|
|
|
|
#ifdef WLED_DISABLE_2D
|
|
#define WLED_DISABLE_PARTICLESYSTEM2D
|
|
#endif
|
|
|
|
#if !(defined(WLED_DISABLE_PARTICLESYSTEM2D) && defined(WLED_DISABLE_PARTICLESYSTEM1D)) // not both disabled
|
|
|
|
#include <stdint.h>
|
|
#include "wled.h"
|
|
|
|
#define PS_P_MAXSPEED 120 // maximum speed a particle can have (vx/vy is int8)
|
|
#define MAX_MEMIDLE 10 // max idle time (in frames) before memory is deallocated (if deallocated during an effect, it will crash!)
|
|
|
|
//#define WLED_DEBUG_PS // note: enabling debug uses ~3k of flash
|
|
|
|
#ifdef WLED_DEBUG_PS
|
|
#define PSPRINT(x) Serial.print(x)
|
|
#define PSPRINTLN(x) Serial.println(x)
|
|
#else
|
|
#define PSPRINT(x)
|
|
#define PSPRINTLN(x)
|
|
#endif
|
|
|
|
// memory and transition manager
|
|
struct partMem {
|
|
void* particleMemPointer; // pointer to particle memory
|
|
uint32_t buffersize; // buffer size in bytes
|
|
uint8_t particleType; // type of particles currently in memory: 0 = none, particle struct size otherwise (required for 1D<->2D transitions)
|
|
uint8_t id; // ID of segment this memory belongs to
|
|
uint8_t watchdog; // counter to handle deallocation
|
|
uint8_t inTransition; // to track PS to PS FX transitions (is set to new FX ID during transitions), not set if not both FX are PS FX
|
|
uint8_t currentFX; // current FX ID, is set when transition is complete, used to detect back and forth transitions
|
|
bool finalTransfer; // used to update buffer in rendering function after transition has ended
|
|
bool transferParticles; // if set, particles in buffer are transferred to new FX
|
|
};
|
|
|
|
void* particleMemoryManager(const uint32_t requestedParticles, size_t structSize, uint32_t &availableToPS, uint32_t numParticlesUsed, const uint8_t effectID); // update particle memory pointer, handles memory transitions
|
|
void particleHandover(void *buffer, size_t structSize, int32_t numParticles);
|
|
void updateUsedParticles(const uint32_t allocated, const uint32_t available, const uint8_t percentage, uint32_t &used);
|
|
bool segmentIsOverlay(void); // check if segment is fully overlapping with at least one underlying segment
|
|
partMem* getPartMem(void); // returns pointer to memory struct for current segment or nullptr
|
|
void updateRenderingBuffer(uint32_t requiredpixels, bool isFramebuffer, bool initialize); // allocate CRGB rendering buffer, update size if needed
|
|
void transferBuffer(uint32_t width, uint32_t height, bool useAdditiveTransfer = false); // transfer the buffer to the segment (supports 1D and 2D)
|
|
void servicePSmem(); // increments watchdog, frees memory if idle too long
|
|
|
|
// limit speed of particles (used in 1D and 2D)
|
|
static inline int32_t limitSpeed(const int32_t speed) {
|
|
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
|
|
}
|
|
#endif
|
|
|
|
#ifndef WLED_DISABLE_PARTICLESYSTEM2D
|
|
// memory allocation
|
|
#define ESP8266_MAXPARTICLES 300 // enough up to 20x20 pixels
|
|
#define ESP8266_MAXSOURCES 24
|
|
#define ESP32S2_MAXPARTICLES 1024 // enough up to 32x32 pixels
|
|
#define ESP32S2_MAXSOURCES 64
|
|
#define ESP32_MAXPARTICLES 2048 // enough up to 64x32 pixels
|
|
#define ESP32_MAXSOURCES 128
|
|
|
|
// particle dimensions (subpixel division)
|
|
#define PS_P_RADIUS 64 // subpixel size, each pixel is divided by this for particle movement (must be a power of 2)
|
|
#define PS_P_HALFRADIUS (PS_P_RADIUS >> 1)
|
|
#define PS_P_RADIUS_SHIFT 6 // shift for RADIUS
|
|
#define PS_P_SURFACE 12 // shift: 2^PS_P_SURFACE = (PS_P_RADIUS)^2
|
|
#define PS_P_MINHARDRADIUS 64 // minimum hard surface radius for collisions
|
|
#define PS_P_MINSURFACEHARDNESS 128 // minimum hardness used in collision impulse calculation, below this hardness, particles become sticky
|
|
|
|
// struct for PS settings (shared for 1D and 2D class)
|
|
typedef union {
|
|
struct{ // one byte bit field for 2D settings
|
|
bool wrapX : 1;
|
|
bool wrapY : 1;
|
|
bool bounceX : 1;
|
|
bool bounceY : 1;
|
|
bool killoutofbounds : 1; // if set, out of bound particles are killed immediately
|
|
bool useGravity : 1; // set to 1 if gravity is used, disables bounceY at the top
|
|
bool useCollisions : 1;
|
|
bool colorByAge : 1; // if set, particle hue is set by ttl value in render function
|
|
};
|
|
byte asByte; // access as a byte, order is: LSB is first entry in the list above
|
|
} PSsettings2D;
|
|
|
|
//struct for a single particle
|
|
typedef struct { // 10 bytes
|
|
int16_t x; // x position in particle system
|
|
int16_t y; // y position in particle system
|
|
uint16_t ttl; // time to live in frames
|
|
int8_t vx; // horizontal velocity
|
|
int8_t vy; // vertical velocity
|
|
uint8_t hue; // color hue
|
|
uint8_t sat; // particle color saturation
|
|
} PSparticle;
|
|
|
|
//struct for particle flags note: this is separate from the particle struct to save memory (ram alignment)
|
|
typedef union {
|
|
struct { // 1 byte
|
|
bool outofbounds : 1; // out of bounds flag, set to true if particle is outside of display area
|
|
bool collide : 1; // if set, particle takes part in collisions
|
|
bool perpetual : 1; // if set, particle does not age (TTL is not decremented in move function, it still dies from killoutofbounds)
|
|
bool custom1 : 1; // unused custom flags, can be used by FX to track particle states
|
|
bool custom2 : 1;
|
|
bool custom3 : 1;
|
|
bool custom4 : 1;
|
|
bool custom5 : 1;
|
|
};
|
|
byte asByte; // access as a byte, order is: LSB is first entry in the list above
|
|
} PSparticleFlags;
|
|
|
|
// struct for additional particle settings (option)
|
|
typedef struct { // 2 bytes
|
|
uint8_t size; // particle size, 255 means 10 pixels in diameter
|
|
uint8_t forcecounter; // counter for applying forces to individual particles
|
|
} PSadvancedParticle;
|
|
|
|
// struct for advanced particle size control (option)
|
|
typedef struct { // 8 bytes
|
|
uint8_t asymmetry; // asymmetrical size (0=symmetrical, 255 fully asymmetric)
|
|
uint8_t asymdir; // direction of asymmetry, 64 is x, 192 is y (0 and 128 is symmetrical)
|
|
uint8_t maxsize; // target size for growing
|
|
uint8_t minsize; // target size for shrinking
|
|
uint8_t sizecounter : 4; // counters used for size contol (grow/shrink/wobble)
|
|
uint8_t wobblecounter : 4;
|
|
uint8_t growspeed : 4;
|
|
uint8_t shrinkspeed : 4;
|
|
uint8_t wobblespeed : 4;
|
|
bool grow : 1; // flags
|
|
bool shrink : 1;
|
|
bool pulsate : 1; // grows & shrinks & grows & ...
|
|
bool wobble : 1; // alternate x and y size
|
|
} PSsizeControl;
|
|
|
|
|
|
//struct for a particle source (20 bytes)
|
|
typedef struct {
|
|
uint16_t minLife; // minimum ttl of emittet particles
|
|
uint16_t maxLife; // maximum ttl of emitted particles
|
|
PSparticle source; // use a particle as the emitter source (speed, position, color)
|
|
PSparticleFlags sourceFlags; // flags for the source particle
|
|
int8_t var; // variation of emitted speed (adds random(+/- var) to speed)
|
|
int8_t vx; // emitting speed
|
|
int8_t vy;
|
|
uint8_t size; // particle size (advanced property)
|
|
} PSsource;
|
|
|
|
// class uses approximately 60 bytes
|
|
class ParticleSystem2D {
|
|
public:
|
|
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
|
|
// note: memory is allcated in the FX function, no deconstructor needed
|
|
void update(void); //update the particles according to set options and render to the matrix
|
|
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)
|
|
void updateSystem(void); // call at the beginning of every FX, updates pointers and dimensions
|
|
void particleMoveUpdate(PSparticle &part, PSparticleFlags &partFlags, PSsettings2D *options = NULL, PSadvancedParticle *advancedproperties = NULL); // move function
|
|
// particle emitters
|
|
int32_t sprayEmit(const PSsource &emitter);
|
|
void flameEmit(const PSsource &emitter);
|
|
int32_t angleEmit(PSsource& emitter, const uint16_t angle, const int32_t speed);
|
|
//particle physics
|
|
void applyGravity(PSparticle &part); // applies gravity to single particle (use this for sources)
|
|
[[gnu::hot]] void applyForce(PSparticle &part, const int8_t xforce, const int8_t yforce, uint8_t &counter);
|
|
[[gnu::hot]] void applyForce(const uint32_t particleindex, const int8_t xforce, const int8_t yforce); // use this for advanced property particles
|
|
void applyForce(const int8_t xforce, const int8_t yforce); // apply a force to all particles
|
|
void applyAngleForce(PSparticle &part, const int8_t force, const uint16_t angle, uint8_t &counter);
|
|
void applyAngleForce(const uint32_t particleindex, const int8_t force, const uint16_t angle); // use this for advanced property particles
|
|
void applyAngleForce(const int8_t force, const uint16_t angle); // apply angular force to all particles
|
|
void applyFriction(PSparticle &part, const int32_t coefficient); // apply friction to specific particle
|
|
void applyFriction(const int32_t coefficient); // apply friction to all used particles
|
|
void pointAttractor(const uint32_t particleindex, PSparticle &attractor, const uint8_t strength, const bool swallow);
|
|
// set options note: inlining the set function uses more flash so dont optimize
|
|
void setUsedParticles(const uint8_t percentage); // set the percentage of particles used in the system, 255=100%
|
|
inline uint32_t getAvailableParticles(void) { return availableParticles; } // available particles in the buffer, use this to check if buffer changed during FX init
|
|
void setCollisionHardness(const uint8_t hardness); // hardness for particle collisions (255 means full hard)
|
|
void setWallHardness(const uint8_t hardness); // hardness for bouncing on the wall if bounceXY is set
|
|
void setWallRoughness(const uint8_t roughness); // wall roughness randomizes wall collisions
|
|
void setMatrixSize(const uint32_t x, const uint32_t y);
|
|
void setWrapX(const bool enable);
|
|
void setWrapY(const bool enable);
|
|
void setBounceX(const bool enable);
|
|
void setBounceY(const bool enable);
|
|
void setKillOutOfBounds(const bool enable); // if enabled, particles outside of matrix instantly die
|
|
void setSaturation(const uint8_t sat); // set global color saturation
|
|
void setColorByAge(const bool enable);
|
|
void setMotionBlur(const uint8_t bluramount); // note: motion blur can only be used if 'particlesize' is set to zero
|
|
void setSmearBlur(const uint8_t bluramount); // enable 2D smeared blurring of full frame
|
|
void setParticleSize(const uint8_t size);
|
|
void setGravity(const int8_t force = 8);
|
|
void enableParticleCollisions(const bool enable, const uint8_t hardness = 255);
|
|
|
|
PSparticle *particles; // pointer to particle array
|
|
PSparticleFlags *particleFlags; // pointer to particle flags array
|
|
PSsource *sources; // pointer to sources
|
|
PSadvancedParticle *advPartProps; // pointer to advanced particle properties (can be NULL)
|
|
PSsizeControl *advPartSize; // pointer to advanced particle size control (can be NULL)
|
|
uint8_t* PSdataEnd; // points to first available byte after the PSmemory, is set in setPointers(). use this for FX custom data
|
|
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)
|
|
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
|
|
uint32_t numSources; // number of sources
|
|
uint32_t usedParticles; // number of particles used in animation, is relative to 'numParticles'
|
|
//note: some variables are 32bit for speed and code size at the cost of ram
|
|
|
|
private:
|
|
//rendering functions
|
|
void ParticleSys_render();
|
|
[[gnu::hot]] void renderParticle(const uint32_t particleindex, const uint8_t brightness, const CRGB& color, const bool wrapX, const bool wrapY);
|
|
//paricle physics applied by system if flags are set
|
|
void applyGravity(); // applies gravity to all particles
|
|
void handleCollisions();
|
|
[[gnu::hot]] void collideParticles(PSparticle &particle1, PSparticle &particle2, const int32_t dx, const int32_t dy, const int32_t collDistSq);
|
|
void fireParticleupdate();
|
|
//utility functions
|
|
void updatePSpointers(const bool isadvanced, const bool sizecontrol); // update the data pointers to current segment data space
|
|
bool updateSize(PSadvancedParticle *advprops, PSsizeControl *advsize); // advanced size control
|
|
void getParticleXYsize(PSadvancedParticle *advprops, PSsizeControl *advsize, uint32_t &xsize, uint32_t &ysize);
|
|
[[gnu::hot]] void bounce(int8_t &incomingspeed, int8_t ¶llelspeed, int32_t &position, const uint32_t maxposition); // bounce on a wall
|
|
// note: variables that are accessed often are 32bit for speed
|
|
PSsettings2D particlesettings; // settings used when updating particles (can also used by FX to move sources), do not edit properties directly, use functions above
|
|
uint32_t numParticles; // total number of particles allocated by this system note: during transitions, less are available, use availableParticles
|
|
uint32_t availableParticles; // number of particles available for use (can be more or less than numParticles, assigned by memory manager)
|
|
uint32_t emitIndex; // index to count through particles to emit so searching for dead pixels is faster
|
|
int32_t collisionHardness;
|
|
uint32_t wallHardness;
|
|
uint32_t wallRoughness; // randomizes wall collisions
|
|
uint32_t particleHardRadius; // hard surface radius of a particle, used for collision detection (32bit for speed)
|
|
uint16_t collisionStartIdx; // particle array start index for collision detection
|
|
uint8_t fireIntesity = 0; // fire intensity, used for fire mode (flash use optimization, better than passing an argument to render function)
|
|
uint8_t fractionOfParticlesUsed; // percentage of particles used in the system (255=100%), used during transition updates
|
|
uint8_t forcecounter; // counter for globally applied forces
|
|
uint8_t gforcecounter; // counter for global gravity
|
|
int8_t gforce; // gravity strength, default is 8 (negative is allowed, positive is downwards)
|
|
// global particle properties for basic particles
|
|
uint8_t particlesize; // global particle size, 0 = 1 pixel, 1 = 2 pixels, 255 = 10 pixels (note: this is also added to individual sized particles)
|
|
uint8_t motionBlur; // motion blur, values > 100 gives smoother animations. Note: motion blurring does not work if particlesize is > 0
|
|
uint8_t smearBlur; // 2D smeared blurring of full frame
|
|
uint8_t effectID; // ID of the effect that is using this particle system, used for transitions
|
|
uint32_t lastRender; // last time the particles were rendered, intermediate fix for speedup
|
|
};
|
|
|
|
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);
|
|
// initialization functions (not part of class)
|
|
bool initParticleSystem2D(ParticleSystem2D *&PartSys, const uint32_t requestedsources, const uint32_t additionalbytes = 0, const bool advanced = false, const bool sizecontrol = false);
|
|
uint32_t calculateNumberOfParticles2D(const uint32_t pixels, const bool advanced, const bool sizecontrol);
|
|
uint32_t calculateNumberOfSources2D(const uint32_t pixels, const uint32_t requestedsources);
|
|
bool allocateParticleSystemMemory2D(const uint32_t numparticles, const uint32_t numsources, const bool advanced, const bool sizecontrol, const uint32_t additionalbytes);
|
|
#endif // WLED_DISABLE_PARTICLESYSTEM2D
|
|
|
|
////////////////////////
|
|
// 1D Particle System //
|
|
////////////////////////
|
|
#ifndef WLED_DISABLE_PARTICLESYSTEM1D
|
|
// memory allocation
|
|
#define ESP8266_MAXPARTICLES_1D 450
|
|
#define ESP8266_MAXSOURCES_1D 16
|
|
#define ESP32S2_MAXPARTICLES_1D 1300
|
|
#define ESP32S2_MAXSOURCES_1D 32
|
|
#define ESP32_MAXPARTICLES_1D 2600
|
|
#define ESP32_MAXSOURCES_1D 64
|
|
|
|
// particle dimensions (subpixel division)
|
|
#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)
|
|
#define PS_P_HALFRADIUS_1D (PS_P_RADIUS_1D >> 1)
|
|
#define PS_P_RADIUS_SHIFT_1D 5 // 1 << PS_P_RADIUS_SHIFT = PS_P_RADIUS
|
|
#define PS_P_SURFACE_1D 5 // shift: 2^PS_P_SURFACE = PS_P_RADIUS_1D
|
|
#define PS_P_MINHARDRADIUS_1D 32 // minimum hard surface radius note: do not change or hourglass effect will be broken
|
|
#define PS_P_MINSURFACEHARDNESS_1D 120 // minimum hardness used in collision impulse calculation
|
|
|
|
// struct for PS settings (shared for 1D and 2D class)
|
|
typedef union {
|
|
struct{
|
|
// one byte bit field for 1D settings
|
|
bool wrap : 1;
|
|
bool bounce : 1;
|
|
bool killoutofbounds : 1; // if set, out of bound particles are killed immediately
|
|
bool useGravity : 1; // set to 1 if gravity is used, disables bounceY at the top
|
|
bool useCollisions : 1;
|
|
bool colorByAge : 1; // if set, particle hue is set by ttl value in render function
|
|
bool colorByPosition : 1; // if set, particle hue is set by its position in the strip segment
|
|
bool unused : 1;
|
|
};
|
|
byte asByte; // access as a byte, order is: LSB is first entry in the list above
|
|
} PSsettings1D;
|
|
|
|
//struct for a single particle (8 bytes)
|
|
typedef struct {
|
|
int32_t x; // x position in particle system
|
|
uint16_t ttl; // time to live in frames
|
|
int8_t vx; // horizontal velocity
|
|
uint8_t hue; // color hue
|
|
} PSparticle1D;
|
|
|
|
//struct for particle flags
|
|
typedef union {
|
|
struct { // 1 byte
|
|
bool outofbounds : 1; // out of bounds flag, set to true if particle is outside of display area
|
|
bool collide : 1; // if set, particle takes part in collisions
|
|
bool perpetual : 1; // if set, particle does not age (TTL is not decremented in move function, it still dies from killoutofbounds)
|
|
bool reversegrav : 1; // if set, gravity is reversed on this particle
|
|
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
|
|
bool fixed : 1; // if set, particle does not move (and collisions make other particles revert direction),
|
|
bool custom1 : 1; // unused custom flags, can be used by FX to track particle states
|
|
bool custom2 : 1;
|
|
};
|
|
byte asByte; // access as a byte, order is: LSB is first entry in the list above
|
|
} PSparticleFlags1D;
|
|
|
|
// struct for additional particle settings (optional)
|
|
typedef struct {
|
|
uint8_t sat; //color saturation
|
|
uint8_t size; // particle size, 255 means 10 pixels in diameter
|
|
uint8_t forcecounter;
|
|
} PSadvancedParticle1D;
|
|
|
|
//struct for a particle source (20 bytes)
|
|
typedef struct {
|
|
uint16_t minLife; // minimum ttl of emittet particles
|
|
uint16_t maxLife; // maximum ttl of emitted particles
|
|
PSparticle1D source; // use a particle as the emitter source (speed, position, color)
|
|
PSparticleFlags1D sourceFlags; // flags for the source particle
|
|
int8_t var; // variation of emitted speed (adds random(+/- var) to speed)
|
|
int8_t v; // emitting speed
|
|
uint8_t sat; // color saturation (advanced property)
|
|
uint8_t size; // particle size (advanced property)
|
|
// note: there is 3 bytes of padding added here
|
|
} PSsource1D;
|
|
|
|
class ParticleSystem1D
|
|
{
|
|
public:
|
|
ParticleSystem1D(const uint32_t length, const uint32_t numberofparticles, const uint32_t numberofsources, const bool isadvanced = false); // constructor
|
|
// note: memory is allcated in the FX function, no deconstructor needed
|
|
void update(void); //update the particles according to set options and render to the matrix
|
|
void updateSystem(void); // call at the beginning of every FX, updates pointers and dimensions
|
|
// particle emitters
|
|
int32_t sprayEmit(const PSsource1D &emitter);
|
|
void particleMoveUpdate(PSparticle1D &part, PSparticleFlags1D &partFlags, PSsettings1D *options = NULL, PSadvancedParticle1D *advancedproperties = NULL); // move function
|
|
//particle physics
|
|
[[gnu::hot]] void applyForce(PSparticle1D &part, const int8_t xforce, uint8_t &counter); //apply a force to a single particle
|
|
void applyForce(const int8_t xforce); // apply a force to all particles
|
|
void applyGravity(PSparticle1D &part, PSparticleFlags1D &partFlags); // applies gravity to single particle (use this for sources)
|
|
void applyFriction(const int32_t coefficient); // apply friction to all used particles
|
|
// set options
|
|
void setUsedParticles(const uint8_t percentage); // set the percentage of particles used in the system, 255=100%
|
|
inline uint32_t getAvailableParticles(void) { return availableParticles; } // available particles in the buffer, use this to check if buffer changed during FX init
|
|
void setWallHardness(const uint8_t hardness); // hardness for bouncing on the wall if bounceXY is set
|
|
void setSize(const uint32_t x); //set particle system size (= strip length)
|
|
void setWrap(const bool enable);
|
|
void setBounce(const bool enable);
|
|
void setKillOutOfBounds(const bool enable); // if enabled, particles outside of matrix instantly die
|
|
// void setSaturation(uint8_t sat); // set global color saturation
|
|
void setColorByAge(const bool enable);
|
|
void setColorByPosition(const bool enable);
|
|
void setMotionBlur(const uint8_t bluramount); // note: motion blur can only be used if 'particlesize' is set to zero
|
|
void setSmearBlur(const uint8_t bluramount); // enable 1D smeared blurring of full frame
|
|
void setParticleSize(const uint8_t size); //size 0 = 1 pixel, size 1 = 2 pixels, is overruled by advanced particle size
|
|
void setGravity(int8_t force = 8);
|
|
void enableParticleCollisions(bool enable, const uint8_t hardness = 255);
|
|
|
|
PSparticle1D *particles; // pointer to particle array
|
|
PSparticleFlags1D *particleFlags; // pointer to particle flags array
|
|
PSsource1D *sources; // pointer to sources
|
|
PSadvancedParticle1D *advPartProps; // pointer to advanced particle properties (can be NULL)
|
|
//PSsizeControl *advPartSize; // pointer to advanced particle size control (can be NULL)
|
|
uint8_t* PSdataEnd; // points to first available byte after the PSmemory, is set in setPointers(). use this for FX custom data
|
|
int32_t maxX; // particle system size i.e. width-1, Note: all "max" variables must be signed to compare to coordinates (which are signed)
|
|
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
|
|
uint32_t numSources; // number of sources
|
|
uint32_t usedParticles; // number of particles used in animation, is relative to 'numParticles'
|
|
|
|
private:
|
|
//rendering functions
|
|
void ParticleSys_render(void);
|
|
[[gnu::hot]] void renderParticle(const uint32_t particleindex, const uint8_t brightness, const CRGB &color, const bool wrap);
|
|
|
|
//paricle physics applied by system if flags are set
|
|
void applyGravity(); // applies gravity to all particles
|
|
void handleCollisions();
|
|
[[gnu::hot]] void collideParticles(PSparticle1D &particle1, const PSparticleFlags1D &particle1flags, PSparticle1D &particle2, const PSparticleFlags1D &particle2flags, const int32_t dx, const uint32_t dx_abs, const int32_t collisiondistance);
|
|
|
|
//utility functions
|
|
void updatePSpointers(const bool isadvanced); // update the data pointers to current segment data space
|
|
//void updateSize(PSadvancedParticle *advprops, PSsizeControl *advsize); // advanced size control
|
|
[[gnu::hot]] void bounce(int8_t &incomingspeed, int8_t ¶llelspeed, int32_t &position, const uint32_t maxposition); // bounce on a wall
|
|
// note: variables that are accessed often are 32bit for speed
|
|
PSsettings1D particlesettings; // settings used when updating particles
|
|
uint32_t numParticles; // total number of particles allocated by this system note: never use more than this, even if more are available (only this many advanced particles are allocated)
|
|
uint32_t availableParticles; // number of particles available for use (can be more or less than numParticles, assigned by memory manager)
|
|
uint8_t fractionOfParticlesUsed; // percentage of particles used in the system (255=100%), used during transition updates
|
|
uint32_t emitIndex; // index to count through particles to emit so searching for dead pixels is faster
|
|
int32_t collisionHardness;
|
|
uint32_t particleHardRadius; // hard surface radius of a particle, used for collision detection
|
|
uint32_t wallHardness;
|
|
uint8_t gforcecounter; // counter for global gravity
|
|
int8_t gforce; // gravity strength, default is 8 (negative is allowed, positive is downwards)
|
|
uint8_t forcecounter; // counter for globally applied forces
|
|
uint16_t collisionStartIdx; // particle array start index for collision detection
|
|
//global particle properties for basic particles
|
|
uint8_t particlesize; // global particle size, 0 = 1 pixel, 1 = 2 pixels
|
|
uint8_t motionBlur; // enable motion blur, values > 100 gives smoother animations
|
|
uint8_t smearBlur; // smeared blurring of full frame
|
|
uint8_t effectID; // ID of the effect that is using this particle system, used for transitions
|
|
uint32_t lastRender; // last time the particles were rendered, intermediate fix for speedup
|
|
};
|
|
|
|
bool initParticleSystem1D(ParticleSystem1D *&PartSys, const uint32_t requestedsources, const uint8_t fractionofparticles = 255, const uint32_t additionalbytes = 0, const bool advanced = false);
|
|
uint32_t calculateNumberOfParticles1D(const uint32_t fraction, const bool isadvanced);
|
|
uint32_t calculateNumberOfSources1D(const uint32_t requestedsources);
|
|
bool allocateParticleSystemMemory1D(const uint32_t numparticles, const uint32_t numsources, const bool isadvanced, const uint32_t additionalbytes);
|
|
void blur1D(CRGB *colorbuffer, uint32_t size, uint32_t blur, uint32_t start);
|
|
#endif // WLED_DISABLE_PARTICLESYSTEM1D
|