@@ -8958,6 +8958,108 @@ uint16_t mode_particleblobs(void) {
89588958 return FRAMETIME;
89598959}
89608960static const char _data_FX_MODE_PARTICLEBLOBS[] PROGMEM = " PS Blobs@Speed,Blobs,Size,Life,Blur,Wobble,Collide,Pulsate;;!;2v;sx=30,ix=64,c1=200,c2=130,c3=0,o3=1" ;
8961+
8962+ /*
8963+ Particle Galaxy, particles spiral like in a galaxy
8964+ Uses palette for particle color
8965+ by DedeHai (Damian Schneider)
8966+ */
8967+ uint16_t mode_particlegalaxy (void ) {
8968+ ParticleSystem2D *PartSys = nullptr ;
8969+ PSsettings2D sourcesettings;
8970+ sourcesettings.asByte = 0b00001100 ; // PS settings for bounceY, bounceY used for source movement (it always bounces whereas particles do not)
8971+ if (SEGMENT.call == 0 ) { // initialization
8972+ if (!initParticleSystem2D (PartSys, 1 , 0 , true )) // init using 1 source and advanced particle settings
8973+ return mode_static (); // allocation failed or not 2D
8974+ PartSys->sources [0 ].source .vx = -4 ; // will collide with wall and get random bounce direction
8975+ PartSys->sources [0 ].source .x = PartSys->maxX >> 1 ; // start in the center
8976+ PartSys->sources [0 ].source .y = PartSys->maxY >> 1 ;
8977+ PartSys->sources [0 ].sourceFlags .perpetual = true ; // source does not age
8978+ PartSys->sources [0 ].maxLife = 4000 ; // lifetime in frames
8979+ PartSys->sources [0 ].minLife = 800 ;
8980+ PartSys->sources [0 ].source .hue = hw_random16 (); // start with random color
8981+ PartSys->setWallHardness (255 ); // bounce forever
8982+ PartSys->setWallRoughness (200 ); // randomize wall bounce
8983+ }
8984+ else {
8985+ PartSys = reinterpret_cast <ParticleSystem2D *>(SEGENV.data ); // if not first call, just set the pointer to the PS
8986+ }
8987+ if (PartSys == nullptr )
8988+ return mode_static (); // something went wrong, no data!
8989+ // Particle System settings
8990+ PartSys->updateSystem (); // update system properties (dimensions and data pointers)
8991+ uint8_t particlesize = SEGMENT.custom1 ;
8992+ if (SEGMENT.check3 )
8993+ particlesize = SEGMENT.custom1 ? 1 : 0 ; // set size to 0 (single pixel) or 1 (quad pixel) so motion blur works and adds streaks
8994+ PartSys->setParticleSize (particlesize); // set size globally
8995+ PartSys->setMotionBlur (250 * SEGMENT.check3 ); // adds trails to single/quad pixel particles, no effect if size > 1
8996+
8997+ if ((SEGMENT.call % ((33 - SEGMENT.custom3 ) >> 1 )) == 0 ) // change hue of emitted particles
8998+ PartSys->sources [0 ].source .hue +=2 ;
8999+
9000+ if (hw_random8 () < (10 + (SEGMENT.intensity >> 1 ))) // 5%-55% chance to emit a particle in this frame
9001+ PartSys->sprayEmit (PartSys->sources [0 ]);
9002+
9003+ if ((SEGMENT.call & 0x3 ) == 0 ) // every 4th frame, move the emitter
9004+ PartSys->particleMoveUpdate (PartSys->sources [0 ].source , PartSys->sources [0 ].sourceFlags , &sourcesettings);
9005+
9006+ // move alive particles in a spiral motion (or almost straight in fast starfield mode)
9007+ int32_t centerx = PartSys->maxX >> 1 ; // center of matrix in subpixel coordinates
9008+ int32_t centery = PartSys->maxY >> 1 ;
9009+ if (SEGMENT.check2 ) { // starfield mode
9010+ PartSys->setKillOutOfBounds (true );
9011+ PartSys->sources [0 ].var = 7 ; // emiting variation
9012+ PartSys->sources [0 ].source .x = centerx; // set emitter to center
9013+ PartSys->sources [0 ].source .y = centery;
9014+ }
9015+ else {
9016+ PartSys->setKillOutOfBounds (false );
9017+ PartSys->sources [0 ].var = 1 ; // emiting variation
9018+ }
9019+ for (uint32_t i = 0 ; i < PartSys->usedParticles ; i++) { // check all particles
9020+ if (PartSys->particles [i].ttl == 0 ) continue ; // skip dead particles
9021+ // (dx/dy): vector pointing from particle to center
9022+ int32_t dx = centerx - PartSys->particles [i].x ;
9023+ int32_t dy = centery - PartSys->particles [i].y ;
9024+ // speed towards center:
9025+ int32_t distance = sqrt32_bw (dx * dx + dy * dy); // absolute distance to center
9026+ if (distance < 20 ) distance = 20 ; // avoid division by zero, keep a minimum
9027+ int32_t speedfactor;
9028+ if (SEGMENT.check2 ) { // starfield mode
9029+ speedfactor = 1 + (1 + (SEGMENT.speed >> 1 )) * distance; // speed increases towards edge
9030+ // apply velocity
9031+ PartSys->particles [i].x += (-speedfactor * dx) / 400000 - (dy >> 6 );
9032+ PartSys->particles [i].y += (-speedfactor * dy) / 400000 + (dx >> 6 );
9033+ }
9034+ else {
9035+ speedfactor = 2 + (((50 + SEGMENT.speed ) << 6 ) / distance); // speed increases towards center
9036+ // rotate clockwise
9037+ int32_t tempVx = (-speedfactor * dy); // speed is orthogonal to center vector
9038+ int32_t tempVy = (speedfactor * dx);
9039+ // add speed towards center to make particles spiral in
9040+ int vxc = (dx << 9 ) / (distance - 19 ); // subtract value from distance to make the pull-in force a bit stronger (helps on faster speeds)
9041+ int vyc = (dy << 9 ) / (distance - 19 );
9042+ // apply velocity
9043+ PartSys->particles [i].x += (tempVx + vxc) / 1024 ; // note: cannot use bit shift as that causes asymmetric rounding
9044+ PartSys->particles [i].y += (tempVy + vyc) / 1024 ;
9045+
9046+ if (distance < 128 ) { // close to center
9047+ if (PartSys->particles [i].ttl > 3 )
9048+ PartSys->particles [i].ttl -= 4 ; // age fast
9049+ PartSys->particles [i].sat = distance << 1 ; // turn white towards center
9050+ }
9051+ }
9052+ if (SEGMENT.custom3 == 31 ) // color by age but mapped to 1024 as particles have a long life, since age is random, this gives more or less random colors
9053+ PartSys->particles [i].hue = PartSys->particles [i].ttl >> 2 ;
9054+ else if (SEGMENT.custom3 == 0 ) // color by distance
9055+ PartSys->particles [i].hue = map (distance, 20 , (PartSys->maxX + PartSys->maxY ) >> 2 , 0 , 180 ); // color by distance to center
9056+ }
9057+
9058+ PartSys->update (); // update and render
9059+ return FRAMETIME;
9060+ }
9061+ static const char _data_FX_MODE_PARTICLEGALAXY[] PROGMEM = " PS Galaxy@!,!,Size,,Color,,Starfield,Trace;;!;2;pal=59,sx=80,c1=2,c3=4" ;
9062+
89619063#endif // WLED_DISABLE_PARTICLESYSTEM2D
89629064#endif // WLED_DISABLE_2D
89639065
@@ -10657,6 +10759,7 @@ void WS2812FX::setupEffectData() {
1065710759 addEffect (FX_MODE_PARTICLECENTERGEQ, &mode_particlecenterGEQ, _data_FX_MODE_PARTICLECIRCULARGEQ);
1065810760 addEffect (FX_MODE_PARTICLEGHOSTRIDER, &mode_particleghostrider, _data_FX_MODE_PARTICLEGHOSTRIDER);
1065910761 addEffect (FX_MODE_PARTICLEBLOBS, &mode_particleblobs, _data_FX_MODE_PARTICLEBLOBS);
10762+ addEffect (FX_MODE_PARTICLEGALAXY, &mode_particlegalaxy, _data_FX_MODE_PARTICLEGALAXY);
1066010763#endif // WLED_DISABLE_PARTICLESYSTEM2D
1066110764#endif // WLED_DISABLE_2D
1066210765
0 commit comments