colour.c (3425B)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | // Copyright 2026 jack@pngu.org // SPDX-License-Identifier: GPL-2.0-or-later #include "color.h" #include <lib/lib8tion/lib8tion.h> #define K255 255 #define K171 171 #define K170 170 #define K85 85 // Adapted from https://fastled.io/docs/hsv2rgb_8cpp_source.html // void hsv2rgb_rainbow() function rgb_t rgb_matrix_hsv_to_rgb(hsv_t hsv) { // Yellow has a higher inherent brightness than // any other color; 'pure' yellow is perceived to // be 93% as bright as white. In order to make // yellow appear the correct relative brightness, // it has to be rendered brighter than all other // colors. const uint8_t hue = hsv.h; const uint8_t sat = hsv.s; uint8_t val = hsv.v; // offset8 = (hue [0..31]) * 8 uint8_t offset8 = hue & 0x1F; offset8 <<= 3; uint8_t third = scale8(offset8, (256 / 3)); // max = 85 uint8_t r, g, b; if (!(hue & 0x80)) { // 0XX if (!(hue & 0x40)) { // 00X // section 0-1 if (!(hue & 0x20)) { // 000 // case 0: // R -> O r = K255 - third; g = third; b = 0; } else { // 001 // case 1: // O -> Y r = K171; g = K85 + third; b = 0; } } else { // 01X // section 2-3 if (!(hue & 0x20)) { // 010 // case 2: // Y -> G // uint8_t twothirds = (third << 1); uint8_t twothirds = scale8(offset8, ((256 * 2) / 3)); // max=170 r = K171 - twothirds; g = K170 + third; b = 0; } else { // 011 // case 3: // G -> A r = 0; g = K255 - third; b = third; } } } else { // section 4-7 // 1XX if (!(hue & 0x40)) { // 10X if (!(hue & 0x20)) { // 100 // case 4: // A -> B r = 0; // uint8_t twothirds = (third << 1); uint8_t twothirds = scale8(offset8, ((256 * 2) / 3)); // max=170 g = K171 - twothirds; // K170? b = K85 + twothirds; } else { // 101 // case 5: // B -> P r = third; g = 0; b = K255 - third; } } else { if (!(hue & 0x20)) { // 110 // case 6: // P -- K r = K85 + third; g = 0; b = K171 - third; } else { // 111 // case 7: // K -> R r = K170 + third; g = 0; b = K85 - third; } } } // This is one of the good places to scale the green down, // although the client can scale green down as well. g >>= 1; // Scale down colors if we're desaturated at all // and add the brightness_floor to r, g, and b. if (sat != 255) { if (sat == 0) { r = 255; b = 255; g = 255; } else { uint8_t desat = 255 - sat; desat = scale8_video(desat, desat); uint8_t satscale = 255 - desat; r = scale8(r, satscale); g = scale8(g, satscale); b = scale8(b, satscale); uint8_t brightness_floor = desat; r += brightness_floor; g += brightness_floor; b += brightness_floor; } } // Now scale everything down if we're at value < 255. if (val != 255) { val = scale8_video(val, val); if (val == 0) { r = 0; g = 0; b = 0; } else { r = scale8(r, val); g = scale8(g, val); b = scale8(b, val); } } return (rgb_t){.r = r, .g = g, .b = b}; } |