drip effect rework

* made effect time-defendant (instead of framerate dependent)
* made effect a bit slower
* fixed physics
* made dropping more random (avoids skipped rows)
* drop traces look better now
* made bounce more realistic
* prevent off-screen drawing
This commit is contained in:
Frank
2024-10-07 13:14:50 +02:00
parent a84216947b
commit 7740c7dc62
2 changed files with 49 additions and 20 deletions

View File

@@ -3713,6 +3713,17 @@ uint16_t mode_exploding_fireworks(void)
static const char _data_FX_MODE_EXPLODING_FIREWORKS[] PROGMEM = "Fireworks 1D@Gravity,Firing side;!,!;!;12;pal=11,ix=128";
//SparkDrop type is used for drip
typedef struct __attribute__ ((packed)) SparkDrop {
float pos;
float boost; // speed "kick" when dropping
float vel;
uint32_t aux; // aux variable (RGBW color)
uint16_t col;
uint8_t colIndex;
} sparkdrop;
/*
* Drip Effect
* ported of: https://www.youtube.com/watch?v=sru2fXh4r7k
@@ -3723,20 +3734,24 @@ uint16_t mode_drip(void)
//allocate segment data
uint16_t strips = SEGMENT.nrOfVStrips();
const int maxNumDrops = 4;
uint16_t dataSize = sizeof(spark) * maxNumDrops;
uint16_t dataSize = sizeof(sparkdrop) * maxNumDrops;
if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
Spark* drops = reinterpret_cast<Spark*>(SEGENV.data);
SparkDrop* drops = reinterpret_cast<SparkDrop*>(SEGENV.data);
if (SEGENV.call == 0) SEGMENT.fill(BLACK); // WLEDMM clear LEDs at startup
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK); // WLEDMM clear LEDs at startup
SEGENV.step = strip.now; // initial time
}
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));
struct virtualStrip {
static void runStrip(uint16_t stripNr, Spark* drops) {
static void runStrip(uint16_t stripNr, SparkDrop* drops, float deltaTime) { // WLEDMM added deltaTime
uint8_t numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3
float gravity = -0.0005f - (float(SEGMENT.speed)/35000.0f); //increased gravity (50000 to 35000)
gravity *= min(max(1, SEGLEN-1), 255); //WLEDMM speed limit 255
float theSpeed = (SEGMENT.speed * SEGMENT.speed) / 255.0f; // WLEDMM
float gravity = -0.0002f - theSpeed/42000.0f; //gravity // WLEDMM adjusted
gravity *= min(max(1, SEGLEN-1), 255); // WLEDMM speed limit 255
const int sourcedrop = 12;
for (int j=0;j<numDrops;j++) {
@@ -3745,37 +3760,44 @@ uint16_t mode_drip(void)
drops[j].vel = 0; // speed
drops[j].col = sourcedrop; // brightness
drops[j].colIndex = 1; // drop state (0 init, 1 forming, 2 falling, 5 bouncing)
drops[j].velX = SEGMENT.color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 0); // random color
drops[j].aux = SEGMENT.color_from_palette(1 + random8(254), false, PALETTE_SOLID_WRAP, 0); // random color - WLEDMM avoid 0 which is usually BLACK
drops[j].boost = 0.65f + float(random8()) / 512.0f; // between 0.65 and 1.15
}
uint32_t dropColor = drops[j].velX;
uint32_t dropColor = drops[j].aux;
SEGMENT.setPixelColor(indexToVStrip(SEGLEN-1, stripNr), color_blend(BLACK,dropColor, sourcedrop));// water source
if (drops[j].colIndex==1) {
if (drops[j].col>255) drops[j].col=255;
SEGMENT.setPixelColor(indexToVStrip(uint16_t(drops[j].pos), stripNr), color_blend(BLACK,dropColor,drops[j].col));
int intPos = max(0.0f, roundf(drops[j].pos)); // WLEDMM round it first
SEGMENT.setPixelColor(int(indexToVStrip(intPos, stripNr)), color_blend(BLACK,dropColor,drops[j].col));
drops[j].col += map(SEGMENT.custom1, 0, 255, 1, 6); // swelling
unsigned swell = map(SEGMENT.custom1, 0, 255, 1, 6); // swelling
drops[j].col += swell;
if (drops[j].boost < 4.0f) drops[j].boost += 0.012f * float(swell); // increase mass when swelling
uint32_t fallrate = (drops[j].col * (1 + SEGMENT.custom1 * SEGMENT.custom1)) / 192; // WLEDMM specific
if (random16() <= (fallrate / 10)) { // random drop => 1% ... 20% probalibity
drops[j].colIndex=2; //fall
drops[j].col=255;
drops[j].vel = gravity * 2.0f * drops[j].boost; // WLEDMM initial kick
}
}
if (drops[j].colIndex > 1) { // falling
if (drops[j].pos > 0.01f) { // fall until end of segment
drops[j].pos += drops[j].vel;
drops[j].pos += drops[j].vel * deltaTime;
if (drops[j].pos < 0) drops[j].pos = 0;
drops[j].vel += gravity; // gravity is negative
drops[j].vel += gravity * deltaTime; // gravity is negative
for (int i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets
int intPos = roundf(drops[j].pos) +i; // WLEDMM round it first
int maxLen = 8 + SEGMENT.speed/64;
for (int i=1; i < maxLen-drops[j].colIndex; i++) { // some minor math so we don't expand bouncing droplets
int intPos = roundf(drops[j].pos + float(i)); // WLEDMM round it first
if ((intPos >= SEGLEN) || (intPos < 0)) break; // WLEDMM skip off-screen pixels
uint16_t pos = constrain(intPos, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally // WLEDMM bad cast to uint16_t removed
SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color_blend(BLACK,dropColor,drops[j].col/i)); //spread pixel with fade while falling
}
if (drops[j].colIndex > 2) { // during bounce, some water is on the floor
SEGMENT.setPixelColor(indexToVStrip(0, stripNr), color_blend(dropColor,BLACK, (2 * drops[j].col)/3)); // WLEDMM reduced brightness
SEGMENT.addPixelColor(indexToVStrip(0, stripNr), color_blend(dropColor,BLACK, drops[j].col*4)); // WLEDMM darker
}
} else { // we hit bottom
if (drops[j].colIndex > 2) { // already hit once, so back to forming
@@ -3785,8 +3807,11 @@ uint16_t mode_drip(void)
} else {
if (drops[j].colIndex==2) { // init bounce
drops[j].vel = -drops[j].vel/4;// reverse velocity with damping
drops[j].pos += drops[j].vel;
// reverse velocity with damping
if (SEGLEN > 16) drops[j].vel = -drops[j].vel/3.5f;
else drops[j].vel = -drops[j].vel/4.5f;
// do bounce
drops[j].pos += drops[j].vel * deltaTime * drops[j].boost*0.5f;
}
drops[j].col = sourcedrop*2;
drops[j].colIndex = 5; // bouncing
@@ -3797,12 +3822,16 @@ uint16_t mode_drip(void)
}
};
// WLEDMM calculate time passed
uint32_t millisPassed = min(max(1UL, strip.now - SEGENV.step), 180UL); // constrain between 1 and 180
SEGENV.step = strip.now;
float deltaTime = float(millisPassed) / 20.0f; // base speed 50 FPS
for (int stripNr=0; stripNr<strips; stripNr++)
virtualStrip::runStrip(stripNr, &drops[stripNr*maxNumDrops]);
virtualStrip::runStrip(stripNr, &drops[stripNr*maxNumDrops], deltaTime);
return FRAMETIME;
}
static const char _data_FX_MODE_DRIP[] PROGMEM = "Drip@Gravity,# of drips,Fall ratio,,,,Overlay;!,!;!;1.5d;c1=127,m12=1"; //bar WLEDMM 1.5d
static const char _data_FX_MODE_DRIP[] PROGMEM = "Drip@Gravity,# of drips,Fall ratio,,,,Overlay;!,!;!;1.5d;c1=127,m12=1"; //bar WLEDMM 1.5d
/*

View File

@@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2409280
#define VERSION 2410070
// WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED.
#define _MoonModules_WLED_