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 |
---|