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.

256 lines
6.7KB

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