Signed-off-by: myperworld <myperworld@126.com>

This commit is contained in:
myperworld committed 2025-10-06 12:34:26 +08:00
1 parent 0986832fd1
commit aacd052c06
3403 files changed
+597376 -12

No files matched your search

@@ -0,0 +1,33 @@
# FastLED FX: Internal Helpers (`detail/`)
This folder contains utilities used by the FX engine. Most apps won’t include these directly; they’re pulled in by higher‑level classes.
### Components
- **`draw_context.h`**: Defines `fl::_DrawContext` (commonly referred to via `Fx::DrawContext`), which carries per‑frame data into effects: `now` (ms), `CRGB* leds`, `frame_time`, and a `speed` hint.
- **`fx_layer.h`**: Wraps an `Fx` and a `Frame` surface. Manages start/pause/draw and exposes the surface for compositing.
- **`fx_compositor.h`**: Cross‑fades between two `FxLayer`s over time using `Transition`. Produces a final buffer by blending surfaces each frame; automatically completes when progress reaches 100%.
- **`transition.h`**: Tracks a time‑based 0–255 progress value between a start time and duration. Used by the compositor to animate transitions.
### When you’ll encounter these
- If you use an FX engine/controller that switches effects with fades.
- If you build your own multi‑effect player, you may interact with `FxLayer` and `FxCompositor` directly.
These pieces are small and dependency‑light, but they’re part of the internal plumbing for higher‑level modules.
### Examples
- Switching between effects with transitions (see `examples/FxEngine/FxEngine.ino`):
```cpp
#include <FastLED.h>
#include "fx/2d/noisepalette.h"
#include "fx/fx_engine.h"
using namespace fl;
#define W 22
#define H 22
#define NUM_LEDS (W*H)
CRGB leds[NUM_LEDS];
XYMap xyMap(W, H, /* serpentine? */ true);
NoisePalette a(xyMap), b(xyMap);
FxEngine engine(NUM_LEDS);
void setup(){ FastLED.addLeds<WS2811,2,GRB>(leds, NUM_LEDS).setScreenMap(xyMap); engine.addFx(a); engine.addFx(b); }
void loop(){ EVERY_N_SECONDS(1){ engine.nextFx(500); } engine.draw(millis(), leds); FastLED.show(); }
```
@@ -0,0 +1,21 @@
#pragma once
#include "crgb.h"
#include "fl/namespace.h"
#include "fl/stdint.h"
namespace fl {
// Abstract base class for effects on a strip/grid of LEDs.
struct _DrawContext {
fl::u32 now;
CRGB *leds;
uint16_t frame_time = 0;
float speed = 1.0f;
_DrawContext(fl::u32 now, CRGB *leds, uint16_t frame_time = 0,
float speed = 1.0f)
: now(now), leds(leds), frame_time(frame_time), speed(speed) {}
};
} // namespace fl
@@ -0,0 +1,85 @@
#pragma once
#include "fl/stdint.h"
#include <string.h>
#include "crgb.h"
#include "fl/namespace.h"
#include "fl/memory.h"
#include "fl/vector.h"
#include "fx/detail/fx_layer.h"
#include "fx/fx.h"
#ifndef FASTLED_FX_ENGINE_MAX_FX
#define FASTLED_FX_ENGINE_MAX_FX 64
#endif
namespace fl {
// Takes two fx layers and composites them together to a final output buffer.
class FxCompositor {
public:
FxCompositor(fl::u32 numLeds) : mNumLeds(numLeds) {
mLayers[0] = fl::make_shared<FxLayer>();
mLayers[1] = fl::make_shared<FxLayer>();
}
void startTransition(fl::u32 now, fl::u32 duration, fl::shared_ptr<Fx> nextFx) {
completeTransition();
if (duration == 0) {
mLayers[0]->setFx(nextFx);
return;
}
mLayers[1]->setFx(nextFx);
mTransition.start(now, duration);
}
void completeTransition() {
if (mLayers[1]->getFx()) {
swapLayers();
mLayers[1]->release();
}
mTransition.end();
}
void draw(fl::u32 now, fl::u32 warpedTime, CRGB *finalBuffer);
private:
void swapLayers() {
FxLayerPtr tmp = mLayers[0];
mLayers[0] = mLayers[1];
mLayers[1] = tmp;
}
FxLayerPtr mLayers[2];
const fl::u32 mNumLeds;
Transition mTransition;
};
inline void FxCompositor::draw(fl::u32 now, fl::u32 warpedTime,
CRGB *finalBuffer) {
if (!mLayers[0]->getFx()) {
return;
}
mLayers[0]->draw(warpedTime);
uint8_t progress = mTransition.getProgress(now);
if (!progress) {
memcpy(finalBuffer, mLayers[0]->getSurface(), sizeof(CRGB) * mNumLeds);
return;
}
mLayers[1]->draw(warpedTime);
const CRGB *surface0 = mLayers[0]->getSurface();
const CRGB *surface1 = mLayers[1]->getSurface();
for (fl::u32 i = 0; i < mNumLeds; i++) {
const CRGB &p0 = surface0[i];
const CRGB &p1 = surface1[i];
CRGB out = CRGB::blend(p0, p1, progress);
finalBuffer[i] = out;
}
if (progress == 255) {
completeTransition();
}
}
} // namespace fl
@@ -0,0 +1,55 @@
#include <string.h>
#include "fx_layer.h"
#include "fl/memfill.h"
namespace fl {
void FxLayer::setFx(fl::shared_ptr<Fx> newFx) {
if (newFx != fx) {
release();
fx = newFx;
}
}
void FxLayer::draw(fl::u32 now) {
// assert(fx);
if (!frame) {
frame = fl::make_shared<Frame>(fx->getNumLeds());
}
if (!running) {
// Clear the frame
fl::memfill((uint8_t*)frame->rgb(), 0, frame->size() * sizeof(CRGB));
fx->resume(now);
running = true;
}
Fx::DrawContext context = {now, frame->rgb()};
fx->draw(context);
}
void FxLayer::pause(fl::u32 now) {
if (fx && running) {
fx->pause(now);
running = false;
}
}
void FxLayer::release() {
pause(0);
fx.reset();
}
fl::shared_ptr<Fx> FxLayer::getFx() {
return fx;
}
CRGB* FxLayer::getSurface() {
return frame->rgb();
}
}
@@ -0,0 +1,37 @@
#pragma once
#include "fl/stdint.h"
#include "crgb.h"
#include "fl/namespace.h"
#include "fl/memory.h"
#include "fl/vector.h"
#include "fl/warn.h"
#include "fx/frame.h"
#include "fx/fx.h"
namespace fl {
FASTLED_SMART_PTR(FxLayer);
class FxLayer {
public:
void setFx(fl::shared_ptr<Fx> newFx);
void draw(fl::u32 now);
void pause(fl::u32 now);
void release();
fl::shared_ptr<Fx> getFx();
CRGB *getSurface();
private:
fl::shared_ptr<Frame> frame;
fl::shared_ptr<Fx> fx;
bool running = false;
};
} // namespace fl
@@ -0,0 +1,49 @@
#pragma once
#include "fl/namespace.h"
#include "fl/stdint.h"
#include "fl/int.h"
namespace fl {
// Logic to control the progression of a transition over time.
class Transition {
public:
Transition() : mStart(0), mDuration(0), mNotStarted(true) {}
~Transition() {}
uint8_t getProgress(fl::u32 now) {
if (mNotStarted) {
return 0;
}
if (now < mStart) {
return 0;
} else if (now >= mStart + mDuration) {
return 255;
} else {
return ((now - mStart) * 255) / mDuration;
}
}
void start(fl::u32 now, fl::u32 duration) {
mNotStarted = false;
mStart = now;
mDuration = duration;
}
void end() { mNotStarted = true; }
bool isTransitioning(fl::u32 now) {
if (mNotStarted) {
return false;
}
return now >= mStart && now < mStart + mDuration;
}
private:
fl::u32 mStart;
fl::u32 mDuration;
bool mNotStarted;
};
} // namespace fl