Skip to content

Commit 18c79ce

Browse files
committed
Added saturation to be set for each particle individually
at the expense of more ram usage, animations now have more options for color control (already used in fireworks now)
1 parent a147a4b commit 18c79ce

File tree

3 files changed

+39
-23
lines changed

3 files changed

+39
-23
lines changed

wled00/FX.cpp

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7915,11 +7915,12 @@ uint16_t mode_particlerotatingspray(void)
79157915
SEGMENT.aux0 = 0; // starting angle
79167916
for (i = 0; i < numParticles; i++)
79177917
{
7918-
particles[i].ttl = 0;
7918+
particles[i].ttl = 0;
79197919
}
79207920
for (i = 0; i < numSprays; i++)
79217921
{
79227922
spray[i].source.hue = random8();
7923+
spray[i].source.sat = 255; // set saturation
79237924
spray[i].source.x = (cols * PS_P_RADIUS) / 2; // center
79247925
spray[i].source.y = (cols * PS_P_RADIUS) / 2; // center
79257926
spray[i].source.vx = 0;
@@ -7980,7 +7981,7 @@ uint16_t mode_particlerotatingspray(void)
79807981
SEGMENT.fill(BLACK); // clear the matrix
79817982

79827983
// render the particles
7983-
ParticleSys_render(particles, numParticles, 255, false, false);
7984+
ParticleSys_render(particles, numParticles, false, false);
79847985

79857986
return FRAMETIME;
79867987
}
@@ -8070,7 +8071,7 @@ uint16_t mode_particlefireworks(void)
80708071
rockets[j].source.vy = -1; // set speed negative so it will emit no more particles after this explosion until relaunch
80718072
if (j == 0) // first rocket, do an angle emit
80728073
{
8073-
emitparticles>>1; //emit less particles for circle-explosion
8074+
emitparticles>>2; //emit less particles for circle-explosion
80748075
rockets[j].maxLife = 150;
80758076
rockets[j].minLife = 120;
80768077
rockets[j].var = 0; // speed variation around vx,vy (+/- var/2)
@@ -8095,6 +8096,8 @@ uint16_t mode_particlefireworks(void)
80958096
{
80968097
angle = 0;
80978098
speed += 8;
8099+
rockets[j].source.hue = random8(); //new color for next row
8100+
rockets[j].source.sat = random8();
80988101
}
80998102
}
81008103
else if (emitparticles > 0)
@@ -8132,6 +8135,7 @@ uint16_t mode_particlefireworks(void)
81328135
{ // rocket has died and is moving up. stop it so it will explode (is handled in the code above)
81338136
rockets[i].source.vy = 0; // set speed to zero so code above will recognize this as an exploding rocket
81348137
rockets[i].source.hue = random8(); // random color
8138+
rockets[i].source.sat = random8(100)+155;
81358139
rockets[i].maxLife = 200;
81368140
rockets[i].minLife = 50;
81378141
rockets[i].source.ttl = random8((255 - SEGMENT.speed))+10; // standby time til next launch (in frames at 42fps, max of 265 is about 6 seconds
@@ -8147,6 +8151,7 @@ uint16_t mode_particlefireworks(void)
81478151
rockets[i].source.vy = random8(SEGMENT.custom1>>3) + 5; //rocket speed depends also on rocket height
81488152
rockets[i].source.vx = random8(5) - 2;
81498153
rockets[i].source.hue = 30; // rocket exhaust = orange (if using rainbow palette)
8154+
rockets[i].source.sat = 250;
81508155
rockets[i].source.ttl = random8(SEGMENT.custom1) + (SEGMENT.custom1>>1); // sets explosion height (rockets explode at the top if set too high as paticle update set speed to zero if moving out of matrix)
81518156
rockets[i].maxLife = 30; //exhaust particle life
81528157
rockets[i].minLife = 10;
@@ -8158,7 +8163,7 @@ uint16_t mode_particlefireworks(void)
81588163
SEGMENT.fill(BLACK); // clear the matrix
81598164

81608165
// render the particles
8161-
ParticleSys_render(particles, numParticles, 255, false, false);
8166+
ParticleSys_render(particles, numParticles, false, false);
81628167

81638168
return FRAMETIME;
81648169
}
@@ -8207,11 +8212,12 @@ uint16_t mode_particlespray(void)
82078212
{
82088213
for (i = 0; i < numParticles; i++)
82098214
{
8210-
particles[i].ttl = 0;
8215+
particles[i].ttl = 0;
82118216
}
82128217
for (i = 0; i < numSprays; i++)
82138218
{
82148219
spray[i].source.hue = random8();
8220+
spray[i].source.sat = 255; // set full saturation
82158221
spray[i].source.x = 4 * PS_P_RADIUS * (i + 1);
82168222
spray[i].source.y = 5; // just above the lower edge, if zero, particles already 'bounce' at start and loose speed.
82178223
spray[i].source.vx = 10;
@@ -8283,7 +8289,7 @@ uint16_t mode_particlespray(void)
82838289
SEGMENT.fill(BLACK); // clear the matrix
82848290

82858291
// render the particles
8286-
ParticleSys_render(particles, numParticles, 255, SEGMENT.check1, false);
8292+
ParticleSys_render(particles, numParticles, SEGMENT.check1, false);
82878293
// CRGB c = PURPLE;
82888294
// SEGMENT.setPixelColorXY(0, 0, c);
82898295

@@ -8507,7 +8513,7 @@ uint16_t mode_particlefall(void)
85078513
particles[i].ttl = 0;
85088514
}
85098515
}
8510-
8516+
particles[i].sat = ((SEGMENT.custom3) << 3) + 7; // set saturation
85118517
if (SEGMENT.call % (64 - (SEGMENT.intensity >> 2)) == 0 && SEGMENT.intensity > 1) // every nth frame emit particles, stop emitting if zero
85128518
{
85138519
while (i < numParticles) // emit particles
@@ -8526,6 +8532,7 @@ uint16_t mode_particlefall(void)
85268532
particles[i].vx = (((int16_t)random8(SEGMENT.custom1)) - (SEGMENT.custom1 >> 1)) >> 1; // side speed is +/- a quarter of the custom1 slider
85278533
particles[i].vy = -(SEGMENT.speed >> 1);
85288534
particles[i].hue = random8(); // set random color
8535+
particles[i].sat = ((SEGMENT.custom3) << 3) + 7; // set saturation
85298536
break; // quit loop if all particles of this round emitted
85308537
}
85318538
i++;
@@ -8581,8 +8588,10 @@ uint16_t mode_particlefall(void)
85818588

85828589
SEGMENT.fill(BLACK); // clear the matrix
85838590

8591+
8592+
85848593
// render the particles
8585-
ParticleSys_render(particles, numParticles, ((SEGMENT.custom3) << 3) + 7, SEGMENT.check1, false); // custom3 slider is saturation, from 7 to 255, 7 is close enough to white (for snow for example)
8594+
ParticleSys_render(particles, numParticles, SEGMENT.check1, false); // custom3 slider is saturation, from 7 to 255, 7 is close enough to white (for snow for example)
85868595

85878596
return FRAMETIME;
85888597
}
@@ -8627,11 +8636,12 @@ uint16_t mode_particlepile(void)
86278636
{
86288637
for (i = 0; i < numParticles; i++)
86298638
{
8630-
particles[i].ttl = 0;
8639+
particles[i].ttl = 0;
86318640
}
86328641
for (i = 0; i < numSprays; i++)
86338642
{
86348643
spray[i].source.hue = random8();
8644+
spray[i].source.sat = 255; // set full saturation
86358645
spray[i].source.x = 2 * PS_P_RADIUS * (i + 1);
86368646
spray[i].source.y = 14 * PS_P_RADIUS; // source y position, fixed at 14pixel height
86378647
spray[i].source.vx = 10;
@@ -8741,7 +8751,7 @@ uint16_t mode_particlepile(void)
87418751
SEGMENT.fill(BLACK); // clear the matrix
87428752

87438753
// render the particles
8744-
ParticleSys_render(particles, numParticles, 255, SEGMENT.check1, false);
8754+
ParticleSys_render(particles, numParticles, SEGMENT.check1, false);
87458755

87468756
return FRAMETIME;
87478757
}
@@ -8779,8 +8789,9 @@ uint16_t mode_particlebox(void)
87798789
SEGMENT.aux0 = rand(); // position (either in noise or in sine function)
87808790
for (i = 0; i < numParticles; i++)
87818791
{
8782-
particles[i].ttl = 500; // all particles are alive (but not all are calculated/rendered)
8792+
particles[i].ttl = 500; // all particles are alive (but not all are calculated/rendered)
87838793
particles[i].hue = i * 3; // full color range (goes over palette colors three times so it is also colorful when using fewer particles)
8794+
particles[i].sat = 255; // set full saturation (lets palette choose the color)
87848795
particles[i].x = map(i, 0, 255, 1, cols * PS_P_RADIUS); // distribute along x according to color
87858796
particles[i].y = random16((rows >> 2) * PS_P_RADIUS); // in the bottom quarder
87868797
}
@@ -8903,7 +8914,7 @@ uint16_t mode_particlebox(void)
89038914
SEGMENT.fill(BLACK); // clear the matrix
89048915

89058916
// render the particles
8906-
ParticleSys_render(particles, displayparticles, 255, false, false);
8917+
ParticleSys_render(particles, displayparticles, false, false);
89078918

89088919
return FRAMETIME;
89098920
}
@@ -8947,6 +8958,7 @@ uint16_t mode_particleperlin(void)
89478958
particles[i].ttl = random16(500) + 200;
89488959
particles[i].x = random16(cols * PS_P_RADIUS);
89498960
particles[i].y = random16(rows * PS_P_RADIUS);
8961+
particles[i].sat = 255; //full saturation, color set by palette
89508962
}
89518963
}
89528964

@@ -8992,7 +9004,7 @@ uint16_t mode_particleperlin(void)
89929004
SEGMENT.fill(BLACK); // clear the matrix
89939005

89949006
// render the particles
8995-
ParticleSys_render(particles, displayparticles, 255, false, false);
9007+
ParticleSys_render(particles, displayparticles, false, false);
89969008

89979009
return FRAMETIME;
89989010
}
@@ -9036,9 +9048,6 @@ uint16_t mode_particleimpact(void)
90369048
if (!SEGENV.allocateData(dataSize))
90379049
return mode_static(); // allocation failed; //allocation failed
90389050

9039-
// DEBUG_PRINT(F("particle datasize = "));
9040-
// DEBUG_PRINTLN(dataSize);
9041-
90429051
meteors = reinterpret_cast<PSpointsource *>(SEGENV.data);
90439052
// calculate the end of the spray data and assign it as the data pointer for the particles:
90449053
particles = reinterpret_cast<PSparticle *>(meteors + MaxNumMeteors); // cast the data array into a particle pointer
@@ -9057,6 +9066,7 @@ uint16_t mode_particleimpact(void)
90579066
{
90589067
meteors[i].source.ttl = random8(20 * i); // set initial delay for meteors
90599068
meteors[i].source.vy = 10; // at positive speeds, no particles are emitted and if particle dies, it will be relaunched
9069+
meteors[i].source.sat = 255; //full saturation, color chosen by palette
90609070
}
90619071
}
90629072

@@ -9147,7 +9157,7 @@ uint16_t mode_particleimpact(void)
91479157
}
91489158
SEGMENT.fill(BLACK); // clear the matrix
91499159
// render the particles
9150-
ParticleSys_render(particles, numParticles, 255, false, false);
9160+
ParticleSys_render(particles, numParticles, false, false);
91519161

91529162
return FRAMETIME;
91539163
}
@@ -9207,6 +9217,7 @@ uint16_t mode_particleattractor(void)
92079217
}
92089218

92099219
spray->source.hue = random8();
9220+
spray->source.sat = 255; //full saturation, color by palette
92109221
spray->source.x = 0;
92119222
spray->source.y = 0; // just above the lower edge, if zero, particles already 'bounce' at start and loose speed.
92129223
spray->source.vx = random8(5) + 6;
@@ -9288,7 +9299,7 @@ uint16_t mode_particleattractor(void)
92889299
SEGMENT.fill(BLACK); // clear the matrix
92899300
//ParticleSys_render(&attract, 1, 30, false, false); // render attractor
92909301
// render the particles
9291-
ParticleSys_render(particles, displayparticles, 255, false, false);
9302+
ParticleSys_render(particles, displayparticles, false, false);
92929303

92939304
return FRAMETIME;
92949305
}

wled00/FXparticleSystem.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
#include "FastLED.h"
3232
#include "FX.h"
3333

34-
// Fountain style emitter for simple particles used for flames (particle TTL depends on source TTL)
34+
// Fountain style emitter for particles used for flames (particle TTL depends on source TTL)
3535
void Emitter_Flame_emit(PSpointsource *emitter, PSparticle *part)
3636
{
3737
part->x = emitter->source.x + random8(emitter->var) - (emitter->var >> 1);
@@ -40,6 +40,7 @@ void Emitter_Flame_emit(PSpointsource *emitter, PSparticle *part)
4040
part->vy = emitter->vy + random8(emitter->var) - (emitter->var >> 1);
4141
part->ttl = (uint8_t)((rand() % (emitter->maxLife - emitter->minLife)) + emitter->minLife + emitter->source.ttl); // flame intensity dies down with emitter TTL
4242
part->hue = emitter->source.hue;
43+
part->sat = emitter->source.sat;
4344
}
4445

4546
// fountain style emitter
@@ -51,6 +52,7 @@ void Emitter_Fountain_emit(PSpointsource *emitter, PSparticle *part)
5152
part->vy = emitter->vy + random8(emitter->var) - (emitter->var >> 1);
5253
part->ttl = (rand() % (emitter->maxLife - emitter->minLife)) + emitter->minLife;
5354
part->hue = emitter->source.hue;
55+
part->sat = emitter->source.sat;
5456
}
5557

5658
// Emits a particle at given angle and speed, angle is from 0-255 (=0-360deg), speed is also affected by emitter->var
@@ -333,7 +335,7 @@ void Particle_Gravity_update(PSparticle *part, bool wrapX, bool bounceX, bool bo
333335
// render particles to the LED buffer (uses palette to render the 8bit particle color value)
334336
// if wrap is set, particles half out of bounds are rendered to the other side of the matrix
335337
// saturation is color saturation, if not set to 255, hsv instead of palette is used (palette does not support saturation)
336-
void ParticleSys_render(PSparticle *particles, uint16_t numParticles, uint8_t saturation, bool wrapX, bool wrapY)
338+
void ParticleSys_render(PSparticle *particles, uint16_t numParticles, bool wrapX, bool wrapY)
337339
{
338340

339341
const uint16_t cols = strip.isMatrix ? SEGMENT.virtualWidth() : 1;
@@ -360,10 +362,10 @@ void ParticleSys_render(PSparticle *particles, uint16_t numParticles, uint8_t sa
360362
// generate RGB values for particle
361363
brightess = min(particles[i].ttl, (uint16_t)255);
362364

363-
if (saturation < 255)
365+
if (particles[i].sat < 255)
364366
{
365367
CHSV baseHSV = rgb2hsv_approximate(ColorFromPalette(SEGPALETTE, particles[i].hue, 255, LINEARBLEND));
366-
baseHSV.s = saturation;
368+
baseHSV.s = particles[i].sat;
367369
baseRGB = (CRGB)baseHSV;
368370
}
369371
else
@@ -791,6 +793,9 @@ void handleCollision(PSparticle *particle1, PSparticle *particle2, const uint8_t
791793
// slow down particle by friction, the higher the speed, the higher the friction
792794
void applyFriction(PSparticle *particle, uint8_t coefficient)
793795
{
796+
if(particle->ttl)
797+
{
794798
particle->vx = ((int16_t)particle->vx * (255 - coefficient)) >> 8;
795799
particle->vy = ((int16_t)particle->vy * (255 - coefficient)) >> 8;
800+
}
796801
}

wled00/FXparticleSystem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ void Particle_attractor(PSparticle *particle, PSparticle *attractor, uint8_t *co
7474
void Particle_Move_update(PSparticle *part);
7575
void Particle_Bounce_update(PSparticle *part, const uint8_t hardness);
7676
void Particle_Gravity_update(PSparticle *part, bool wrapX, bool bounceX, bool bounceY, const uint8_t hardness);
77-
void ParticleSys_render(PSparticle *particles, uint16_t numParticles, uint8_t saturation, bool wrapX, bool wrapY);
77+
void ParticleSys_render(PSparticle *particles, uint16_t numParticles, bool wrapX, bool wrapY);
7878
void FireParticle_update(PSparticle *part, bool wrapX, bool WrapY);
7979
void ParticleSys_renderParticleFire(PSparticle *particles, uint16_t numParticles, bool wrapX);
8080
void PartMatrix_addHeat(uint8_t col, uint8_t row, uint16_t heat);

0 commit comments

Comments
 (0)