Color.cpp (8065B)
1 /* 2 * DISTRHO Plugin Framework (DPF) 3 * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any purpose with 6 * or without fee is hereby granted, provided that the above copyright notice and this 7 * permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD 10 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN 11 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 13 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "../Color.hpp" 18 19 START_NAMESPACE_DGL 20 21 // ----------------------------------------------------------------------- 22 23 static float computeHue(float h, float m1, float m2) 24 { 25 if (h < 0) h += 1; 26 if (h > 1) h -= 1; 27 if (h < 1.0f/6.0f) 28 return m1 + (m2 - m1) * h * 6.0f; 29 if (h < 3.0f/6.0f) 30 return m2; 31 if (h < 4.0f/6.0f) 32 return m1 + (m2 - m1) * (2.0f/3.0f - h) * 6.0f; 33 return m1; 34 } 35 36 static void fixRange(float& value) 37 { 38 /**/ if (value < 0.0f) 39 value = 0.0f; 40 else if (value > 1.0f) 41 value = 1.0f; 42 } 43 44 static float getFixedRange(const float& value) 45 { 46 if (value <= 0.0f) 47 return 0.0f; 48 if (value >= 1.0f) 49 return 1.0f; 50 return value; 51 } 52 53 static uchar getFixedRange2(const float& value) 54 { 55 const float value2(getFixedRange(value)*255.0f); 56 if (value2 <= 0.0f) 57 return 0; 58 if (value2 >= 255.0f) 59 return 255; 60 return static_cast<uchar>(value2 + 0.5f); 61 } 62 63 // ----------------------------------------------------------------------- 64 65 Color::Color() noexcept 66 : red(0.0f), 67 green(0.0f), 68 blue(0.0f), 69 alpha(1.0f) {} 70 71 Color::Color(const int r, const int g, const int b, const float a) noexcept 72 : red(static_cast<float>(r)/255.0f), 73 green(static_cast<float>(g)/255.0f), 74 blue(static_cast<float>(b)/255.0f), 75 alpha(a) 76 { 77 fixBounds(); 78 } 79 80 Color::Color(const float r, const float g, const float b, const float a) noexcept 81 : red(r), 82 green(g), 83 blue(b), 84 alpha(a) 85 { 86 fixBounds(); 87 } 88 89 Color::Color(const Color& color) noexcept 90 : red(color.red), 91 green(color.green), 92 blue(color.blue), 93 alpha(color.alpha) 94 { 95 fixBounds(); 96 } 97 98 Color& Color::operator=(const Color& color) noexcept 99 { 100 red = color.red; 101 green = color.green; 102 blue = color.blue; 103 alpha = color.alpha; 104 fixBounds(); 105 return *this; 106 } 107 108 Color::Color(const Color& color1, const Color& color2, const float u) noexcept 109 : red(color1.red), 110 green(color1.green), 111 blue(color1.blue), 112 alpha(color1.alpha) 113 { 114 interpolate(color2, u); 115 } 116 117 Color Color::withAlpha(const float alpha2) const noexcept 118 { 119 Color color(*this); 120 color.alpha = alpha2; 121 return color; 122 } 123 124 Color Color::minus(const int value) const noexcept 125 { 126 const float fvalue = static_cast<float>(value)/255.f; 127 Color color(*this); 128 color.red -= fvalue; 129 color.green -= fvalue; 130 color.blue -= fvalue; 131 color.fixBounds(); 132 return color; 133 } 134 135 Color Color::minus(const float value) const noexcept 136 { 137 Color color(*this); 138 color.red -= value; 139 color.green -= value; 140 color.blue -= value; 141 color.fixBounds(); 142 return color; 143 } 144 145 Color Color::plus(const int value) const noexcept 146 { 147 const float fvalue = static_cast<float>(value)/255.f; 148 Color color(*this); 149 color.red += fvalue; 150 color.green += fvalue; 151 color.blue += fvalue; 152 color.fixBounds(); 153 return color; 154 } 155 156 Color Color::plus(const float value) const noexcept 157 { 158 Color color(*this); 159 color.red += value; 160 color.green += value; 161 color.blue += value; 162 color.fixBounds(); 163 return color; 164 } 165 166 Color Color::invert() const noexcept 167 { 168 Color color(*this); 169 color.red = 1.f - color.red; 170 color.green = 1.f - color.green; 171 color.blue = 1.f - color.blue; 172 return color; 173 } 174 175 Color Color::fromHSL(float hue, float saturation, float lightness, float alpha) 176 { 177 float m1, m2; 178 Color col; 179 hue = fmodf(hue, 1.0f); 180 if (hue < 0.0f) hue += 1.0f; 181 fixRange(saturation); 182 fixRange(lightness); 183 m2 = lightness <= 0.5f ? (lightness * (1 + saturation)) : (lightness + saturation - lightness * saturation); 184 m1 = 2 * lightness - m2; 185 col.red = computeHue(hue + 1.0f/3.0f, m1, m2); 186 col.green = computeHue(hue, m1, m2); 187 col.blue = computeHue(hue - 1.0f/3.0f, m1, m2); 188 col.alpha = alpha; 189 col.fixBounds(); 190 return col; 191 } 192 193 Color Color::fromHTML(const char* rgb, const float alpha) noexcept 194 { 195 Color fallback; 196 DISTRHO_SAFE_ASSERT_RETURN(rgb != nullptr && rgb[0] != '\0', fallback); 197 198 if (rgb[0] == '#') 199 ++rgb; 200 DISTRHO_SAFE_ASSERT_RETURN(rgb[0] != '\0', fallback); 201 202 std::size_t rgblen = std::strlen(rgb); 203 DISTRHO_SAFE_ASSERT_RETURN(rgblen == 3 || rgblen == 6, fallback); 204 205 char rgbtmp[5] = { '0', 'x', '\0', '\0', '\0' }; 206 int r, g, b; 207 208 if (rgblen == 3) 209 { 210 rgbtmp[2] = rgb[0]; 211 r = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)) * 17; 212 213 rgbtmp[2] = rgb[1]; 214 g = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)) * 17; 215 216 rgbtmp[2] = rgb[2]; 217 b = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)) * 17; 218 } 219 else 220 { 221 rgbtmp[2] = rgb[0]; 222 rgbtmp[3] = rgb[1]; 223 r = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); 224 225 rgbtmp[2] = rgb[2]; 226 rgbtmp[3] = rgb[3]; 227 g = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); 228 229 rgbtmp[2] = rgb[4]; 230 rgbtmp[3] = rgb[5]; 231 b = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); 232 } 233 234 return Color(r, g, b, alpha); 235 } 236 237 void Color::interpolate(const Color& other, float u) noexcept 238 { 239 fixRange(u); 240 const float oneMinusU = 1.0f - u; 241 242 red = (red * oneMinusU) + (other.red * u); 243 green = (green * oneMinusU) + (other.green * u); 244 blue = (blue * oneMinusU) + (other.blue * u); 245 alpha = (alpha * oneMinusU) + (other.alpha * u); 246 247 fixBounds(); 248 } 249 250 // ----------------------------------------------------------------------- 251 252 bool Color::isEqual(const Color& color, const bool withAlpha) noexcept 253 { 254 const uchar r1 = getFixedRange2(rgba[0]); 255 const uchar g1 = getFixedRange2(rgba[1]); 256 const uchar b1 = getFixedRange2(rgba[2]); 257 const uchar a1 = getFixedRange2(rgba[3]); 258 259 const uchar r2 = getFixedRange2(color.rgba[0]); 260 const uchar g2 = getFixedRange2(color.rgba[1]); 261 const uchar b2 = getFixedRange2(color.rgba[2]); 262 const uchar a2 = getFixedRange2(color.rgba[3]); 263 264 if (withAlpha) 265 return (r1 == r2 && g1 == g2 && b1 == b2 && a1 == a2); 266 else 267 return (r1 == r2 && g1 == g2 && b1 == b2); 268 } 269 270 bool Color::isNotEqual(const Color& color, const bool withAlpha) noexcept 271 { 272 const uchar r1 = getFixedRange2(rgba[0]); 273 const uchar g1 = getFixedRange2(rgba[1]); 274 const uchar b1 = getFixedRange2(rgba[2]); 275 const uchar a1 = getFixedRange2(rgba[3]); 276 277 const uchar r2 = getFixedRange2(color.rgba[0]); 278 const uchar g2 = getFixedRange2(color.rgba[1]); 279 const uchar b2 = getFixedRange2(color.rgba[2]); 280 const uchar a2 = getFixedRange2(color.rgba[3]); 281 282 if (withAlpha) 283 return (r1 != r2 || g1 != g2 || b1 != b2 || a1 != a2); 284 else 285 return (r1 != r2 || g1 != g2 || b1 != b2); 286 } 287 288 bool Color::operator==(const Color& color) noexcept 289 { 290 return isEqual(color, true); 291 } 292 293 bool Color::operator!=(const Color& color) noexcept 294 { 295 return isNotEqual(color, true); 296 } 297 298 // ----------------------------------------------------------------------- 299 300 void Color::fixBounds() noexcept 301 { 302 fixRange(red); 303 fixRange(green); 304 fixRange(blue); 305 fixRange(alpha); 306 } 307 308 // ----------------------------------------------------------------------- 309 310 END_NAMESPACE_DGL