FastLED 3.7.8
Loading...
Searching...
No Matches
pixel_iterator.h
1
2#pragma once
3
4#include "namespace.h"
5#include "rgbw.h"
6#include <stddef.h>
7#include <stdint.h>
8#include <string.h>
9
10FASTLED_NAMESPACE_BEGIN
11
12template<typename PixelControllerT>
14 static void loadAndScaleRGBW(void* pixel_controller, Rgbw rgbw, uint8_t* b0_out, uint8_t* b1_out, uint8_t* b2_out, uint8_t* b3_out) {
15 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
16 pc->loadAndScaleRGBW(rgbw, b0_out, b1_out, b2_out, b3_out);
17 }
18
19 static void loadAndScaleRGB(void* pixel_controller, uint8_t* r_out, uint8_t* g_out, uint8_t* b_out) {
20 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
21 pc->loadAndScaleRGB(r_out, g_out, b_out);
22 }
23
24 static void loadAndScale_APA102_HD(void* pixel_controller, uint8_t* b0_out, uint8_t* b1_out, uint8_t* b2_out, uint8_t* brightness_out) {
25 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
26 pc->loadAndScale_APA102_HD(b0_out, b1_out, b2_out, brightness_out);
27 }
28
29 static void stepDithering(void* pixel_controller) {
30 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
31 pc->stepDithering();
32 }
33
34 static void advanceData(void* pixel_controller) {
35 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
36 pc->advanceData();
37 }
38
39 static int size(void* pixel_controller) {
40 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
41 return pc->size();
42 }
43 static bool has(void* pixel_controller, int n) {
44 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
45 return pc->has(n);
46 }
47};
48
49typedef void (*loadAndScaleRGBWFunction)(void* pixel_controller, Rgbw rgbw, uint8_t* b0_out, uint8_t* b1_out, uint8_t* b2_out, uint8_t* b3_out);
50typedef void (*loadAndScaleRGBFunction)(void* pixel_controller, uint8_t* r_out, uint8_t* g_out, uint8_t* b_out);
51typedef void (*loadAndScale_APA102_HDFunction)(void* pixel_controller, uint8_t* b0_out, uint8_t* b1_out, uint8_t* b2_out, uint8_t* brightness_out);
52typedef void (*stepDitheringFunction)(void* pixel_controller);
53typedef void (*advanceDataFunction)(void* pixel_controller);
54typedef int (*sizeFunction)(void* pixel_controller);
55typedef bool (*hasFunction)(void* pixel_controller, int n);
56
57
58// PixelIterator is turns a PixelController<> into a concrete object that can be used to iterate
59// over pixels and transform them into driver data. See PixelController<>::as_iterator() for how
60// to create a PixelIterator.
62 public:
63 template<typename PixelControllerT>
64 PixelIterator(PixelControllerT* pc, Rgbw rgbw)
65 : mPixelController(pc), mRgbw(rgbw) {
66 // Manually build up a vtable.
67 // Wait... what? Stupid nerds trying to show off how smart they are...
68 // Why not just use a virtual function?!
69 //
70 // Before you think this then you should know that the alternative straight
71 // forward way is to have a virtual interface class that PixelController inherits from.
72 // ...and that was already tried. And if you try to do this yourself
73 // this then let me tell you what is going to happen...
74 //
75 // EVERY SINGLE PLATFORM THAT HAS A COMPILED BINARY SIZE CHECK WILL IMMEDIATELY
76 // FAIL AS THE BINARY BLOWS UP BY 10-30%!!! It doesn't matter if only one PixelController
77 // with a vtable is used, gcc seems not to de-virtualize the calls. And we really care
78 // about binary size since FastLED needs to run on those tiny little microcontrollers like
79 // the Attiny85 (and family) which are in the sub $1 range used for commercial products.
80 //
81 // So to satisfy these tight memory requirements we make the dynamic dispatch used in PixelIterator
82 // an optional zero-cost abstraction which doesn't affect the binary size for platforms that
83 // don't use it. So that's why we are using this manual construction of the vtable that is built
84 // up using template magic. If your platform has lots of memory then you'll gladly trade
85 // a sliver of memory for the convenience of having a concrete implementation of
86 // PixelController that you can use without having to make all your driver code a template.
87 //
88 // Btw, this pattern in C++ is called the "type-erasure pattern". It allows non virtual
89 // polymorphism by leveraging the C++ template system to ensure type safety.
91 mLoadAndScaleRGBW = &Vtable::loadAndScaleRGBW;
92 mLoadAndScaleRGB = &Vtable::loadAndScaleRGB;
93 mLoadAndScale_APA102_HD = &Vtable::loadAndScale_APA102_HD;
94 mStepDithering = &Vtable::stepDithering;
95 mAdvanceData = &Vtable::advanceData;
96 mSize = &Vtable::size;
97 mHas = &Vtable::has;
98 }
99
100 bool has(int n) { return mHas(mPixelController, n); }
101 void loadAndScaleRGBW(uint8_t *b0_out, uint8_t *b1_out, uint8_t *b2_out, uint8_t *w_out) {
102 mLoadAndScaleRGBW(mPixelController, mRgbw, b0_out, b1_out, b2_out, w_out);
103 }
104 void loadAndScaleRGB(uint8_t *r_out, uint8_t *g_out, uint8_t *b_out) {
105 mLoadAndScaleRGB(mPixelController, r_out, g_out, b_out);
106 }
107 void loadAndScale_APA102_HD(uint8_t *b0_out, uint8_t *b1_out, uint8_t *b2_out, uint8_t *brightness_out) {
108 mLoadAndScale_APA102_HD(mPixelController, b0_out, b1_out, b2_out, brightness_out);
109 }
110 void stepDithering() { mStepDithering(mPixelController); }
111 void advanceData() { mAdvanceData(mPixelController); }
112 int size() { return mSize(mPixelController); }
113
114 void set_rgbw(Rgbw rgbw) { mRgbw = rgbw; }
115 Rgbw get_rgbw() const { return mRgbw; }
116
117 private:
118 // vtable emulation
119 void* mPixelController = nullptr;
120 Rgbw mRgbw;
121 loadAndScaleRGBWFunction mLoadAndScaleRGBW = nullptr;
122 loadAndScaleRGBFunction mLoadAndScaleRGB = nullptr;
123 loadAndScale_APA102_HDFunction mLoadAndScale_APA102_HD = nullptr;
124 stepDitheringFunction mStepDithering = nullptr;
125 advanceDataFunction mAdvanceData = nullptr;
126 sizeFunction mSize = nullptr;
127 hasFunction mHas = nullptr;
128};
129
130
131FASTLED_NAMESPACE_END
Definition rgbw.h:25