| 119 | } |
| 120 | |
| 121 | static CRGB HSV16toRGB(const HSV16& hsv) { |
| 122 | // Convert 16-bit values to working range |
| 123 | u32 h = hsv.h; |
| 124 | u32 s = hsv.s; |
| 125 | u32 v = hsv.v; |
| 126 | |
| 127 | if (s == 0) { |
| 128 | // Grayscale case - use precise mapping |
| 129 | u8 gray = map16_to_8(v); |
| 130 | return CRGB{gray, gray, gray}; |
| 131 | } |
| 132 | |
| 133 | // Determine which sector of the color wheel (0-5) |
| 134 | u32 sector = (h * 6) / 65536; |
| 135 | u32 sector_pos = (h * 6) % 65536; // Position within sector (0-65535) |
| 136 | |
| 137 | // Calculate intermediate values using precise mapping |
| 138 | // c = v * s / 65536, with proper rounding |
| 139 | u32 c = map32_to_16(v * s); |
| 140 | |
| 141 | // Calculate x = c * (1 - |2*(sector_pos/65536) - 1|) |
| 142 | u32 x; |
| 143 | if (sector & 1) { |
| 144 | // For odd sectors (1, 3, 5), we want decreasing values |
| 145 | // x = c * (65535 - sector_pos) / 65535 |
| 146 | x = map32_to_16(c * (65535 - sector_pos)); |
| 147 | } else { |
| 148 | // For even sectors (0, 2, 4), we want increasing values |
| 149 | // x = c * sector_pos / 65535 |
| 150 | x = map32_to_16(c * sector_pos); |
| 151 | } |
| 152 | |
| 153 | u32 m = v - c; |
| 154 | |
| 155 | u32 r1, g1, b1; |
| 156 | switch (sector) { |
| 157 | case 0: r1 = c; g1 = x; b1 = 0; break; |
| 158 | case 1: r1 = x; g1 = c; b1 = 0; break; |
| 159 | case 2: r1 = 0; g1 = c; b1 = x; break; |
| 160 | case 3: r1 = 0; g1 = x; b1 = c; break; |
| 161 | case 4: r1 = x; g1 = 0; b1 = c; break; |
| 162 | default: r1 = c; g1 = 0; b1 = x; break; |
| 163 | } |
| 164 | |
| 165 | // Add baseline and scale to 8-bit using accurate mapping |
| 166 | u8 R = map16_to_8(u16(r1 + m)); |
| 167 | u8 G = map16_to_8(u16(g1 + m)); |
| 168 | u8 B = map16_to_8(u16(b1 + m)); |
| 169 | |
| 170 | return CRGB{R, G, B}; |
| 171 | } |
| 172 | |
| 173 | HSV16::HSV16(const CRGB& rgb) { |
| 174 | *this = RGBtoHSV16(rgb); |
no test coverage detected