DISTRHO Plugin Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
6.7KB

  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. #include "../Color.hpp"
  17. START_NAMESPACE_DGL
  18. // -----------------------------------------------------------------------
  19. static float computeHue(float h, float m1, float m2)
  20. {
  21. if (h < 0) h += 1;
  22. if (h > 1) h -= 1;
  23. if (h < 1.0f/6.0f)
  24. return m1 + (m2 - m1) * h * 6.0f;
  25. if (h < 3.0f/6.0f)
  26. return m2;
  27. if (h < 4.0f/6.0f)
  28. return m1 + (m2 - m1) * (2.0f/3.0f - h) * 6.0f;
  29. return m1;
  30. }
  31. static void fixRange(float& value)
  32. {
  33. /**/ if (value < 0.0f)
  34. value = 0.0f;
  35. else if (value > 1.0f)
  36. value = 1.0f;
  37. }
  38. static float getFixedRange(const float& value)
  39. {
  40. if (value <= 0.0f)
  41. return 0.0f;
  42. if (value >= 1.0f)
  43. return 1.0f;
  44. return value;
  45. }
  46. static uchar getFixedRange2(const float& value)
  47. {
  48. const float value2(getFixedRange(value)*255.0f);
  49. if (value2 <= 0.0f)
  50. return 0;
  51. if (value2 >= 255.0f)
  52. return 255;
  53. return static_cast<uchar>(value2 + 0.5f);
  54. }
  55. // -----------------------------------------------------------------------
  56. Color::Color() noexcept
  57. : red(0.0f),
  58. green(0.0f),
  59. blue(0.0f),
  60. alpha(1.0f) {}
  61. Color::Color(const int r, const int g, const int b, const float a) noexcept
  62. : red(static_cast<float>(r)/255.0f),
  63. green(static_cast<float>(g)/255.0f),
  64. blue(static_cast<float>(b)/255.0f),
  65. alpha(a)
  66. {
  67. fixBounds();
  68. }
  69. Color::Color(const float r, const float g, const float b, const float a) noexcept
  70. : red(r),
  71. green(g),
  72. blue(b),
  73. alpha(a)
  74. {
  75. fixBounds();
  76. }
  77. Color::Color(const Color& color) noexcept
  78. : red(color.red),
  79. green(color.green),
  80. blue(color.blue),
  81. alpha(color.alpha)
  82. {
  83. fixBounds();
  84. }
  85. Color& Color::operator=(const Color& color) noexcept
  86. {
  87. red = color.red;
  88. green = color.green;
  89. blue = color.blue;
  90. alpha = color.alpha;
  91. fixBounds();
  92. return *this;
  93. }
  94. Color::Color(const Color& color1, const Color& color2, const float u) noexcept
  95. : red(color1.red),
  96. green(color1.green),
  97. blue(color1.blue),
  98. alpha(color1.alpha)
  99. {
  100. interpolate(color2, u);
  101. }
  102. Color Color::fromHSL(float hue, float saturation, float lightness, float alpha)
  103. {
  104. float m1, m2;
  105. Color col;
  106. hue = fmodf(hue, 1.0f);
  107. if (hue < 0.0f) hue += 1.0f;
  108. fixRange(saturation);
  109. fixRange(lightness);
  110. m2 = lightness <= 0.5f ? (lightness * (1 + saturation)) : (lightness + saturation - lightness * saturation);
  111. m1 = 2 * lightness - m2;
  112. col.red = computeHue(hue + 1.0f/3.0f, m1, m2);
  113. col.green = computeHue(hue, m1, m2);
  114. col.blue = computeHue(hue - 1.0f/3.0f, m1, m2);
  115. col.alpha = alpha;
  116. col.fixBounds();
  117. return col;
  118. }
  119. Color Color::fromHTML(const char* rgb, const float alpha) noexcept
  120. {
  121. Color fallback;
  122. DISTRHO_SAFE_ASSERT_RETURN(rgb != nullptr && rgb[0] != '\0', fallback);
  123. if (rgb[0] == '#')
  124. ++rgb;
  125. DISTRHO_SAFE_ASSERT_RETURN(rgb[0] != '\0', fallback);
  126. std::size_t rgblen = std::strlen(rgb);
  127. DISTRHO_SAFE_ASSERT_RETURN(rgblen == 3 || rgblen == 6, fallback);
  128. char rgbtmp[5] = { '0', 'x', '\0', '\0', '\0' };
  129. int r, g, b;
  130. if (rgblen == 3)
  131. {
  132. rgbtmp[2] = rgb[0];
  133. r = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)) * 17;
  134. rgbtmp[2] = rgb[1];
  135. g = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)) * 17;
  136. rgbtmp[2] = rgb[2];
  137. b = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)) * 17;
  138. }
  139. else
  140. {
  141. rgbtmp[2] = rgb[0];
  142. rgbtmp[3] = rgb[1];
  143. r = static_cast<int>(std::strtol(rgbtmp, nullptr, 16));
  144. rgbtmp[2] = rgb[2];
  145. rgbtmp[3] = rgb[3];
  146. g = static_cast<int>(std::strtol(rgbtmp, nullptr, 16));
  147. rgbtmp[2] = rgb[4];
  148. rgbtmp[3] = rgb[5];
  149. b = static_cast<int>(std::strtol(rgbtmp, nullptr, 16));
  150. }
  151. return Color(r, g, b, alpha);
  152. }
  153. void Color::interpolate(const Color& other, float u) noexcept
  154. {
  155. fixRange(u);
  156. const float oneMinusU = 1.0f - u;
  157. red = (red * oneMinusU) + (other.red * u);
  158. green = (green * oneMinusU) + (other.green * u);
  159. blue = (blue * oneMinusU) + (other.blue * u);
  160. alpha = (alpha * oneMinusU) + (other.alpha * u);
  161. fixBounds();
  162. }
  163. // -----------------------------------------------------------------------
  164. bool Color::isEqual(const Color& color, const bool withAlpha) noexcept
  165. {
  166. const uchar r1 = getFixedRange2(rgba[0]);
  167. const uchar g1 = getFixedRange2(rgba[1]);
  168. const uchar b1 = getFixedRange2(rgba[2]);
  169. const uchar a1 = getFixedRange2(rgba[3]);
  170. const uchar r2 = getFixedRange2(color.rgba[0]);
  171. const uchar g2 = getFixedRange2(color.rgba[1]);
  172. const uchar b2 = getFixedRange2(color.rgba[2]);
  173. const uchar a2 = getFixedRange2(color.rgba[3]);
  174. if (withAlpha)
  175. return (r1 == r2 && g1 == g2 && b1 == b2 && a1 == a2);
  176. else
  177. return (r1 == r2 && g1 == g2 && b1 == b2);
  178. }
  179. bool Color::isNotEqual(const Color& color, const bool withAlpha) noexcept
  180. {
  181. const uchar r1 = getFixedRange2(rgba[0]);
  182. const uchar g1 = getFixedRange2(rgba[1]);
  183. const uchar b1 = getFixedRange2(rgba[2]);
  184. const uchar a1 = getFixedRange2(rgba[3]);
  185. const uchar r2 = getFixedRange2(color.rgba[0]);
  186. const uchar g2 = getFixedRange2(color.rgba[1]);
  187. const uchar b2 = getFixedRange2(color.rgba[2]);
  188. const uchar a2 = getFixedRange2(color.rgba[3]);
  189. if (withAlpha)
  190. return (r1 != r2 || g1 != g2 || b1 != b2 || a1 != a2);
  191. else
  192. return (r1 != r2 || g1 != g2 || b1 != b2);
  193. }
  194. bool Color::operator==(const Color& color) noexcept
  195. {
  196. return isEqual(color, true);
  197. }
  198. bool Color::operator!=(const Color& color) noexcept
  199. {
  200. return isNotEqual(color, true);
  201. }
  202. // -----------------------------------------------------------------------
  203. void Color::fixBounds() noexcept
  204. {
  205. fixRange(red);
  206. fixRange(green);
  207. fixRange(blue);
  208. fixRange(alpha);
  209. }
  210. // -----------------------------------------------------------------------
  211. END_NAMESPACE_DGL