FastLED 3.9.15
Loading...
Searching...
No Matches
raster_sparse.h
Go to the documentation of this file.
1
2#pragma once
3
4/*
5A sparse path through an xy grid. When a value is set != 0, it will get stored
6in the sparse grid. The raster will only store the values that are set, and will
7not allocate memory for the entire grid. This is useful for large grids where
8only a small number of pixels are set.
9*/
10
11#include <stdint.h>
12
13#include "fl/geometry.h"
14#include "fl/grid.h"
15#include "fl/hash_map.h"
16#include "fl/map.h"
17#include "fl/namespace.h"
18#include "fl/slice.h"
19#include "fl/tile2x2.h"
20#include "fl/xymap.h"
21
23struct CRGB;
25
26#ifndef FASTLED_RASTER_SPARSE_INLINED_COUNT
27#define FASTLED_RASTER_SPARSE_INLINED_COUNT 128
28#endif
29
30namespace fl {
31
32class XYMap;
33class Gradient;
34class Tile2x2_u8;
35
36// A raster of uint8_t values. This is a sparse raster, meaning that it will
37// only store the values that are set.
39 public:
40 XYRasterU8Sparse() = default;
45
47 mSparseGrid.clear();
48 mCache.clear();
49 return *this;
50 }
51
52 XYRasterU8Sparse &clear() { return reset(); }
53
54 // Rasterizes point with a value For best visual results, you'll want to
55 // rasterize tile2x2 tiles, which are generated for you by the XYPathRenderer
56 // to represent sub pixel / neightbor splatting positions along a path.
57 // TODO: Bring the math from XYPathRenderer::at_subpixel(float alpha)
58 // into a general purpose function.
59 void rasterize(const vec2<int16_t> &pt, uint8_t value) {
60 // Turn it into a Tile2x2_u8 tile and see if we can cache it.
61 write(pt, value);
62 }
63
64 void setSize(uint16_t width, uint16_t height) {
66 }
67
72
75
76 iterator begin() { return mSparseGrid.begin(); }
77 const_iterator begin() const { return mSparseGrid.begin(); }
78 iterator end() { return mSparseGrid.end(); }
79 const_iterator end() const { return mSparseGrid.end(); }
80 size_t size() const { return mSparseGrid.size(); }
81 bool empty() const { return mSparseGrid.empty(); }
82
83 void rasterize(const Slice<const Tile2x2_u8> &tiles);
84 void rasterize(const Tile2x2_u8 &tile) { rasterize_internal(tile); }
85
86 void rasterize_internal(const Tile2x2_u8 &tile,
87 const rect<int16_t> *optional_bounds = nullptr);
88
89 // Renders the subpixel tiles to the raster. Any previous data is
90 // cleared. Memory will only be allocated if the size of the raster
91 // increased. void rasterize(const Slice<const Tile2x2_u8> &tiles);
92 // uint8_t &at(uint16_t x, uint16_t y) { return mGrid.at(x, y); }
93 // const uint8_t &at(uint16_t x, uint16_t y) const { return mGrid.at(x,
94 // y); }
95
96 Pair<bool, uint8_t> at(uint16_t x, uint16_t y) const {
97 const uint8_t *val = mSparseGrid.find_value(vec2<int16_t>(x, y));
98 if (val != nullptr) {
99 return {true, *val};
100 }
101 return {false, 0};
102 }
103
105 if (mAbsoluteBoundsSet) {
106 return mAbsoluteBounds;
107 }
108 return bounds_pixels();
109 }
110
112 int min_x = 0;
113 bool min_x_set = false;
114 int min_y = 0;
115 bool min_y_set = false;
116 int max_x = 0;
117 bool max_x_set = false;
118 int max_y = 0;
119 bool max_y_set = false;
120 for (const auto &it : mSparseGrid) {
121 const vec2<int16_t> &pt = it.first;
122 if (!min_x_set || pt.x < min_x) {
123 min_x = pt.x;
124 min_x_set = true;
125 }
126 if (!min_y_set || pt.y < min_y) {
127 min_y = pt.y;
128 min_y_set = true;
129 }
130 if (!max_x_set || pt.x > max_x) {
131 max_x = pt.x;
132 max_x_set = true;
133 }
134 if (!max_y_set || pt.y > max_y) {
135 max_y = pt.y;
136 max_y_set = true;
137 }
138 }
139 return rect<int16_t>(min_x, min_y, max_x + 1, max_y + 1);
140 }
141
142 // Warning! - SLOW.
143 uint16_t width() const { return bounds().width(); }
144 uint16_t height() const { return bounds().height(); }
145
146 void draw(const CRGB &color, const XYMap &xymap, CRGB *out);
147
148 void drawGradient(const Gradient &gradient, const XYMap &xymap, CRGB *out);
149
150 // Inlined, yet customizable drawing access. This will only send you
151 // pixels that are within the bounds of the XYMap.
152 template <typename XYVisitor>
153 void draw(const XYMap &xymap, XYVisitor &visitor) {
154 for (const auto &it : mSparseGrid) {
155 auto pt = it.first;
156 if (!xymap.has(pt.x, pt.y)) {
157 continue;
158 }
159 uint32_t index = xymap(pt.x, pt.y);
160 uint8_t value = it.second;
161 if (value > 0) { // Something wrote here.
162 visitor.draw(pt, index, value);
163 }
164 }
165 }
166
167 static const int kMaxCacheSize = 8; // Max size for tiny cache.
168
169 void write(const vec2<int16_t> &pt, uint8_t value) {
170 // FASTLED_WARN("write: " << pt.x << "," << pt.y << " value: " <<
171 // value); mSparseGrid.insert(pt, value);
172
173 uint8_t **cached = mCache.find_value(pt);
174 if (cached) {
175 uint8_t *val = *cached;
176 if (*val < value) {
177 *val = value;
178 }
179 return;
180 }
181 if (mCache.size() <= kMaxCacheSize) {
182 // cache it.
183 uint8_t *v = mSparseGrid.find_value(pt);
184 if (v == nullptr) {
185 // FASTLED_WARN("write: " << pt.x << "," << pt.y << " value: "
186 // << value);
187 if (mSparseGrid.needs_rehash()) {
188 // mSparseGrid is about to rehash, so we need to clear the
189 // small cache because it shares pointers.
190 mCache.clear();
191 }
192
193 mSparseGrid.insert(pt, value);
194 return;
195 }
196 mCache.insert(pt, v);
197 if (*v < value) {
198 *v = value;
199 }
200 return;
201 } else {
202 // overflow, clear cache and write directly.
203 mCache.clear();
204 mSparseGrid.insert(pt, value);
205 return;
206 }
207 }
208
209 private:
211 using Value = uint8_t;
218 // Small cache for the last N writes to help performance.
222 bool mAbsoluteBoundsSet = false;
223};
224
225} // namespace fl
int y
Definition Audio.ino:72
int x
Definition Audio.ino:71
XYMap xymap(WIDTH, HEIGHT, SERPENTINE)
fl::HashMap< Key, Value, HashKey, EqualToKey, FASTLED_HASHMAP_INLINED_COUNT > HashMapLarge
uint16_t height() const
void draw(const XYMap &xymap, XYVisitor &visitor)
void setSize(uint16_t width, uint16_t height)
XYRasterU8Sparse & clear()
XYRasterU8Sparse(int width, int height)
fl::HashMap< vec2< int16_t >, uint8_t >::const_iterator const_iterator
XYRasterU8Sparse()=default
void rasterize(const vec2< int16_t > &pt, uint8_t value)
void rasterize(const Tile2x2_u8 &tile)
const_iterator begin() const
static const int kMaxCacheSize
void rasterize_internal(const Tile2x2_u8 &tile, const rect< int16_t > *optional_bounds=nullptr)
Pair< bool, uint8_t > at(uint16_t x, uint16_t y) const
EqualTo< Key > EqualToKey
fl::HashMap< vec2< int16_t >, uint8_t >::iterator iterator
vec2< int16_t > Key
XYRasterU8Sparse(const XYRasterU8Sparse &)=delete
void setBounds(const rect< int16_t > &bounds)
rect< int16_t > bounds_pixels() const
void write(const vec2< int16_t > &pt, uint8_t value)
const_iterator end() const
FastHash< Key > FastHashKey
size_t size() const
HashMap< vec2< int16_t >, uint8_t *, FastHashKey, EqualToKey, kMaxCacheSize > mCache
XYRasterU8Sparse & reset()
void draw(const CRGB &color, const XYMap &xymap, CRGB *out)
HashMapLarge mSparseGrid
void drawGradient(const Gradient &gradient, const XYMap &xymap, CRGB *out)
uint16_t width() const
rect< int16_t > bounds() const
fl::rect< int16_t > mAbsoluteBounds
#define FASTLED_HASHMAP_INLINED_COUNT
Definition hash_map.h:43
#define FASTLED_NAMESPACE_END
Definition namespace.h:23
Implements the FastLED namespace macros.
Implements a simple red square effect for 2D LED grids.
Definition crgb.h:16
Representation of an RGB pixel (Red, Green, Blue)
Definition crgb.h:55
Definition pair.h:5
uint16_t width() const
Definition geometry.h:408
uint16_t height() const
Definition geometry.h:410