FastLED 3.9.15
Loading...
Searching...
No Matches

◆ FL_DISABLE_WARNING()

FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING ( shift-count- overflow)

Definition at line 15 of file downscale.cpp.hpp.

17 {
18
19void downscaleHalf(const CRGB *src, fl::u16 srcWidth, fl::u16 srcHeight,
20 CRGB *dst) {
21 fl::u16 dstWidth = srcWidth / 2;
22 fl::u16 dstHeight = srcHeight / 2;
23
24 for (fl::u16 y = 0; y < dstHeight; ++y) {
25 for (fl::u16 x = 0; x < dstWidth; ++x) {
26 // Map to top-left of the 2x2 block in source
27 fl::u16 srcX = x * 2;
28 fl::u16 srcY = y * 2;
29
30 // Fetch 2x2 block
31 const CRGB &p00 = src[(srcY)*srcWidth + (srcX)];
32 const CRGB &p10 = src[(srcY)*srcWidth + (srcX + 1)];
33 const CRGB &p01 = src[(srcY + 1) * srcWidth + (srcX)];
34 const CRGB &p11 = src[(srcY + 1) * srcWidth + (srcX + 1)];
35
36 // Average each color channel
37 fl::u16 r =
38 (p00.r + p10.r + p01.r + p11.r + 2) / 4; // +2 for rounding
39 fl::u16 g = (p00.g + p10.g + p01.g + p11.g + 2) / 4;
40 fl::u16 b = (p00.b + p10.b + p01.b + p11.b + 2) / 4;
41
42 // Store result
43 dst[y * dstWidth + x] = CRGB((fl::u8)r, (fl::u8)g, (fl::u8)b);
44 }
45 }
46}
47
48void downscaleHalf(const CRGB *src, const XYMap &srcXY, CRGB *dst,
49 const XYMap &dstXY) {
50 fl::u16 dstWidth = dstXY.getWidth();
51 fl::u16 dstHeight = dstXY.getHeight();
52
53 FASTLED_ASSERT(srcXY.getWidth() == dstXY.getWidth() * 2,
54 "Source width must be double the destination width");
55 FASTLED_ASSERT(srcXY.getHeight() == dstXY.getHeight() * 2,
56 "Source height must be double the destination height");
57
58 for (fl::u16 y = 0; y < dstHeight; ++y) {
59 for (fl::u16 x = 0; x < dstWidth; ++x) {
60 // Map to top-left of the 2x2 block in source
61 fl::u16 srcX = x * 2;
62 fl::u16 srcY = y * 2;
63
64 // Fetch 2x2 block
65 const CRGB &p00 = src[srcXY.mapToIndex(srcX, srcY)];
66 const CRGB &p10 = src[srcXY.mapToIndex(srcX + 1, srcY)];
67 const CRGB &p01 = src[srcXY.mapToIndex(srcX, srcY + 1)];
68 const CRGB &p11 = src[srcXY.mapToIndex(srcX + 1, srcY + 1)];
69
70 // Average each color channel
71 fl::u16 r =
72 (p00.r + p10.r + p01.r + p11.r + 2) / 4; // +2 for rounding
73 fl::u16 g = (p00.g + p10.g + p01.g + p11.g + 2) / 4;
74 fl::u16 b = (p00.b + p10.b + p01.b + p11.b + 2) / 4;
75
76 // Store result
77 dst[dstXY.mapToIndex(x, y)] =
78 CRGB((fl::u8)r, (fl::u8)g, (fl::u8)b);
79 }
80 }
81}
82
83void downscaleArbitrary(const CRGB *src, const XYMap &srcXY, CRGB *dst,
84 const XYMap &dstXY) {
85 const fl::u16 srcWidth = srcXY.getWidth();
86 const fl::u16 srcHeight = srcXY.getHeight();
87 const fl::u16 dstWidth = dstXY.getWidth();
88 const fl::u16 dstHeight = dstXY.getHeight();
89
90 const fl::u32 FP_ONE = 256; // Q8.8 fixed-point multiplier
91
92 FASTLED_ASSERT(dstWidth <= srcWidth,
93 "Destination width must be <= source width");
94 FASTLED_ASSERT(dstHeight <= srcHeight,
95 "Destination height must be <= source height");
96
97 for (fl::u16 dy = 0; dy < dstHeight; ++dy) {
98 // Fractional boundaries in Q8.8
99 fl::u32 dstY0 = (dy * srcHeight * FP_ONE) / dstHeight;
100 fl::u32 dstY1 = ((dy + 1) * srcHeight * FP_ONE) / dstHeight;
101
102 for (fl::u16 dx = 0; dx < dstWidth; ++dx) {
103 fl::u32 dstX0 = (dx * srcWidth * FP_ONE) / dstWidth;
104 fl::u32 dstX1 = ((dx + 1) * srcWidth * FP_ONE) / dstWidth;
105
106 fl::u64 rSum = 0, gSum = 0, bSum = 0;
107 fl::u32 totalWeight = 0;
108
109 // Find covered source pixels
110 fl::u16 srcY_start = dstY0 / FP_ONE;
111 fl::u16 srcY_end = (dstY1 + FP_ONE - 1) / FP_ONE; // ceil
112
113 fl::u16 srcX_start = dstX0 / FP_ONE;
114 fl::u16 srcX_end = (dstX1 + FP_ONE - 1) / FP_ONE; // ceil
115
116 for (fl::u16 sy = srcY_start; sy < srcY_end; ++sy) {
117 // Calculate vertical overlap in Q8.8
118 fl::u32 sy0 = sy * FP_ONE;
119 fl::u32 sy1 = (sy + 1) * FP_ONE;
120 fl::u32 y_overlap = fl::min(dstY1, sy1) - fl::max(dstY0, sy0);
121 if (y_overlap == 0)
122 continue;
123
124 for (fl::u16 sx = srcX_start; sx < srcX_end; ++sx) {
125 fl::u32 sx0 = sx * FP_ONE;
126 fl::u32 sx1 = (sx + 1) * FP_ONE;
127 fl::u32 x_overlap = fl::min(dstX1, sx1) - fl::max(dstX0, sx0);
128 if (x_overlap == 0)
129 continue;
130
131 fl::u32 weight = (x_overlap * y_overlap + (FP_ONE >> 1)) >>
132 8; // Q8.8 * Q8.8 → Q16.16 → Q8.8
133
134 const CRGB &p = src[srcXY.mapToIndex(sx, sy)];
135 rSum += p.r * weight;
136 gSum += p.g * weight;
137 bSum += p.b * weight;
138 totalWeight += weight;
139 }
140 }
141
142 // Final division, rounding
143 fl::u8 r =
144 totalWeight ? (rSum + (totalWeight >> 1)) / totalWeight : 0;
145 fl::u8 g =
146 totalWeight ? (gSum + (totalWeight >> 1)) / totalWeight : 0;
147 fl::u8 b =
148 totalWeight ? (bSum + (totalWeight >> 1)) / totalWeight : 0;
149
150 dst[dstXY.mapToIndex(dx, dy)] = CRGB(r, g, b);
151 }
152 }
153}
154
155void downscale(const CRGB *src, const XYMap &srcXY, CRGB *dst,
156 const XYMap &dstXY) {
157 fl::u16 srcWidth = srcXY.getWidth();
158 fl::u16 srcHeight = srcXY.getHeight();
159 fl::u16 dstWidth = dstXY.getWidth();
160 fl::u16 dstHeight = dstXY.getHeight();
161
162 FASTLED_ASSERT(dstWidth <= srcWidth,
163 "Destination width must be <= source width");
164 FASTLED_ASSERT(dstHeight <= srcHeight,
165 "Destination height must be <= source height");
166 const bool destination_is_half_of_source =
167 (dstWidth * 2 == srcWidth) && (dstHeight * 2 == srcHeight);
168 // Attempt to use the downscaleHalf function if the destination is half the
169 // size of the source.
170 if (destination_is_half_of_source) {
171 const bool both_rectangles = (srcXY.getType() == XYMap::kLineByLine) &&
172 (dstXY.getType() == XYMap::kLineByLine);
173 if (both_rectangles) {
174 // If both source and destination are rectangular, we can use the
175 // optimized version
176 downscaleHalf(src, srcWidth, srcHeight, dst);
177 } else {
178 // Otherwise, we need to use the mapped version
179 downscaleHalf(src, srcXY, dst, dstXY);
180 }
181 return;
182 }
183
184 downscaleArbitrary(src, srcXY, dst, dstXY);
185}
186
187} // namespace fl
int y
Definition simple.h:93
int x
Definition simple.h:92
fl::CRGB CRGB
Definition crgb.h:25
FL_DISABLE_WARNING_PUSH U constexpr common_type_t< T, U > min(T a, U b) FL_NOEXCEPT
Definition math.h:71
unsigned char u8
Definition stdint.h:131
constexpr common_type_t< T, U > max(T a, U b) FL_NOEXCEPT
Definition math.h:75
void downscale(const CRGB *src, const XYMap &srcXY, CRGB *dst, const XYMap &dstXY)
void downscaleArbitrary(const CRGB *src, const XYMap &srcXY, CRGB *dst, const XYMap &dstXY)
void downscaleHalf(const CRGB *src, fl::u16 srcWidth, fl::u16 srcHeight, CRGB *dst)
fl::u64 u64
Definition s16x16x4.h:221

References fl::downscale(), fl::downscaleArbitrary(), fl::downscaleHalf(), fl::FP_ONE, fl::XYMap::kLineByLine, fl::max(), fl::min(), x, and y.

+ Here is the call graph for this function: