Signed-off-by: myperworld <myperworld@126.com>
This commit is contained in:
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
|
||||
Reference in new issue
Block a user