Adding Particle System (port from AC)
- port from AC - also adding hardware random functions
This commit is contained in:
2806
wled00/FX.cpp
2806
wled00/FX.cpp
File diff suppressed because it is too large
Load Diff
54
wled00/FX.h
54
wled00/FX.h
@@ -324,20 +324,50 @@ bool strip_uses_global_leds(void) __attribute__((pure)); // WLEDMM implemented
|
||||
#define FX_MODE_WAVESINS 184
|
||||
#define FX_MODE_ROCKTAVES 185
|
||||
#define FX_MODE_2DAKEMI 186
|
||||
#define FX_MODE_ARTIFX 187 //WLEDMM ARTIFX
|
||||
#define FX_MODE_PARTYJERK 188
|
||||
#define FX_MODE_PARTICLEVOLCANO 187
|
||||
#define FX_MODE_PARTICLEFIRE 188
|
||||
#define FX_MODE_PARTICLEFIREWORKS 189
|
||||
#define FX_MODE_PARTICLEVORTEX 190
|
||||
#define FX_MODE_PARTICLEPERLIN 191
|
||||
#define FX_MODE_PARTICLEPIT 192
|
||||
#define FX_MODE_PARTICLEBOX 193
|
||||
#define FX_MODE_PARTICLEATTRACTOR 194
|
||||
#define FX_MODE_PARTICLEIMPACT 195
|
||||
#define FX_MODE_PARTICLEWATERFALL 196
|
||||
#define FX_MODE_PARTICLESPRAY 197
|
||||
#define FX_MODE_PARTICLESGEQ 198
|
||||
#define FX_MODE_PARTICLECENTERGEQ 199
|
||||
#define FX_MODE_PARTICLEGHOSTRIDER 200
|
||||
#define FX_MODE_PARTICLEBLOBS 201
|
||||
#define FX_MODE_PSDRIP 202
|
||||
#define FX_MODE_PSPINBALL 203
|
||||
#define FX_MODE_PSDANCINGSHADOWS 204
|
||||
#define FX_MODE_PSFIREWORKS1D 205
|
||||
#define FX_MODE_PSSPARKLER 206
|
||||
#define FX_MODE_PSHOURGLASS 207
|
||||
#define FX_MODE_PS1DSPRAY 208
|
||||
#define FX_MODE_PSBALANCE 209
|
||||
#define FX_MODE_PSCHASE 210
|
||||
#define FX_MODE_PSSTARBURST 211
|
||||
#define FX_MODE_PS1DGEQ 212
|
||||
#define FX_MODE_PSFIRE1D 213
|
||||
#define FX_MODE_PS1DSONICSTREAM 214
|
||||
#define FX_MODE_PS1DSONICBOOM 215
|
||||
#define FX_MODE_PS1DSPRINGY 216
|
||||
#define FX_MODE_ARTIFX 217 //WLEDMM ARTIFX
|
||||
#define FX_MODE_PARTYJERK 218
|
||||
|
||||
// Experimental Audioresponsive modes from WLED-SR
|
||||
// #define FX_MODE_3DSphereMove 189 // experimental WLED-SR "cube" mode
|
||||
#define FX_MODE_POPCORN_AR 190 // WLED-SR audioreactive popcorn
|
||||
#define FX_MODE_MULTI_COMET_AR 191 // WLED-SR audioreactive multi-comet
|
||||
#define FX_MODE_STARBURST_AR 192 // WLED-SR audioreactive fireworks starburst
|
||||
// #define FX_MODE_PALETTE_AR 193 // WLED-SR audioreactive palette
|
||||
#define FX_MODE_FIREWORKS_AR 194 // WLED-SR audioreactive fireworks
|
||||
#define FX_MODE_GEQLASER 195 // WLED-MM GEQ Laser
|
||||
#define FX_MODE_2DPAINTBRUSH 196 // WLED-MM Paintbrush
|
||||
#define FX_MODE_2DSNOWFALL 197 // WLED-MM Snowfall
|
||||
#define MODE_COUNT 198
|
||||
// #define FX_MODE_3DSphereMove 219 // experimental WLED-SR "cube" mode
|
||||
#define FX_MODE_POPCORN_AR 220 // WLED-SR audioreactive popcorn
|
||||
#define FX_MODE_MULTI_COMET_AR 221 // WLED-SR audioreactive multi-comet
|
||||
#define FX_MODE_STARBURST_AR 222 // WLED-SR audioreactive fireworks starburst
|
||||
// #define FX_MODE_PALETTE_AR 223 // WLED-SR audioreactive palette
|
||||
#define FX_MODE_FIREWORKS_AR 224 // WLED-SR audioreactive fireworks
|
||||
#define FX_MODE_GEQLASER 225 // WLED-MM GEQ Laser
|
||||
#define FX_MODE_2DPAINTBRUSH 226 // WLED-MM Paintbrush
|
||||
#define FX_MODE_2DSNOWFALL 227 // WLED-MM Snowfall
|
||||
#define MODE_COUNT 228
|
||||
|
||||
typedef enum mapping1D2D {
|
||||
M12_Pixels = 0,
|
||||
|
||||
1896
wled00/FXparticleSystem.cpp
Normal file
1896
wled00/FXparticleSystem.cpp
Normal file
File diff suppressed because it is too large
Load Diff
388
wled00/FXparticleSystem.h
Normal file
388
wled00/FXparticleSystem.h
Normal file
@@ -0,0 +1,388 @@
|
||||
/*
|
||||
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) 2025 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
|
||||
|
||||
// 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 256 // enough up to 16x16 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%
|
||||
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 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
|
||||
CRGB *framebuffer; // local frame buffer for rendering
|
||||
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
|
||||
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 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
|
||||
};
|
||||
|
||||
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 320
|
||||
#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%
|
||||
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 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
|
||||
CRGB *framebuffer; // local frame buffer for rendering
|
||||
PSsettings1D particlesettings; // settings used when updating particles
|
||||
uint32_t numParticles; // total number of particles allocated by this system
|
||||
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
|
||||
};
|
||||
|
||||
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
|
||||
@@ -398,6 +398,29 @@ uint8_t get_random_wheel_index(uint8_t pos);
|
||||
CRGB getCRGBForBand(int x, uint8_t *fftResult, int pal); //WLEDMM netmindz ar palette
|
||||
char *cleanUpName(char *in); // to clean up a name that was read from file
|
||||
|
||||
// fast (true) random numbers using hardware RNG, all functions return values in the range lowerlimit to upperlimit-1
|
||||
// note: for true random numbers with high entropy, do not call faster than every 200ns (5MHz)
|
||||
// tests show it is still highly random reading it quickly in a loop (better than fastled PRNG)
|
||||
// for 8bit and 16bit random functions: no limit check is done for best speed
|
||||
// 32bit inputs are used for speed and code size, limits don't work if inverted or out of range
|
||||
// inlining does save code size except for random(a,b) and 32bit random with limits
|
||||
#ifdef ESP8266
|
||||
#define HW_RND_REGISTER RANDOM_REG32
|
||||
#else // ESP32 family
|
||||
#include "soc/wdev_reg.h"
|
||||
#define HW_RND_REGISTER REG_READ(WDEV_RND_REG)
|
||||
#endif
|
||||
#define random hw_random // replace arduino random()
|
||||
inline uint32_t hw_random() { return HW_RND_REGISTER; };
|
||||
uint32_t hw_random(uint32_t upperlimit); // not inlined for code size
|
||||
int32_t hw_random(int32_t lowerlimit, int32_t upperlimit);
|
||||
inline uint16_t hw_random16() { return HW_RND_REGISTER; };
|
||||
inline uint16_t hw_random16(uint32_t upperlimit) { return (hw_random16() * upperlimit) >> 16; }; // input range 0-65535 (uint16_t)
|
||||
inline int16_t hw_random16(int32_t lowerlimit, int32_t upperlimit) { int32_t range = upperlimit - lowerlimit; return lowerlimit + hw_random16(range); }; // signed limits, use int16_t ranges
|
||||
inline uint8_t hw_random8() { return HW_RND_REGISTER; };
|
||||
inline uint8_t hw_random8(uint32_t upperlimit) { return (hw_random8() * upperlimit) >> 8; }; // input range 0-255
|
||||
inline uint8_t hw_random8(uint32_t lowerlimit, uint32_t upperlimit) { uint32_t range = upperlimit - lowerlimit; return lowerlimit + hw_random8(range); }; // input range 0-255
|
||||
|
||||
// RAII guard class for the JSON Buffer lock
|
||||
// Modeled after std::lock_guard
|
||||
class JSONBufferGuard {
|
||||
|
||||
@@ -653,3 +653,18 @@ char *cleanUpName(char *in) {
|
||||
|
||||
return(in);
|
||||
}
|
||||
|
||||
// 32 bit hardware random number generator, inlining uses more code, use hw_random16() if speed is critical (see fcn_declare.h)
|
||||
uint32_t hw_random(uint32_t upperlimit) {
|
||||
uint32_t rnd = hw_random();
|
||||
uint64_t scaled = uint64_t(rnd) * uint64_t(upperlimit);
|
||||
return scaled >> 32;
|
||||
}
|
||||
|
||||
int32_t hw_random(int32_t lowerlimit, int32_t upperlimit) {
|
||||
if(lowerlimit >= upperlimit) {
|
||||
return lowerlimit;
|
||||
}
|
||||
uint32_t diff = upperlimit - lowerlimit;
|
||||
return hw_random(diff) + lowerlimit;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user