Skip to content

Commit

Permalink
updated rotating particle spray with more user options
Browse files Browse the repository at this point in the history
  • Loading branch information
DedeHai committed Feb 21, 2024
1 parent d21ad8e commit 1a7ef9b
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 17 deletions.
42 changes: 31 additions & 11 deletions wled00/FX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7893,15 +7893,15 @@ uint16_t mode_particlerotatingspray(void)
#ifdef ESP8266
const uint32_t numParticles = 150; // maximum number of particles
#else
const uint32_t numParticles = 500; // maximum number of particles
const uint32_t numParticles = 700; // maximum number of particles
#endif

const uint8_t numSprays = 8; // maximum number of sprays

PSparticle *particles;
PSpointsource *spray;

// allocate memory and divide it into proper pointers, max is 32kB for all segments.
// allocate memory and divide it into proper pointers, max is 32kB for all segments, 100 particles use 1200bytes
uint32_t dataSize = sizeof(PSparticle) * numParticles;
dataSize += sizeof(PSpointsource) * (numSprays);
if (!SEGENV.allocateData(dataSize))
Expand All @@ -7918,13 +7918,14 @@ uint16_t mode_particlerotatingspray(void)
if (SEGMENT.call == 0) // initialization
{
SEGMENT.aux0 = 0; // starting angle
SEGMENT.aux1 = 0xFF; // user check
for (i = 0; i < numParticles; i++)
{
particles[i].ttl = 0;
}
for (i = 0; i < numSprays; i++)
{
spray[i].source.hue = random8();
spray[i].source.hue = random8(); //TODO: how to keep track of options? can use SEGMENT.aux1: change hue to random or rainbow depending on check but need to find out when it changed.
spray[i].source.sat = 255; // set saturation
spray[i].source.x = (cols * PS_P_RADIUS) / 2; // center
spray[i].source.y = (rows * PS_P_RADIUS) / 2; // center
Expand All @@ -7939,12 +7940,28 @@ uint16_t mode_particlerotatingspray(void)
}

// change source emitting color from time to time
if (SEGMENT.call % ((263 - SEGMENT.intensity) >> 3) == 0) // every nth frame, cycle color
if (SEGMENT.call % ((263 - SEGMENT.intensity) >> 3) == 0) // every nth frame, cycle color and update hue if necessary
{
for (i = 0; i < spraycount; i++)
{
{
spray[i].source.hue++; // = random8(); //change hue of spray source
}
if (SEGMENT.check1 != SEGMENT.aux1)
{
SEGMENT.aux1 = SEGMENT.check1;
for (i = 0; i < spraycount; i++)
{
if (SEGMENT.check1) // random color is checked
{
spray[i].source.hue = random8();
}
else
{
uint8_t coloroffset = 0xFF / spraycount;
spray[i].source.hue = coloroffset * i;
}
}
}
}

uint8_t percycle = spraycount; // maximum number of particles emitted per cycle
Expand All @@ -7970,17 +7987,20 @@ uint16_t mode_particlerotatingspray(void)

for (i = 0; i < spraycount; i++)
{
SEGMENT.aux0 += SEGMENT.speed << 2;

if (SEGMENT.check2)
SEGMENT.aux0 += SEGMENT.speed << 2;
else
SEGMENT.aux0 -= SEGMENT.speed << 2;

// calculate the x and y speed using aux0 as the 16bit angle. returned value by sin16/cos16 is 16bit, shifting it by 8 bits results in +/-128, divide that by custom1 slider value
spray[i].vx = (cos16(SEGMENT.aux0 + angleoffset * i) >> 8) / ((257 - SEGMENT.custom1) >> 1); // update spray angle (rotate all sprays with angle offset)
spray[i].vy = (sin16(SEGMENT.aux0 + angleoffset * i) >> 8) / ((257 - SEGMENT.custom1) >> 1); // update spray angle (rotate all sprays with angle offset)
spray[i].vx = (cos16(SEGMENT.aux0 + angleoffset * i) >> 8) / ((263 - SEGMENT.custom1) >> 3); // update spray angle (rotate all sprays with angle offset)
spray[i].vy = (sin16(SEGMENT.aux0 + angleoffset * i) >> 8) / ((263 - SEGMENT.custom1) >> 3); // update spray angle (rotate all sprays with angle offset)
spray[i].var = (SEGMENT.custom3 >> 1); // emiting variation = nozzle size (custom 3 goes from 0-32)
}

for (i = 0; i < numParticles; i++)
{
Particle_Move_update(&particles[i]); // move the particles
Particle_Move_update(&particles[i], true); // move the particles, kill out of bounds particles
}

SEGMENT.fill(BLACK); // clear the matrix
Expand All @@ -7990,7 +8010,7 @@ uint16_t mode_particlerotatingspray(void)

return FRAMETIME;
}
static const char _data_FX_MODE_PARTICLEROTATINGSPRAY[] PROGMEM = "Rotating Particle Spray@Rotation Speed,Color Change,Particle Speed,Spray Count,Nozzle Size;;!;012;pal=6,sx=39,ix=178,c1=225,c2=128,c3=0";
static const char _data_FX_MODE_PARTICLEROTATINGSPRAY[] PROGMEM = "Rotating Particle Spray@Rotation Speed,Color Change,Particle Speed,Spray Count,Nozzle Size,Random Color, Direction;;!;012;pal=6,sx=39,ix=178,c1=225,c2=128,c3=0";

/*
* Particle Fireworks
Expand Down
18 changes: 14 additions & 4 deletions wled00/FXparticleSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ void Particle_attractor(PSparticle *particle, PSparticle *attractor, uint8_t *co

// TODO: could solve all update functions in a single function with parameters and handle gravity acceleration in a separte function (uses more cpu time but that is not a huge issue) or maybe not, like this, different preferences can be set

void Particle_Move_update(PSparticle *part) // particle moves, decays and dies
void Particle_Move_update(PSparticle *part, bool killoutofbounds) // particle moves, decays and dies, if killoutofbounds is set, out of bounds particles are set to ttl=0
{
// Matrix dimension
const uint16_t cols = strip.isMatrix ? SEGMENT.virtualWidth() : 1;
Expand All @@ -187,13 +187,20 @@ void Particle_Move_update(PSparticle *part) // particle moves, decays and dies
// check if particle is out of bounds
if ((part->y <= 0) || (part->y >= PS_MAX_Y))
{
part->outofbounds = 1;
if (killoutofbounds)
part->ttl = 0;
else
part->outofbounds = 1;
}
if ((part->x <= 0) || (part->x >= PS_MAX_X))
{
part->outofbounds = 1;
if(killoutofbounds)
part->ttl = 0;
else
part->outofbounds = 1;
}
}

}

void Particle_Bounce_update(PSparticle *part, const uint8_t hardness) // bounces a particle on the matrix edges, if surface 'hardness' is <255 some energy will be lost in collision (127 means 50% lost)
Expand All @@ -211,6 +218,8 @@ void Particle_Bounce_update(PSparticle *part, const uint8_t hardness) // bounces
// age
part->ttl--;

part->outofbounds = 0; // reset out of bounds (particles are never out of bounds)

// apply velocity
int16_t newX, newY;

Expand All @@ -235,6 +244,7 @@ void Particle_Bounce_update(PSparticle *part, const uint8_t hardness) // bounces
part->x = min(newX, (int16_t)PS_MAX_X); // limit to matrix boundaries
part->y = min(newY, (int16_t)PS_MAX_Y);
}

}

void Particle_Wrap_update(PSparticle *part, bool wrapX, bool wrapY) // particle moves, decays and dies (age or out of matrix), if wrap is set, pixels leaving the matrix reappear on other side
Expand Down Expand Up @@ -523,7 +533,7 @@ void ParticleSys_render(PSparticle *particles, uint32_t numParticles, bool wrapX
}

// update & move particle using simple particles, wraps around left/right if wrapX is true, wrap around up/down if wrapY is true
void FireParticle_update(PSparticle *part, bool wrapX = false, bool wrapY = false)
void FireParticle_update(PSparticle *part, bool wrapX, bool wrapY)
{
// Matrix dimension
const uint16_t cols = strip.isMatrix ? SEGMENT.virtualWidth() : 1;
Expand Down
4 changes: 2 additions & 2 deletions wled00/FXparticleSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@ void Emitter_Flame_emit(PSpointsource *emitter, PSparticle *part);
void Emitter_Fountain_emit(PSpointsource *emitter, PSparticle *part);
void Emitter_Angle_emit(PSpointsource *emitter, PSparticle *part, uint8_t angle, uint8_t speed);
void Particle_attractor(PSparticle *particle, PSparticle *attractor, uint8_t *counter, uint8_t strength, bool swallow);
void Particle_Move_update(PSparticle *part);
void Particle_Move_update(PSparticle *part, bool killoutofbounds = false);
void Particle_Bounce_update(PSparticle *part, const uint8_t hardness);
void Particle_Wrap_update(PSparticle *part, bool wrapX, bool wrapY);
void Particle_Gravity_update(PSparticle *part, bool wrapX, bool bounceX, bool bounceY, const uint8_t hardness);
void ParticleSys_render(PSparticle *particles, uint32_t numParticles, bool wrapX, bool wrapY);
void FireParticle_update(PSparticle *part, bool wrapX, bool WrapY);
void FireParticle_update(PSparticle *part, bool wrapX = false, bool WrapY = false);
void ParticleSys_renderParticleFire(PSparticle *particles, uint32_t numParticles, bool wrapX);
void PartMatrix_addHeat(uint8_t col, uint8_t row, uint16_t heat);
void detectCollisions(PSparticle *particles, uint32_t numparticles, uint8_t hardness);
Expand Down

0 comments on commit 1a7ef9b

Please sign in to comment.