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.

260 lines
6.8KB

  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::withAlpha(const float alpha) noexcept
  103. {
  104. Color color(*this);
  105. color.alpha = alpha;
  106. return color;
  107. }
  108. Color Color::fromHSL(float hue, float saturation, float lightness, float alpha)
  109. {
  110. float m1, m2;
  111. Color col;
  112. hue = fmodf(hue, 1.0f);
  113. if (hue < 0.0f) hue += 1.0f;
  114. fixRange(saturation);
  115. fixRange(lightness);
  116. m2 = lightness <= 0.5f ? (lightness * (1 + saturation)) : (lightness + saturation - lightness * saturation);
  117. m1 = 2 * lightness - m2;
  118. col.red = computeHue(hue + 1.0f/3.0f, m1, m2);
  119. col.green = computeHue(hue, m1, m2);
  120. col.blue = computeHue(hue - 1.0f/3.0f, m1, m2);
  121. col.alpha = alpha;
  122. col.fixBounds();
  123. return col;
  124. }
  125. Color Color::fromHTML(const char* rgb, const float alpha) noexcept
  126. {
  127. Color fallback;
  128. DISTRHO_SAFE_ASSERT_RETURN(rgb != nullptr && rgb[0] != '\0', fallback);
  129. if (rgb[0] == '#')
  130. ++rgb;
  131. DISTRHO_SAFE_ASSERT_RETURN(rgb[0] != '\0', fallback);
  132. std::size_t rgblen = std::strlen(rgb);
  133. DISTRHO_SAFE_ASSERT_RETURN(rgblen == 3 || rgblen == 6, fallback);
  134. char rgbtmp[5] = { '0', 'x', '\0', '\0', '\0' };
  135. int r, g, b;
  136. if (rgblen == 3)
  137. {
  138. rgbtmp[2] = rgb[0];
  139. r = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)) * 17;
  140. rgbtmp[2] = rgb[1];
  141. g = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)) * 17;
  142. rgbtmp[2] = rgb[2];
  143. b = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)) * 17;
  144. }
  145. else
  146. {
  147. rgbtmp[2] = rgb[0];
  148. rgbtmp[3] = rgb[1];
  149. r = static_cast<int>(std::strtol(rgbtmp, nullptr, 16));
  150. rgbtmp[2] = rgb[2];
  151. rgbtmp[3] = rgb[3];
  152. g = static_cast<int>(std::strtol(rgbtmp, nullptr, 16));
  153. rgbtmp[2] = rgb[4];
  154. rgbtmp[3] = rgb[5];
  155. b = static_cast<int>(std::strtol(rgbtmp, nullptr, 16));
  156. }
  157. return Color(r, g, b, alpha);
  158. }
  159. void Color::interpolate(const Color& other, float u) noexcept
  160. {
  161. fixRange(u);
  162. const float oneMinusU = 1.0f - u;
  163. red = (red * oneMinusU) + (other.red * u);
  164. green = (green * oneMinusU) + (other.green * u);
  165. blue = (blue * oneMinusU) + (other.blue * u);
  166. alpha = (alpha * oneMinusU) + (other.alpha * u);
  167. fixBounds();
  168. }
  169. // -----------------------------------------------------------------------
  170. bool Color::isEqual(const Color& color, const bool withAlpha) noexcept
  171. {
  172. const uchar r1 = getFixedRange2(rgba[0]);
  173. const uchar g1 = getFixedRange2(rgba[1]);
  174. const uchar b1 = getFixedRange2(rgba[2]);
  175. const uchar a1 = getFixedRange2(rgba[3]);
  176. const uchar r2 = getFixedRange2(color.rgba[0]);
  177. const uchar g2 = getFixedRange2(color.rgba[1]);
  178. const uchar b2 = getFixedRange2(color.rgba[2]);
  179. const uchar a2 = getFixedRange2(color.rgba[3]);
  180. if (withAlpha)
  181. return (r1 == r2 && g1 == g2 && b1 == b2 && a1 == a2);
  182. else
  183. return (r1 == r2 && g1 == g2 && b1 == b2);
  184. }
  185. bool Color::isNotEqual(const Color& color, const bool withAlpha) noexcept
  186. {
  187. const uchar r1 = getFixedRange2(rgba[0]);
  188. const uchar g1 = getFixedRange2(rgba[1]);
  189. const uchar b1 = getFixedRange2(rgba[2]);
  190. const uchar a1 = getFixedRange2(rgba[3]);
  191. const uchar r2 = getFixedRange2(color.rgba[0]);
  192. const uchar g2 = getFixedRange2(color.rgba[1]);
  193. const uchar b2 = getFixedRange2(color.rgba[2]);
  194. const uchar a2 = getFixedRange2(color.rgba[3]);
  195. if (withAlpha)
  196. return (r1 != r2 || g1 != g2 || b1 != b2 || a1 != a2);
  197. else
  198. return (r1 != r2 || g1 != g2 || b1 != b2);
  199. }
  200. bool Color::operator==(const Color& color) noexcept
  201. {
  202. return isEqual(color, true);
  203. }
  204. bool Color::operator!=(const Color& color) noexcept
  205. {
  206. return isNotEqual(color, true);
  207. }
  208. // -----------------------------------------------------------------------
  209. void Color::fixBounds() noexcept
  210. {
  211. fixRange(red);
  212. fixRange(green);
  213. fixRange(blue);
  214. fixRange(alpha);
  215. }
  216. // -----------------------------------------------------------------------
  217. END_NAMESPACE_DGL