| 1 | // ============================================================ // |
|---|
| 2 | // // |
|---|
| 3 | // File : aw_rgb.hxx // |
|---|
| 4 | // Purpose : // |
|---|
| 5 | // // |
|---|
| 6 | // Coded by Ralf Westram (coder@reallysoft.de) in June 2016 // |
|---|
| 7 | // http://www.arb-home.de/ // |
|---|
| 8 | // // |
|---|
| 9 | // ============================================================ // |
|---|
| 10 | |
|---|
| 11 | #ifndef AW_RGB_HXX |
|---|
| 12 | #define AW_RGB_HXX |
|---|
| 13 | |
|---|
| 14 | #ifndef CXXFORWARD_H |
|---|
| 15 | #include <cxxforward.h> |
|---|
| 16 | #endif |
|---|
| 17 | #ifndef ARB_ASSERT_H |
|---|
| 18 | #include <arb_assert.h> |
|---|
| 19 | #endif |
|---|
| 20 | #ifndef _STDINT_H |
|---|
| 21 | #include <stdint.h> |
|---|
| 22 | #endif |
|---|
| 23 | #ifndef _GLIBCXX_CMATH |
|---|
| 24 | #include <cmath> |
|---|
| 25 | #endif |
|---|
| 26 | #ifndef _GLIBCXX_ALGORITHM |
|---|
| 27 | #include <algorithm> |
|---|
| 28 | #endif |
|---|
| 29 | |
|---|
| 30 | #ifndef aw_assert |
|---|
| 31 | #define aw_assert(bed) arb_assert(bed) |
|---|
| 32 | #endif |
|---|
| 33 | |
|---|
| 34 | typedef unsigned long AW_rgb; // =XColor.pixel (motif color format) |
|---|
| 35 | |
|---|
| 36 | class AW_rgb_normalized; |
|---|
| 37 | |
|---|
| 38 | class AW_rgb16 { |
|---|
| 39 | uint16_t R, G, B; |
|---|
| 40 | |
|---|
| 41 | void rescale(uint16_t my_max); |
|---|
| 42 | public: |
|---|
| 43 | static CONSTEXPR float MAX = 65535.0; |
|---|
| 44 | |
|---|
| 45 | AW_rgb16() : R(0), G(0), B(0) {} |
|---|
| 46 | AW_rgb16(uint16_t red, uint16_t green, uint16_t blue) : R(red), G(green), B(blue) {} |
|---|
| 47 | explicit AW_rgb16(const char *colorname); |
|---|
| 48 | explicit inline AW_rgb16(const AW_rgb_normalized& o); |
|---|
| 49 | explicit inline AW_rgb16(AW_rgb m) { |
|---|
| 50 | B = m & 255; m >>= 8; |
|---|
| 51 | G = m & 255; m >>= 8; |
|---|
| 52 | R = m & 255; |
|---|
| 53 | } |
|---|
| 54 | |
|---|
| 55 | bool operator == (const AW_rgb16& o) const { return R==o.R && G==o.G && B == o.B; } |
|---|
| 56 | bool operator != (const AW_rgb16& o) const { return !operator==(o); } |
|---|
| 57 | |
|---|
| 58 | uint16_t r() const { return R; } |
|---|
| 59 | uint16_t g() const { return G; } |
|---|
| 60 | uint16_t b() const { return B; } |
|---|
| 61 | |
|---|
| 62 | const char *ascii() const; |
|---|
| 63 | }; |
|---|
| 64 | |
|---|
| 65 | class AW_rgb_normalized { |
|---|
| 66 | float R, G, B; |
|---|
| 67 | |
|---|
| 68 | static bool is_normal(const float& f) { return f >= 0.0 && f<=1.0; } |
|---|
| 69 | static const float& normal(const float& f) { aw_assert(is_normal(f)); return f; } |
|---|
| 70 | |
|---|
| 71 | protected: |
|---|
| 72 | AW_rgb_normalized(void*, float red, float green, float blue) : // accepts any values |
|---|
| 73 | R(red), |
|---|
| 74 | G(green), |
|---|
| 75 | B(blue) |
|---|
| 76 | {} |
|---|
| 77 | public: |
|---|
| 78 | AW_rgb_normalized(float red, float green, float blue) : |
|---|
| 79 | R(normal(red)), |
|---|
| 80 | G(normal(green)), |
|---|
| 81 | B(normal(blue)) |
|---|
| 82 | {} |
|---|
| 83 | explicit AW_rgb_normalized(const AW_rgb16& o) : |
|---|
| 84 | R(normal(o.r()/AW_rgb16::MAX)), |
|---|
| 85 | G(normal(o.g()/AW_rgb16::MAX)), |
|---|
| 86 | B(normal(o.b()/AW_rgb16::MAX)) |
|---|
| 87 | {} |
|---|
| 88 | #if defined(Cxx11) |
|---|
| 89 | explicit AW_rgb_normalized(const char *colorname) : AW_rgb_normalized(AW_rgb16(colorname)) {} |
|---|
| 90 | #else // !defined(Cxx11) |
|---|
| 91 | explicit AW_rgb_normalized(const char *colorname) { *this = AW_rgb_normalized(AW_rgb16(colorname)); } |
|---|
| 92 | #endif |
|---|
| 93 | |
|---|
| 94 | float r() const { return R; } |
|---|
| 95 | float g() const { return G; } |
|---|
| 96 | float b() const { return B; } |
|---|
| 97 | }; |
|---|
| 98 | |
|---|
| 99 | inline AW_rgb16::AW_rgb16(const AW_rgb_normalized& o) : R(o.r()*MAX), G(o.g()*MAX), B(o.b()*MAX) {} |
|---|
| 100 | |
|---|
| 101 | // --------------------------- |
|---|
| 102 | // color calculation |
|---|
| 103 | // |
|---|
| 104 | // Note: avoids color overflows (eg. white cannot get any whiter, black cannot get any blacker) |
|---|
| 105 | |
|---|
| 106 | class AW_rgb_diff : private AW_rgb_normalized { |
|---|
| 107 | public: |
|---|
| 108 | AW_rgb_diff(float red, float green, float blue) : AW_rgb_normalized(NULp, red, green, blue) {} |
|---|
| 109 | |
|---|
| 110 | float r() const { return AW_rgb_normalized::r(); } |
|---|
| 111 | float g() const { return AW_rgb_normalized::g(); } |
|---|
| 112 | float b() const { return AW_rgb_normalized::b(); } |
|---|
| 113 | |
|---|
| 114 | AW_rgb_diff abs() const { |
|---|
| 115 | return AW_rgb_diff(fabs(r()), |
|---|
| 116 | fabs(g()), |
|---|
| 117 | fabs(b())); |
|---|
| 118 | } |
|---|
| 119 | }; |
|---|
| 120 | |
|---|
| 121 | inline AW_rgb_diff operator-(const AW_rgb_normalized& c1, const AW_rgb_normalized& c2) { |
|---|
| 122 | return AW_rgb_diff(c1.r()-c2.r(), |
|---|
| 123 | c1.g()-c2.g(), |
|---|
| 124 | c1.b()-c2.b()); |
|---|
| 125 | } |
|---|
| 126 | |
|---|
| 127 | // AW_rgb_diff (add, scale, negate) |
|---|
| 128 | inline AW_rgb_diff operator+(const AW_rgb_diff& d1, const AW_rgb_diff& d2) { |
|---|
| 129 | return AW_rgb_diff(d1.r()+d2.r(), |
|---|
| 130 | d1.g()+d2.g(), |
|---|
| 131 | d1.b()+d2.b()); |
|---|
| 132 | } |
|---|
| 133 | inline AW_rgb_diff operator*(const AW_rgb_diff& d, const float& f) { return AW_rgb_diff(d.r()*f, d.g()*f, d.b()*f); } |
|---|
| 134 | inline AW_rgb_diff operator*(const float& f, const AW_rgb_diff& d) { return d*f; } |
|---|
| 135 | inline AW_rgb_diff operator-(const AW_rgb_diff& d) { return d*-1.0; } |
|---|
| 136 | |
|---|
| 137 | inline AW_rgb_diff max(const AW_rgb_diff& d1, const AW_rgb_diff& d2) { |
|---|
| 138 | return AW_rgb_diff(std::max(d1.r(), d2.r()), |
|---|
| 139 | std::max(d1.g(), d2.g()), |
|---|
| 140 | std::max(d1.b(), d2.b())); |
|---|
| 141 | } |
|---|
| 142 | |
|---|
| 143 | // modify color using diff: |
|---|
| 144 | inline float avoid_overflow(float f) { return f<0.0 ? 0.0 : (f>1.0 ? 1.0 : f); } |
|---|
| 145 | |
|---|
| 146 | inline AW_rgb_normalized operator+(const AW_rgb_normalized& col, const AW_rgb_diff& off) { |
|---|
| 147 | return AW_rgb_normalized(avoid_overflow(col.r()+off.r()), |
|---|
| 148 | avoid_overflow(col.g()+off.g()), |
|---|
| 149 | avoid_overflow(col.b()+off.b())); |
|---|
| 150 | } |
|---|
| 151 | inline AW_rgb_normalized operator-(const AW_rgb_normalized& col, const AW_rgb_diff& off) { return col + -off; } |
|---|
| 152 | |
|---|
| 153 | // allow to calculate directly with AW_rgb16: |
|---|
| 154 | inline AW_rgb_diff operator-(const AW_rgb16& c1, const AW_rgb16& c2) { return AW_rgb_normalized(c1)-AW_rgb_normalized(c2); } |
|---|
| 155 | inline AW_rgb16 operator+(const AW_rgb16& col, const AW_rgb_diff& off) { return AW_rgb16(AW_rgb_normalized(col)+off); } |
|---|
| 156 | inline AW_rgb16 operator-(const AW_rgb16& col, const AW_rgb_diff& off) { return AW_rgb16(AW_rgb_normalized(col)-off); } |
|---|
| 157 | |
|---|
| 158 | |
|---|
| 159 | #else |
|---|
| 160 | #error aw_rgb.hxx included twice |
|---|
| 161 | #endif // AW_RGB_HXX |
|---|