FastLED 3.7.8
Loading...
Searching...
No Matches
five_bit_hd_gamma.cpp
1
2
3#define FASTLED_INTERNAL 1
4
5#include "FastLED.h"
6#include "five_bit_hd_gamma.h"
7#include "fastled_progmem.h"
8#include "lib8tion/scale8.h"
9#include "namespace.h"
10
11// Author: Zach Vorhies
12
13#ifndef FASTLED_FIVE_BIT_HD_GAMMA_LOW_END_LINEAR_RAMP
14#define FASTLED_FIVE_BIT_HD_GAMMA_LOW_END_LINEAR_RAMP 0
15#endif
16
17FASTLED_NAMESPACE_BEGIN
18
19#ifndef FASTLED_FIVE_BIT_HD_GAMMA_FUNCTION_2_8
20// Fast a memory efficient gamma=2 function.
21void five_bit_hd_gamma_function(
22 uint8_t r8, uint8_t g8, uint8_t b8,
23 uint16_t* r16, uint16_t* g16, uint16_t* b16) {
24 *r16 = uint16_t(r8) * r8;
25 *g16 = uint16_t(g8) * g8;
26 *b16 = uint16_t(b8) * b8;
27}
28#else
29// Using look up table for gamma16 correction at power of 2.8
30static const uint16_t PROGMEM _gamma_2_8[256] = {
31 0, 0, 0, 1, 1, 2, 4, 6, 8, 11, 14,
32 18, 23, 29, 35, 41, 49, 57, 67, 77, 88, 99,
33 112, 126, 141, 156, 173, 191, 210, 230, 251, 274, 297,
34 322, 348, 375, 404, 433, 464, 497, 531, 566, 602, 640,
35 680, 721, 763, 807, 853, 899, 948, 998, 1050, 1103, 1158,
36 1215, 1273, 1333, 1394, 1458, 1523, 1590, 1658, 1729, 1801, 1875,
37 1951, 2029, 2109, 2190, 2274, 2359, 2446, 2536, 2627, 2720, 2816,
38 2913, 3012, 3114, 3217, 3323, 3431, 3541, 3653, 3767, 3883, 4001,
39 4122, 4245, 4370, 4498, 4627, 4759, 4893, 5030, 5169, 5310, 5453,
40 5599, 5747, 5898, 6051, 6206, 6364, 6525, 6688, 6853, 7021, 7191,
41 7364, 7539, 7717, 7897, 8080, 8266, 8454, 8645, 8838, 9034, 9233,
42 9434, 9638, 9845, 10055, 10267, 10482, 10699, 10920, 11143, 11369, 11598,
43 11829, 12064, 12301, 12541, 12784, 13030, 13279, 13530, 13785, 14042, 14303,
44 14566, 14832, 15102, 15374, 15649, 15928, 16209, 16493, 16781, 17071, 17365,
45 17661, 17961, 18264, 18570, 18879, 19191, 19507, 19825, 20147, 20472, 20800,
46 21131, 21466, 21804, 22145, 22489, 22837, 23188, 23542, 23899, 24260, 24625,
47 24992, 25363, 25737, 26115, 26496, 26880, 27268, 27659, 28054, 28452, 28854,
48 29259, 29667, 30079, 30495, 30914, 31337, 31763, 32192, 32626, 33062, 33503,
49 33947, 34394, 34846, 35300, 35759, 36221, 36687, 37156, 37629, 38106, 38586,
50 39071, 39558, 40050, 40545, 41045, 41547, 42054, 42565, 43079, 43597, 44119,
51 44644, 45174, 45707, 46245, 46786, 47331, 47880, 48432, 48989, 49550, 50114,
52 50683, 51255, 51832, 52412, 52996, 53585, 54177, 54773, 55374, 55978, 56587,
53 57199, 57816, 58436, 59061, 59690, 60323, 60960, 61601, 62246, 62896, 63549,
54 64207, 64869, 65535};
55
56void five_bit_hd_gamma_function(uint8_t r8, uint8_t g8,
57 uint8_t b8, uint16_t *r16,
58 uint16_t *g16,
59 uint16_t *b16) {
60 *r16 = _gamma_2_8[r8];
61 *g16 = _gamma_2_8[g8];
62 *b16 = _gamma_2_8[b8];
63}
64#endif // FASTLED_FIVE_BIT_HD_GAMMA_FUNCTION_2_8
65
66
67void __builtin_five_bit_hd_gamma_bitshift(
68 uint8_t r8, uint8_t g8, uint8_t b8,
69 uint8_t r8_scale, uint8_t g8_scale, uint8_t b8_scale,
70 uint8_t* out_r8,
71 uint8_t* out_g8,
72 uint8_t* out_b8,
73 uint8_t* out_power_5bit) {
74
75 // Step 1: Gamma Correction
76 uint16_t r16, g16, b16;
77 five_bit_hd_gamma_function(r8, g8, b8, &r16, &g16, &b16);
78
79 // Step 2: Post gamma correction scale.
80 if (r8_scale != 0xff || g8_scale != 0xff || b8_scale != 0xff) {
81 r16 = scale16by8(r16, r8_scale);
82 g16 = scale16by8(g16, g8_scale);
83 b16 = scale16by8(b16, b8_scale);
84 }
85
86 // Step 3: Initialize 5-bit brightness.
87 // Note: we only get 5 levels of brightness
88 uint8_t v8 = 31;
89
90 uint16_t numerator = 1;
91 uint16_t denominator = 1;
92 const uint32_t r16_const = r16;
93 const uint32_t g16_const = g16;
94 const uint32_t b16_const = b16;
95
96 // Step 4: Bit Shifting Loop, can probably replaced with a
97 // single pass bit-twiddling hack.
98 do {
99 // Note that to avoid slow divisions, we multiply the max_value
100 // by the denominator.
101 uint32_t max_value = 0xfffful * 15;
102 if (r16_const * 31 > max_value) {
103 break;
104 }
105 if (g16_const * 31 > max_value) {
106 break;
107 }
108 if (b16_const * 31 > max_value) {
109 break;
110 }
111 numerator = 31;
112 denominator = 15;
113 v8 = 15;
114
115 max_value = 0xfffful * 15 * 7;
116 if (r16_const * 31 * 15 > max_value) {
117 break;
118 }
119 if (g16_const * 31 * 15 > max_value) {
120 break;
121 }
122 if (b16_const * 31 * 15 > max_value) {
123 break;
124 }
125 numerator = 31 * 15;
126 denominator = 15 * 7;
127 v8 = 7;
128
129 max_value = 0xfffful * 15 * 7 * 3;
130 if (r16_const * 31 * 15 * 7 > max_value) {
131 break;
132 }
133 if (g16_const * 31 * 15 * 7 > max_value) {
134 break;
135 }
136 if (b16_const * 31 * 15 * 7 > max_value) {
137 break;
138 }
139 numerator = 31 * 15 * 7;
140 denominator = 15 * 7 * 3;
141 v8 = 3;
142
143 max_value = 0xfffful * 15 * 7 * 3;
144 if (r16_const * 31 * 15 * 7 * 3 > max_value) {
145 break;
146 }
147 if (g16_const * 31 * 15 * 7 * 3 > max_value) {
148 break;
149 }
150 if (b16_const * 31 * 15 * 7 * 3 > max_value) {
151 break;
152 }
153 numerator = 31 * 15 * 7 * 3;
154 v8 = 1;
155 } while(false);
156
157 r16 = uint16_t(r16_const * numerator / denominator);
158 g16 = uint16_t(g16_const * numerator / denominator);
159 b16 = uint16_t(b16_const * numerator / denominator);
160
161 // Step 5: Conversion Back to 8-bit.
162 uint8_t r8_final = (r8 == 255 && uint8_t(r16 >> 8) >= 254) ? 255 : uint8_t(r16 >> 8);
163 uint8_t g8_final = (g8 == 255 && uint8_t(g16 >> 8) >= 254) ? 255 : uint8_t(g16 >> 8);
164 uint8_t b8_final = (b8 == 255 && uint8_t(b16 >> 8) >= 254) ? 255 : uint8_t(b16 >> 8);
165
166#if FASTLED_FIVE_BIT_HD_GAMMA_LOW_END_LINEAR_RAMP > 0
167 if (v8 == 1) {
168 // Linear tuning for the lowest possible brightness. x=y until
169 // the intersection point at 9.
170 if (r8 < FASTLED_FIVE_BIT_HD_GAMMA_LOW_END_LINEAR_RAMP && r16 > 0) {
171 r8_final = r8;
172 }
173 if (g8 < FASTLED_FIVE_BIT_HD_GAMMA_LOW_END_LINEAR_RAMP && g16 > 0) {
174 g8_final = g8;
175 }
176 if (b8 < FASTLED_FIVE_BIT_HD_GAMMA_LOW_END_LINEAR_RAMP && b16 > 0) {
177 b8_final = b8;
178 }
179 }
180#endif
181
182 // Step 6: Output
183 *out_r8 = r8_final;
184 *out_g8 = g8_final;
185 *out_b8 = b8_final;
186 *out_power_5bit = v8;
187}
188
189
190FASTLED_NAMESPACE_END
central include file for FastLED, defines the CFastLED class/object
Wrapper definitions to allow seamless use of PROGMEM in environments that have it.
LIB8STATIC_ALWAYS_INLINE uint16_t scale16by8(uint16_t i, fract8 scale)
Scale a 16-bit unsigned value by an 8-bit value, which is treated as the numerator of a fraction whos...
Definition scale8.h:454
Fast, efficient 8-bit scaling functions specifically designed for high-performance LED programming.