Skip to content

Commit 3538684

Browse files
authored
Removed PS memory manager and some minor improvements (wled#4651)
* Removed memory manager from PS - reverted all changes related to memory manager - moved local buffer into effect data memory - some RAM issues may occur on larger setups: tested on S3 it works fine up to 32x32 but runs into memory issues at 64x32 * fixed ifdef, improved readability, add optimize "o2" flags to improve speed - added struct for x and y coordinates, thx to @blazoncek * cleanup and minor improvements - removed local buffer for ESP8266 in 1D system to save on RAM - increased particle brightness in PS Impact - minor tweak in collision binning (might improve speed) - removed comments and some other unused stuff - fixed a few compiler wranings * fixed init sequence bug
1 parent c661d8f commit 3538684

File tree

4 files changed

+222
-771
lines changed

4 files changed

+222
-771
lines changed

wled00/FX.cpp

Lines changed: 38 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7998,7 +7998,7 @@ uint16_t mode_particlefire(void) {
79987998
uint32_t i; // index variable
79997999
uint32_t numFlames; // number of flames: depends on fire width. for a fire width of 16 pixels, about 25-30 flames give good results
80008000

8001-
if (SEGMENT.call == 0) { // initialization TODO: make this a PSinit function, this is needed in every particle FX but first, get this working.
8001+
if (SEGMENT.call == 0) { // initialization
80028002
if (!initParticleSystem2D(PartSys, SEGMENT.virtualWidth(), 4)) //maximum number of source (PS may limit based on segment size); need 4 additional bytes for time keeping (uint32_t lastcall)
80038003
return mode_static(); // allocation failed or not 2D
80048004
SEGENV.aux0 = hw_random16(); // aux0 is wind position (index) in the perlin noise
@@ -8090,7 +8090,7 @@ uint16_t mode_particlepit(void) {
80908090
ParticleSystem2D *PartSys = nullptr;
80918091

80928092
if (SEGMENT.call == 0) { // initialization
8093-
if (!initParticleSystem2D(PartSys, 1, 0, true, false)) // init, request one source (actually dont really need one TODO: test if using zero sources also works)
8093+
if (!initParticleSystem2D(PartSys, 0, 0, true, false)) // init
80948094
return mode_static(); // allocation failed or not 2D
80958095
PartSys->setKillOutOfBounds(true);
80968096
PartSys->setGravity(); // enable with default gravity
@@ -8161,7 +8161,7 @@ uint16_t mode_particlewaterfall(void) {
81618161
uint8_t numSprays;
81628162
uint32_t i = 0;
81638163

8164-
if (SEGMENT.call == 0) { // initialization TODO: make this a PSinit function, this is needed in every particle FX but first, get this working.
8164+
if (SEGMENT.call == 0) { // initialization
81658165
if (!initParticleSystem2D(PartSys, 12)) // init, request 12 sources, no additional data needed
81668166
return mode_static(); // allocation failed or not 2D
81678167

@@ -8184,7 +8184,7 @@ uint16_t mode_particlewaterfall(void) {
81848184
else
81858185
PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS
81868186
if (PartSys == nullptr)
8187-
return mode_static(); // something went wrong, no data! (TODO: ask how to handle this so it always works)
8187+
return mode_static(); // something went wrong, no data!
81888188

81898189
// Particle System settings
81908190
PartSys->updateSystem(); // update system properties (dimensions and data pointers)
@@ -8313,7 +8313,7 @@ uint16_t mode_particleperlin(void) {
83138313
ParticleSystem2D *PartSys = nullptr;
83148314
uint32_t i;
83158315

8316-
if (SEGMENT.call == 0) { // initialization TODO: make this a PSinit function, this is needed in every particle FX but first, get this working.
8316+
if (SEGMENT.call == 0) { // initialization
83178317
if (!initParticleSystem2D(PartSys, 1, 0, true)) // init with 1 source and advanced properties
83188318
return mode_static(); // allocation failed or not 2D
83198319

@@ -8374,20 +8374,19 @@ static const char _data_FX_MODE_PARTICLEPERLIN[] PROGMEM = "PS Fuzzy Noise@Speed
83748374
uint16_t mode_particleimpact(void) {
83758375
ParticleSystem2D *PartSys = nullptr;
83768376
uint32_t i = 0;
8377-
uint8_t MaxNumMeteors;
8377+
uint32_t numMeteors;
83788378
PSsettings2D meteorsettings;
83798379
meteorsettings.asByte = 0b00101000; // PS settings for meteors: bounceY and gravity enabled
83808380

8381-
if (SEGMENT.call == 0) { // initialization TODO: make this a PSinit function, this is needed in every particle FX but first, get this working.
8381+
if (SEGMENT.call == 0) { // initialization
83828382
if (!initParticleSystem2D(PartSys, NUMBEROFSOURCES)) // init, no additional data needed
83838383
return mode_static(); // allocation failed or not 2D
83848384
PartSys->setKillOutOfBounds(true);
83858385
PartSys->setGravity(); // enable default gravity
83868386
PartSys->setBounceY(true); // always use ground bounce
83878387
PartSys->setWallRoughness(220); // high roughness
8388-
MaxNumMeteors = min(PartSys->numSources, (uint32_t)NUMBEROFSOURCES);
8389-
for (i = 0; i < MaxNumMeteors; i++) {
8390-
// PartSys->sources[i].source.y = 500;
8388+
numMeteors = min(PartSys->numSources, (uint32_t)NUMBEROFSOURCES);
8389+
for (i = 0; i < numMeteors; i++) {
83918390
PartSys->sources[i].source.ttl = hw_random16(10 * i); // set initial delay for meteors
83928391
PartSys->sources[i].source.vy = 10; // at positive speeds, no particles are emitted and if particle dies, it will be relaunched
83938392
}
@@ -8396,7 +8395,7 @@ uint16_t mode_particleimpact(void) {
83968395
PartSys = reinterpret_cast<ParticleSystem2D *>(SEGENV.data); // if not first call, just set the pointer to the PS
83978396

83988397
if (PartSys == nullptr)
8399-
return mode_static(); // something went wrong, no data! (TODO: ask how to handle this so it always works)
8398+
return mode_static(); // something went wrong, no data!
84008399

84018400
// Particle System settings
84028401
PartSys->updateSystem(); // update system properties (dimensions and data pointers)
@@ -8406,29 +8405,18 @@ uint16_t mode_particleimpact(void) {
84068405
uint8_t hardness = map(SEGMENT.custom2, 0, 255, PS_P_MINSURFACEHARDNESS - 2, 255);
84078406
PartSys->setWallHardness(hardness);
84088407
PartSys->enableParticleCollisions(SEGMENT.check3, hardness); // enable collisions and set particle collision hardness
8409-
MaxNumMeteors = min(PartSys->numSources, (uint32_t)NUMBEROFSOURCES);
8410-
uint8_t numMeteors = MaxNumMeteors; // TODO: clean this up map(SEGMENT.custom3, 0, 31, 1, MaxNumMeteors); // number of meteors to use for animation
8411-
8408+
numMeteors = min(PartSys->numSources, (uint32_t)NUMBEROFSOURCES);
84128409
uint32_t emitparticles; // number of particles to emit for each rocket's state
84138410

84148411
for (i = 0; i < numMeteors; i++) {
84158412
// determine meteor state by its speed:
8416-
if ( PartSys->sources[i].source.vy < 0) { // moving down, emit sparks
8417-
#ifdef ESP8266
8413+
if ( PartSys->sources[i].source.vy < 0) // moving down, emit sparks
84188414
emitparticles = 1;
8419-
#else
8420-
emitparticles = 2;
8421-
#endif
8422-
}
84238415
else if ( PartSys->sources[i].source.vy > 0) // moving up means meteor is on 'standby'
84248416
emitparticles = 0;
84258417
else { // speed is zero, explode!
84268418
PartSys->sources[i].source.vy = 10; // set source speed positive so it goes into timeout and launches again
8427-
#ifdef ESP8266
8428-
emitparticles = hw_random16(SEGMENT.intensity >> 3) + 5; // defines the size of the explosion
8429-
#else
8430-
emitparticles = map(SEGMENT.intensity, 0, 255, 10, hw_random16(PartSys->usedParticles>>2)); // defines the size of the explosion !!!TODO: check if this works on ESP8266, drop esp8266 def if it does
8431-
#endif
8419+
emitparticles = map(SEGMENT.intensity, 0, 255, 10, hw_random16(PartSys->usedParticles>>2)); // defines the size of the explosion
84328420
}
84338421
for (int e = emitparticles; e > 0; e--) {
84348422
PartSys->sprayEmit(PartSys->sources[i]);
@@ -8449,13 +8437,13 @@ uint16_t mode_particleimpact(void) {
84498437
PartSys->sources[i].source.vx = 0;
84508438
PartSys->sources[i].sourceFlags.collide = true;
84518439
#ifdef ESP8266
8452-
PartSys->sources[i].maxLife = 180;
8453-
PartSys->sources[i].minLife = 20;
8440+
PartSys->sources[i].maxLife = 900;
8441+
PartSys->sources[i].minLife = 100;
84548442
#else
8455-
PartSys->sources[i].maxLife = 250;
8456-
PartSys->sources[i].minLife = 50;
8443+
PartSys->sources[i].maxLife = 1250;
8444+
PartSys->sources[i].minLife = 250;
84578445
#endif
8458-
PartSys->sources[i].source.ttl = hw_random16((512 - (SEGMENT.speed << 1))) + 40; // standby time til next launch (in frames)
8446+
PartSys->sources[i].source.ttl = hw_random16((768 - (SEGMENT.speed << 1))) + 40; // standby time til next launch (in frames)
84598447
PartSys->sources[i].vy = (SEGMENT.custom1 >> 2); // emitting speed y
84608448
PartSys->sources[i].var = (SEGMENT.custom1 >> 2); // speed variation around vx,vy (+/- var)
84618449
}
@@ -8470,13 +8458,17 @@ uint16_t mode_particleimpact(void) {
84708458
PartSys->sources[i].source.hue = hw_random16(); // random color
84718459
PartSys->sources[i].source.ttl = 500; // long life, will explode at bottom
84728460
PartSys->sources[i].sourceFlags.collide = false; // trail particles will not collide
8473-
PartSys->sources[i].maxLife = 60; // spark particle life
8474-
PartSys->sources[i].minLife = 20;
8461+
PartSys->sources[i].maxLife = 300; // spark particle life
8462+
PartSys->sources[i].minLife = 100;
84758463
PartSys->sources[i].vy = -9; // emitting speed (down)
84768464
PartSys->sources[i].var = 3; // speed variation around vx,vy (+/- var)
84778465
}
84788466
}
84798467

8468+
for (uint32_t i = 0; i < PartSys->usedParticles; i++) {
8469+
if (PartSys->particles[i].ttl > 5) PartSys->particles[i].ttl -= 5; //ttl is linked to brightness, this allows to use higher brightness but still a short spark lifespan
8470+
}
8471+
84808472
PartSys->update(); // update and render
84818473
return FRAMETIME;
84828474
}
@@ -8880,7 +8872,7 @@ uint16_t mode_particleghostrider(void) {
88808872
// emit two particles
88818873
PartSys->angleEmit(PartSys->sources[0], emitangle, speed);
88828874
PartSys->angleEmit(PartSys->sources[0], emitangle, speed);
8883-
if (SEGMENT.call % (11 - (SEGMENT.custom2 / 25)) == 0) { // every nth frame, cycle color and emit particles //TODO: make this a segment call % SEGMENT.custom2 for better control
8875+
if (SEGMENT.call % (11 - (SEGMENT.custom2 / 25)) == 0) { // every nth frame, cycle color and emit particles
88848876
PartSys->sources[0].source.hue++;
88858877
}
88868878
if (SEGMENT.custom2 > 190) //fast color change
@@ -8900,7 +8892,7 @@ uint16_t mode_particleblobs(void) {
89008892
ParticleSystem2D *PartSys = nullptr;
89018893

89028894
if (SEGMENT.call == 0) {
8903-
if (!initParticleSystem2D(PartSys, 1, 0, true, true)) //init, request one source, no additional bytes, advanced size & size control (actually dont really need one TODO: test if using zero sources also works)
8895+
if (!initParticleSystem2D(PartSys, 0, 0, true, true)) //init, no additional bytes, advanced size & size control
89048896
return mode_static(); // allocation failed or not 2D
89058897
PartSys->setBounceX(true);
89068898
PartSys->setBounceY(true);
@@ -9521,8 +9513,8 @@ uint16_t mode_particleHourglass(void) {
95219513

95229514
uint32_t colormode = SEGMENT.custom1 >> 5; // 0-7
95239515

9524-
if ((SEGMENT.intensity | (PartSys->getAvailableParticles() << 8)) != *settingTracker) { // initialize, getAvailableParticles changes while in FX transition
9525-
*settingTracker = SEGMENT.intensity | (PartSys->getAvailableParticles() << 8);
9516+
if (SEGMENT.intensity != *settingTracker) { // initialize
9517+
*settingTracker = SEGMENT.intensity;
95269518
for (uint32_t i = 0; i < PartSys->usedParticles; i++) {
95279519
PartSys->particleFlags[i].reversegrav = true; // resting particles dont fall
95289520
*direction = 0; // down
@@ -9569,7 +9561,7 @@ uint16_t mode_particleHourglass(void) {
95699561
}
95709562

95719563
// re-order particles in case collisions flipped particles (highest number index particle is on the "bottom")
9572-
for (int i = 0; i < PartSys->usedParticles - 1; i++) {
9564+
for (uint32_t i = 0; i < PartSys->usedParticles - 1; i++) {
95739565
if (PartSys->particles[i].x < PartSys->particles[i+1].x && PartSys->particleFlags[i].fixed == false && PartSys->particleFlags[i+1].fixed == false) {
95749566
std::swap(PartSys->particles[i].x, PartSys->particles[i+1].x);
95759567
}
@@ -9680,10 +9672,7 @@ uint16_t mode_particleBalance(void) {
96809672
if (SEGMENT.call == 0) { // initialization
96819673
if (!initParticleSystem1D(PartSys, 1, 128)) // init, no additional data needed, use half of max particles
96829674
return mode_static(); // allocation failed or is single pixel
9683-
//PartSys->setKillOutOfBounds(true);
96849675
PartSys->setParticleSize(1);
9685-
SEGENV.aux0 = 0;
9686-
SEGENV.aux1 = 0; //TODO: really need to set to zero or is it calloc'd?
96879676
}
96889677
else
96899678
PartSys = reinterpret_cast<ParticleSystem1D *>(SEGENV.data); // if not first call, just set the pointer to the PS
@@ -9777,7 +9766,7 @@ uint16_t mode_particleChase(void) {
97779766
uint32_t numParticles = 1 + map(SEGMENT.intensity, 0, 255, 2, 255 / (1 + (SEGMENT.custom1 >> 6))); // depends on intensity and particle size (custom1), minimum 1
97789767
numParticles = min(numParticles, PartSys->usedParticles); // limit to available particles
97799768
int32_t huestep = 1 + ((((uint32_t)SEGMENT.custom2 << 19) / numParticles) >> 16); // hue increment
9780-
uint32_t settingssum = SEGMENT.speed + SEGMENT.intensity + SEGMENT.custom1 + SEGMENT.custom2 + SEGMENT.check1 + SEGMENT.check2 + SEGMENT.check3 + PartSys->getAvailableParticles(); // note: getAvailableParticles is used to enforce update during transitions
9769+
uint32_t settingssum = SEGMENT.speed + SEGMENT.intensity + SEGMENT.custom1 + SEGMENT.custom2 + SEGMENT.check1 + SEGMENT.check2 + SEGMENT.check3;
97819770
if (SEGENV.aux0 != settingssum) { // settings changed changed, update
97829771
if (SEGMENT.check1)
97839772
SEGENV.step = PartSys->advPartProps[0].size / 2 + (PartSys->maxX / numParticles);
@@ -9835,7 +9824,7 @@ uint16_t mode_particleChase(void) {
98359824
globalhuestep = 2; // global hue change to add some color variation
98369825
if ((SEGMENT.call & 0x1F) == 0)
98379826
SEGENV.step += *stepdir; // change density
9838-
for(int32_t i = 0; i < PartSys->usedParticles; i++) {
9827+
for(uint32_t i = 0; i < PartSys->usedParticles; i++) {
98399828
PartSys->particles[i].hue -= globalhuestep; // shift global hue (both directions)
98409829
PartSys->particles[i].vx = 1 + (SEGMENT.speed >> 2) + ((int32_t(sin16_t(strip.now >> 1) + 32767) * (SEGMENT.speed >> 2)) >> 16);
98419830
}
@@ -10007,7 +9996,7 @@ uint16_t mode_particleFire1D(void) {
100079996
PartSys->setColorByAge(true);
100089997
uint32_t emitparticles = 1;
100099998
uint32_t j = hw_random16();
10010-
for (uint i = 0; i < 3; i++) { // 3 base flames TODO: check if this is ok or needs adjustments
9999+
for (uint i = 0; i < 3; i++) { // 3 base flames
1001110000
if (PartSys->sources[i].source.ttl > 50)
1001210001
PartSys->sources[i].source.ttl -= 10; // TODO: in 2D making the source fade out slow results in much smoother flames, need to check if it can be done the same
1001310002
else
@@ -10028,7 +10017,7 @@ uint16_t mode_particleFire1D(void) {
1002810017
}
1002910018
}
1003010019
else {
10031-
PartSys->sources[j].minLife = PartSys->sources[j].source.ttl + SEGMENT.intensity; // TODO: in 2D, emitted particle ttl depends on source TTL, mimic here the same way? OR: change 2D to the same way it is done here and ditch special fire treatment in emit?
10020+
PartSys->sources[j].minLife = PartSys->sources[j].source.ttl + SEGMENT.intensity;
1003210021
PartSys->sources[j].maxLife = PartSys->sources[j].minLife + 50;
1003310022
PartSys->sources[j].v = SEGMENT.speed >> 2;
1003410023
if (SEGENV.call & 0x01) // every second frame
@@ -10266,7 +10255,7 @@ uint16_t mode_particleSpringy(void) {
1026610255
int32_t springlength = PartSys->maxX / (PartSys->usedParticles); // spring length (spacing between particles)
1026710256
int32_t springK = map(SEGMENT.speed, 0, 255, 5, 35); // spring constant (stiffness)
1026810257

10269-
uint32_t settingssum = SEGMENT.custom1 + SEGMENT.check2 + PartSys->getAvailableParticles(); // note: getAvailableParticles is used to enforce update during transitions
10258+
uint32_t settingssum = SEGMENT.custom1 + SEGMENT.check2;
1027010259
if (SEGENV.aux0 != settingssum) { // number of particles changed, update distribution
1027110260
for (int32_t i = 0; i < (int32_t)PartSys->usedParticles; i++) {
1027210261
PartSys->advPartProps[i].sat = 255; // full saturation
@@ -10289,7 +10278,7 @@ uint16_t mode_particleSpringy(void) {
1028910278
PartSys->particles[0].x = dxlimit; // limit the spring length
1029010279
springforce[0] += ((springlength >> 1) - (PartSys->particles[0].x)) * springK; // first particle anchors to x=0
1029110280

10292-
for (int32_t i = 1; i < PartSys->usedParticles; i++) {
10281+
for (uint32_t i = 1; i < PartSys->usedParticles; i++) {
1029310282
// reorder particles if they are out of order to prevent chaos
1029410283
if (PartSys->particles[i].x < PartSys->particles[i-1].x)
1029510284
std::swap(PartSys->particles[i].x, PartSys->particles[i-1].x); // swap particle positions to maintain order
@@ -10310,7 +10299,7 @@ uint16_t mode_particleSpringy(void) {
1031010299
}
1031110300
// apply spring forces to particles
1031210301
bool dampenoscillations = (SEGMENT.call % (9 - (SEGMENT.speed >> 5))) == 0; // dampen oscillation if particles are slow, more damping on stiffer springs
10313-
for (int32_t i = 0; i < PartSys->usedParticles; i++) {
10302+
for (uint32_t i = 0; i < PartSys->usedParticles; i++) {
1031410303
springforce[i] = springforce[i] / 64; // scale spring force (cannot use shifts because of negative values)
1031510304
int maxforce = 120; // limit spring force
1031610305
springforce[i] = springforce[i] > maxforce ? maxforce : springforce[i] < -maxforce ? -maxforce : springforce[i]; // limit spring force
@@ -10327,7 +10316,7 @@ uint16_t mode_particleSpringy(void) {
1032710316
PartSys->applyFriction((SEGMENT.intensity >> 2));
1032810317

1032910318
// add a small resetting force so particles return to resting position even under high damping
10330-
for (int32_t i = 1; i < PartSys->usedParticles - 1; i++) {
10319+
for (uint32_t i = 1; i < PartSys->usedParticles - 1; i++) {
1033110320
int restposition = (springlength >> 1) + i * springlength; // resting position
1033210321
int dx = restposition - PartSys->particles[i].x; // distance, always positive
1033310322
PartSys->applyForce(PartSys->particles[i], dx > 0 ? 1 : (dx < 0 ? -1 : 0), PartSys->advPartProps[i].forcecounter);
@@ -10377,7 +10366,7 @@ uint16_t mode_particleSpringy(void) {
1037710366
}
1037810367
}
1037910368

10380-
for (int32_t i = 0; i < PartSys->usedParticles; i++) {
10369+
for (uint32_t i = 0; i < PartSys->usedParticles; i++) {
1038110370
if (SEGMENT.custom2 == 255) { // map speed to hue
1038210371
int speedclr = ((int8_t(abs(PartSys->particles[i].vx))) >> 2) << 4; // scale for greater color variation, dump small values to avoid flickering
1038310372
//int speed = PartSys->particles[i].vx << 2; // +/- 512

wled00/FX_fcn.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,9 +1665,6 @@ void WS2812FX::service() {
16651665
_segment_index++;
16661666
}
16671667
Segment::setClippingRect(0, 0); // disable clipping for overlays
1668-
#if !(defined(WLED_DISABLE_PARTICLESYSTEM2D) && defined(WLED_DISABLE_PARTICLESYSTEM1D))
1669-
servicePSmem(); // handle segment particle system memory
1670-
#endif
16711668
_isServicing = false;
16721669
_triggered = false;
16731670

0 commit comments

Comments
 (0)