DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

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