Rose
Color.h
1 
24 #pragma once
25 
26 #include <algorithm>
27 #include <array>
28 #include <SDL.h>
29 #include <iostream>
30 #include "Configuration.h"
31 
36 namespace rose::color {
37 
46  struct Value : public std::array<float, 4> {
50  constexpr Value() noexcept: std::array<float, 4>() {
51  for (auto &v : *this) {
52  v = 0.f;
53  }
54  }
55 
56  constexpr explicit Value(std::array<float, 4> v) noexcept: std::array<float, 4>(v) {}
57  };
58 
59  struct HSVA;
64  struct RGBA : public Value {
65 
66  static const RGBA TransparentBlack;
67 
68  static const RGBA OpaqueBlack;
69 
70  static const RGBA OpaqueWhite;
71 
72  constexpr RGBA() noexcept = default;
73 
75  constexpr explicit RGBA(std::array<float, 4> v) noexcept: Value(v) {}
76 
78  constexpr RGBA(uint r, uint g, uint b, uint a) noexcept {
79  operator[](0) = (float) (r & 0xffu) / 255.f;
80  operator[](1) = (float) (g & 0xffu) / 255.f;
81  operator[](2) = (float) (b & 0xffu) / 255.f;
82  operator[](3) = (float) (a & 0xffu) / 255.f;
83  }
84 
86  constexpr RGBA(float r, float g, float b, float a) noexcept {
87  operator[](0) = r;
88  operator[](1) = g;
89  operator[](2) = b;
90  operator[](3) = a;
91  }
92 
94  constexpr explicit RGBA(const HSVA &hsva) noexcept;
95 
97  [[nodiscard]] constexpr SDL_Color toSdlColor() const noexcept {
98  SDL_Color color{};
99  color.r = (uint8_t)(r() * 255.f);
100  color.g = (uint8_t)(g() * 255.f);
101  color.b = (uint8_t)(b() * 255.f);
102  color.a = (uint8_t)(a() * 255.f);
103  return color;
104  }
105 
107  constexpr float &r() noexcept { return operator[](0); }
108 
110  [[nodiscard]] constexpr float r() const noexcept { return operator[](0); }
111 
113  constexpr float &g() noexcept { return operator[](1); }
114 
116  [[nodiscard]] constexpr float g() const noexcept { return operator[](1); }
117 
119  constexpr float &b() noexcept { return operator[](2); }
120 
122  [[nodiscard]] constexpr float b() const noexcept { return operator[](2); }
123 
125  constexpr float &a() noexcept { return operator[](3); }
126 
128  [[nodiscard]] constexpr float a() const noexcept { return operator[](3); }
129 
131  constexpr RGBA operator*(float m) const noexcept {
132  return RGBA{r() * m, g() * m, b() * m, a() * m};
133  }
134 
135  [[nodiscard]] constexpr RGBA brightness(float m) const noexcept {
136  return RGBA{r() * m, g() * m, b() * m, a() * m};
137  }
138 
140  constexpr RGBA operator+(const RGBA color) const noexcept {
141  return RGBA{r() + color.r(), g() + color.g(), b() + color.b(), a() + color.a()};
142  }
143 
144  [[nodiscard]] constexpr RGBA interpolate(const RGBA& to, float v) const noexcept {
145  auto inter = [](float from, float to, float value) -> float {
146  return from + (to - from) * value;
147  };
148 
149  RGBA result{};
150  result[0] = inter(operator[](0), to[0], v);
151  result[1] = inter(operator[](1), to[1], v);
152  result[2] = inter(operator[](2), to[2], v);
153  result[3] = inter(operator[](3), to[3], v);
154 
155  return result;
156  }
157 
158  [[nodiscard]] constexpr RGBA withAlpha(float alpha) const noexcept {
159  auto r = *this;
160  r[3] = alpha;
161  return r;
162  }
163 
164  [[nodiscard]] HSVA toHSVA() const;
165  };
166 
167  template<typename T>
168  static constexpr T mod(T x, T y) noexcept {
169  if (y == 0)
170  return 0;
171  if constexpr (std::is_integral_v<T>) {
172  return x % y;
173  } else {
174  auto trunc = (float) ((int) (x / y));
175  auto r = x - trunc * y;
176  return r;
177  }
178  }
179 
184  struct HSVA : public Value {
185  constexpr HSVA() noexcept = default;
186 
187  constexpr explicit HSVA(std::array<float, 4> v) noexcept: Value(v) {
188  operator[](0) /= 360.f;
189  }
190 
191  constexpr HSVA(float h, float s, float v, float a) noexcept: Value() {
192  operator[](0) = h / 360.f;
193  operator[](1) = s;
194  operator[](2) = v;
195  operator[](3) = a;
196  }
197 
198  [[nodiscard]] constexpr HSVA modValue(float dValue) const noexcept {
199  HSVA result{*this};
200  result[2] += dValue;
201  return result;
202  }
203 
209  [[nodiscard]] constexpr HSVA withHue(uint32_t hue) const {
210  return HSVA{{(float) (hue % 360) / 360.f, saturation(), value(), alpha()}};
211  }
212 
218  [[nodiscard]] constexpr HSVA withSaturation(float sat) const {
219  HSVA result{*this};
220  result[1] = std::clamp(sat, 0.f, 1.f);
221  return result;
222  }
223 
229  [[nodiscard]] constexpr HSVA withValue(float val) const {
230  HSVA result{*this};
231  result[2] = std::clamp(val, 0.f, 1.f);
232  return result;
233  }
234 
240  [[nodiscard]] constexpr HSVA withMinSaturation(float sat) const {
241  return HSVA{{hue(), std::max(saturation(),sat), value(), alpha()}};
242  }
243 
248  [[nodiscard]] constexpr HSVA contrasting() const {
249  float value = 0;
250  if (operator[](2) < 0.5f)
251  value = operator[](2) + 0.4f;
252  else
253  value = operator[](2) - 0.4f;
254  return HSVA{{operator[](0), operator[](1), value, operator[](3)}};
255  }
256 
262  [[nodiscard]] constexpr RGBA toRGBA() const noexcept {
263  auto H = mod(operator[](0) * 360.0f, 360.f);
264  float S = operator[](1);
265  float V = operator[](2);
266  float C = S * V;
267  float X = C * (1 - abs(mod(H / 60.0f, 2.f) - 1));
268  float m = V - C;
269  float r = 0.f, g = 0.f, b = 0.f;
270  if (H >= 0 && H < 60) {
271  r = C, g = X, b = 0;
272  } else if (H >= 60 && H < 120) {
273  r = X, g = C, b = 0;
274  } else if (H >= 120 && H < 180) {
275  r = 0, g = C, b = X;
276  } else if (H >= 180 && H < 240) {
277  r = 0, g = X, b = C;
278  } else if (H >= 240 && H < 300) {
279  r = X, g = 0, b = C;
280  } else {
281  r = C, g = 0, b = X;
282  }
283 
284  return RGBA{std::array<float, 4>{r + m, g + m, b + m, operator[](3)}};
285  }
286 
287  constexpr float &hue() noexcept { return operator[](0); }
288 
289  [[nodiscard]] constexpr float hue() const noexcept { return operator[](0); }
290 
291  constexpr float &saturation() noexcept { return operator[](1); }
292 
293  [[nodiscard]] constexpr float saturation() const noexcept { return operator[](1); }
294 
295  constexpr float &value() noexcept { return operator[](2); }
296 
297  [[nodiscard]] constexpr float value() const noexcept { return operator[](2); }
298 
299  constexpr float &alpha() noexcept { return operator[](3); }
300 
301  [[nodiscard]] constexpr float alpha() const noexcept { return operator[](3); }
302 
303  [[nodiscard]] constexpr HSVA interpolate(const HSVA& to, float v) const noexcept {
304  auto inter = [](float from, float to, float value) -> float {
305  return from + (to - from) * value;
306  };
307 
308  HSVA result{};
309  result[0] = inter(operator[](0), to[0], v);
310  result[1] = inter(operator[](1), to[1], v);
311  result[2] = inter(operator[](2), to[2], v);
312  result[3] = inter(operator[](3), to[3], v);
313 
314  return result;
315  }
316  };
317 
318  constexpr RGBA::RGBA(const HSVA &hsva) noexcept : RGBA(hsva.toRGBA()) {
319  }
320 
327  static constexpr uint32_t set_a_value(uint32_t pixel, uint32_t a) { return (pixel & cmask) | a << ashift; }
328 
329 
335  template<class Representation>
336  class Interpolator {
337  public:
338  using color_type = Representation;
339  using index_type = ssize_t;
340 
341  protected:
342  color_type mStart;
343  color_type mFinish;
344  index_type mSteps;
346 
351  class Iterator {
352  public:
353  using iterator_category = std::random_access_iterator_tag;
354  using difference_type = index_type;
355  using value_type = color_type;
356  using pointer = color_type *;
357  using reference = color_type &;
358 
359  protected:
360  const Interpolator<color_type> *mInterpolator{nullptr};
361  color_type mValue{};
362  index_type mIndex{0};
363 
364  public:
365  Iterator() = default;
366 
371  explicit Iterator(const Interpolator *interpolator) : mInterpolator(interpolator) {
372  mValue = interpolator->mStart;
373  }
374 
380  Iterator(const Interpolator *interpolator, difference_type index) : Iterator(interpolator) {
381  if (index >= 0 && index < interpolator->mSteps)
382  mIndex = index;
383  else
384  mIndex = interpolator->mSteps;
385  mValue = (*mInterpolator)(mIndex);
386  }
387 
392  Iterator(const Iterator &iterator) : Iterator(iterator.mInterpolator) {
393  mIndex = iterator.mIndex;
394  mValue = iterator.mValue;
395  }
396 
401  Iterator(Iterator &&iterator) noexcept: Iterator(iterator.mInterpolator) {
402  mIndex = iterator.mIndex;
403  mValue = iterator.mValue;
404  iterator.mInterpolator = nullptr;
405  }
406 
412  Iterator &operator=(const Iterator &iterator) {
413  mInterpolator = iterator.mInterpolator;
414  mIndex = iterator.mIndex;
415  mValue = iterator.mValue;
416  return *this;
417  }
418 
424  Iterator &operator=(Iterator &&iterator) noexcept {
425  mInterpolator = iterator.mInterpolator;
426  mIndex = iterator.mIndex;
427  mValue = iterator.mValue;
428  iterator.mInterpolator = nullptr;
429  return *this;
430  }
431 
436  reference operator*() const { return mValue; }
437 
442  pointer operator->() const { return &mValue; }
443 
446  if (mIndex < mInterpolator->mSteps) {
447  ++mIndex;
448  mValue = (*mInterpolator)(mIndex);
449  }
450  return *this;
451  }
452 
455  Iterator tmp{*this};
456  operator++();
457  return tmp;
458  }
459 
460  bool operator==(const Iterator &other) const {
461  return mInterpolator == other.mInterpolator && mIndex == other.mIndex;
462  }
463 
464  bool operator!=(const Iterator &other) const {
465  return mInterpolator != other.mInterpolator || mIndex != other.mIndex;
466  }
467  };
468 
469  public:
470  Interpolator() = delete;
471 
472  Interpolator(Representation start, Representation finish, size_t steps)
473  : mStart(start), mFinish(finish), mSteps(steps) {
474  auto fSteps = static_cast<float>(mSteps);
475  std::transform(mStart.begin(), mStart.end(), mFinish.begin(), mIncrement.begin(),
476  [=](float start, float finish) {
477  return (finish - start) / fSteps;
478  });
479  }
480 
486  color_type operator()(index_type index) {
487  color_type result{};
488  auto fIndex = static_cast<float>(index);
489  std::transform(mStart.begin(), mIncrement.begin(), result.begin(),
490  [=](float start, float increment) {
491  return start + increment * fIndex;
492  });
493  return result;
494  }
495 
500  Iterator begin() {
501  return Iterator{*this};
502  }
503 
508  Iterator end() {
509  Iterator iterator{*this};
510  iterator.mIndex = mSteps;
511  return iterator;
512  }
513  };
514 
515  static constexpr color::HSVA DarkBaseColorHSVA{{200.f, .00, .25, 1.0}};
516  static constexpr color::RGBA DarkBaseColor{DarkBaseColorHSVA};
517  static constexpr color::RGBA DarkTopColor{DarkBaseColorHSVA.modValue(0.2)};
518  static constexpr color::RGBA DarkBotColor{DarkBaseColorHSVA.modValue(-0.15)};
519  static constexpr color::RGBA DarkLeftColor{DarkBaseColorHSVA.modValue(0.1)};
520  static constexpr color::RGBA DarkRightColor{DarkBaseColorHSVA.modValue(-0.15)};
521  static constexpr color::RGBA DarkInvertColor{DarkBaseColorHSVA.modValue(-0.075)};
522  static constexpr color::RGBA DarkTextColour{DarkBaseColorHSVA.contrasting()};
523  static constexpr color::HSVA DarkRedHSVA{ 0.f, 1.f, 0.55f, 1.f};
524 // (67,139,40) https://www.color-hex.com/color-palette/105943
525  static constexpr color::HSVA DarkGreenHSVA{79.f,1.f,.4f,1.f};
526  static constexpr color::HSVA DarkYellowHSVA{ 50.f, 1.f, 0.55f, 1.f};
527 }
528 
529 inline std::ostream& operator<<(std::ostream& strm, const rose::color::RGBA& rgba) {
530  strm << "[RGBA " << rgba.r() << ',' << rgba.g() << ',' << rgba.b() << ',' << rgba.a() << "] ";
531  return strm;
532 }
533 
534 inline std::ostream& operator<<(std::ostream& strm, const rose::color::HSVA& hsva) {
535  strm << "[HSVA " << hsva.hue() << ',' << hsva.saturation() << ',' << hsva.value() << ',' << hsva.alpha() << "] ";
536  return strm;
537 }
constexpr RGBA(std::array< float, 4 > v) noexcept
Construct RGBA from a std::array of floats in range [0.0 ... 1.0].
Definition: Color.h:75
GaugeIndex & operator++(GaugeIndex &gaugeIndex)
GaugeIndex pre-increment operator.
Definition: Gauge.h:45
constexpr RGBA(uint r, uint g, uint b, uint a) noexcept
Construct RGBA from unsigned integer components in range [0 ... 255].
Definition: Color.h:78
constexpr float a() const noexcept
Value access to the Alpha value.
Definition: Color.h:128
constexpr HSVA withValue(float val) const
Get a new colour from this HSL colour by modifying the value.
Definition: Color.h:229
constexpr RGBA operator+(const RGBA color) const noexcept
Add two RGBA values together.
Definition: Color.h:140
Red Green Blue Alpha representation of a color.
Definition: Color.h:64
Color management.
Definition: Color.cpp:10
color_type mStart
The starting color.
Definition: Color.h:342
constexpr float & g() noexcept
Reference access to the Green value.
Definition: Color.h:113
index_type mIndex
The index of the current position.
Definition: Color.h:362
Iterator(Iterator &&iterator) noexcept
Move constructor.
Definition: Color.h:401
constexpr float & a() noexcept
Reference access to the Alpha value.
Definition: Color.h:125
constexpr float b() const noexcept
Value access to the Blue value.
Definition: Color.h:122
constexpr HSVA contrasting() const
Get a new contrasting colour to this HSL colour.
Definition: Color.h:248
color_type mValue
The current color Value.
Definition: Color.h:361
Hue Saturation Value (or Brightness) representation of a color.
Definition: Color.h:184
Iterator & operator++()
Pre-increment operator.
Definition: Color.h:445
constexpr HSVA withHue(uint32_t hue) const
Get a new colour from this HSL colour by modifying the hue.
Definition: Color.h:209
constexpr float r() const noexcept
Value access to the red value.
Definition: Color.h:110
constexpr RGBA operator*(float m) const noexcept
Multiply a color by a constant.
Definition: Color.h:131
The actual value of a color.
Definition: Color.h:46
Iterator & operator=(const Iterator &iterator)
Assignment operator.
Definition: Color.h:412
Iterator end()
Get an iterator pointing one past the end of the interpolated range.
Definition: Color.h:508
Iterator(const Interpolator *interpolator, difference_type index)
Constructor, set the iterator to a random location, or end if index is out of range.
Definition: Color.h:380
An iterator over the range of the interpolator.
Definition: Color.h:351
Iterator & operator=(Iterator &&iterator) noexcept
Move assignment operator.
Definition: Color.h:424
constexpr Value() noexcept
Constructor, initialize color to transparent black.
Definition: Color.h:50
color_type mFinish
The finishing color.
Definition: Color.h:343
Iterator(const Iterator &iterator)
Copy constructor.
Definition: Color.h:392
constexpr RGBA(float r, float g, float b, float a) noexcept
Construct RGBA from float components in range [0.0 ... 1.0].
Definition: Color.h:86
const Interpolator< color_type > * mInterpolator
A pointer to the Interpolator.
Definition: Color.h:360
Provide linear interpolation between two color Values.
Definition: Color.h:336
reference operator*() const
Return a reference to the iterator value.
Definition: Color.h:436
Iterator operator++(int)
Post-increment operator.
Definition: Color.h:454
constexpr float & b() noexcept
Reference access to the Blue value.
Definition: Color.h:119
int pixel(SDL_Renderer *renderer, Sint16 x, Sint16 y)
Draw pixel in currently set color.
Definition: GfxPrimitives.cpp:20
color_type operator()(index_type index)
Get the interpolated value at index.
Definition: Color.h:486
constexpr float & r() noexcept
Reference access to the Red value.
Definition: Color.h:107
constexpr RGBA toRGBA() const noexcept
Convert to RGBA in an array of floats.
Definition: Color.h:262
Iterator begin()
Get an iterator pointing to the start of the interpolated range.
Definition: Color.h:500
Iterator(const Interpolator *interpolator)
Constructor, set the iterator to begin.
Definition: Color.h:371
pointer operator->() const
Return a pointer to the iterator value.
Definition: Color.h:442
constexpr float g() const noexcept
Value access to the red value.
Definition: Color.h:116
constexpr HSVA withSaturation(float sat) const
Get a new colour from this HSL colour by modifying the saturation.
Definition: Color.h:218
constexpr SDL_Color toSdlColor() const noexcept
Convert this colour to an SDL_Color.
Definition: Color.h:97
index_type mSteps
The number of steps in the interpolation.
Definition: Color.h:344
Value mIncrement
The amount to increment.
Definition: Color.h:345
constexpr HSVA withMinSaturation(float sat) const
Get a new colour from this HSL colour by modifying the saturation value.
Definition: Color.h:240