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.

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