Arctic Engine
Designed to give you control and not take anything away.
rgba.h
1// The MIT License (MIT)
2//
3// Copyright (c) 2015 - 2016 Inigo Quilez
4// Copyright (c) 2017 - 2020 Huldra
5//
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to deal
8// in the Software without restriction, including without limitation the rights
9// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
10// copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12//
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15//
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22// IN THE SOFTWARE.
23
24#ifndef ENGINE_RGBA_H_
25#define ENGINE_RGBA_H_
26
27#include "engine/arctic_types.h"
28
29#define MASK_LO 0x00ff00fful
30#define MASK_HI 0xff00ff00ul
31#define MASK_BLEND 0xfefefefful
32
33namespace arctic {
34
37struct Rgba {
38 union {
39 struct {
40 Ui8 r;
41 Ui8 g;
42 Ui8 b;
43 Ui8 a;
44 };
45 Ui32 rgba;
46 Ui8 element[4];
47 };
48
49 Rgba() {}
50
51 explicit Rgba(Ui8 r_in, Ui8 g_in, Ui8 b_in) {
52 r = r_in;
53 g = g_in;
54 b = b_in;
55 a = 255;
56 }
58 explicit Rgba(Ui8 r_in, Ui8 g_in, Ui8 b_in, Ui8 a_in) {
59 r = r_in;
60 g = g_in;
61 b = b_in;
62 a = a_in;
63 }
64
66 explicit Rgba(Ui32 rgba_in) {
67 rgba = rgba_in;
68 }
69 Ui8 &operator[](Si32 i) {
70 return element[i];
71 }
72 const Ui8 &operator[](Si32 i) const {
73 return element[i];
74 }
75
76 Rgba &operator =(const Rgba &v) {
77 rgba = v.rgba;
78 return *this;
79 }
80
81 const bool operator== (const Rgba &v) const {
82 return rgba == v.rgba;
83 }
84 const bool operator!= (const Rgba &v) const {
85 return rgba != v.rgba;
86 }
87};
88
89inline Rgba Mix(Rgba const &a, Rgba const &b, float const f) {
90 return Rgba(static_cast<Ui8>(a.r * (1.0f - f) + f * b.r),
91 static_cast<Ui8>(a.g * (1.0f - f) + f * b.g),
92 static_cast<Ui8>(a.b * (1.0f - f) + f * b.b),
93 static_cast<Ui8>(a.a * (1.0f - f) + f * b.a));
94}
95inline Rgba Mix(Rgba const a, Rgba const b, float const f) {
96 return Rgba(static_cast<Ui8>(a.r * (1.0f - f) + f * b.r),
97 static_cast<Ui8>(a.g * (1.0f - f) + f * b.g),
98 static_cast<Ui8>(a.b * (1.0f - f) + f * b.b),
99 static_cast<Ui8>(a.a * (1.0f - f) + f * b.a));
100}
101inline Rgba Min(const Rgba a, const Rgba b) {
102 return Rgba((a.r < b.r) ? a.r : b.r,
103 (a.g < b.g) ? a.g : b.g,
104 (a.b < b.b) ? a.b : b.b,
105 (a.a < b.a) ? a.a : b.a);
106}
107inline Rgba Max(const Rgba a, const Rgba b) {
108 return Rgba((a.r > b.r) ? a.r : b.r,
109 (a.g > b.g) ? a.g : b.g,
110 (a.b > b.b) ? a.b : b.b,
111 (a.a > b.a) ? a.a : b.a);
112}
113inline Rgba Clamp(const Rgba rgba, const Rgba mi, const Rgba ma) {
114 return Max(Min(rgba, ma), mi);
115}
116
117inline Rgba BlendFast(Rgba c1, Rgba c2) {
118 return Rgba(static_cast<Ui32>((
119 (static_cast<Ui64>(c1.rgba) & MASK_BLEND) +
120 (static_cast<Ui64>(c2.rgba) & MASK_BLEND)) >> 1u));
121}
122
123inline Rgba Mix(Rgba c1, Rgba c2, Ui32 alpha_1_8) {
124 Ui32 a = c1.rgba & MASK_LO;
125 Ui32 b = c2.rgba & MASK_LO;
126 Ui32 d = a + (((b - a) * alpha_1_8) >> 8u);
127 d = d & MASK_LO;
128
129 Ui32 m = (c1.rgba & MASK_HI) >> 8u;
130 Ui32 n = (c2.rgba & MASK_HI) >> 8u;
131 Ui32 e = (c1.rgba & MASK_HI) + ((n - m) * alpha_1_8);
132 e = e & MASK_HI;
133
134 return Rgba(d | e);
135}
136
137inline Rgba Scale(Rgba c, Ui32 alpha_1_8) {
138 Ui32 a = c.rgba & MASK_LO;
139 Ui32 d = (a * alpha_1_8) >> 8u;
140 d = d & MASK_LO;
141
142 a = (c.rgba & MASK_HI) >> 8u;
143 Ui32 e = a * alpha_1_8;
144 e = e & MASK_HI;
145
146 return Rgba(d | e);
147}
148
149inline Rgba Lerp(Rgba c1, Rgba c2, Si32 alpha_1_8) {
150 Ui32 a = c1.rgba & MASK_LO;
151 Ui32 b = c2.rgba & MASK_LO;
152 Ui32 d = a + (((b - a) * static_cast<Ui32>(alpha_1_8)) >> 8u);
153 d = d & MASK_LO;
154
155 a = (c1.rgba & MASK_HI) >> 8u;
156 b = (c2.rgba & MASK_HI) >> 8u;
157 Ui32 e = (c1.rgba & MASK_HI) + ((b - a) * static_cast<Ui32>(alpha_1_8));
158 e = e & MASK_HI;
159
160 return Rgba(d | e);
161}
162
163inline Rgba GetGray(Rgba c) {
164 Ui32 res = 19595 * static_cast<Ui32>(c.r)
165 + 38470 * static_cast<Ui32>(c.g)
166 + 7471 * static_cast<Ui32>(c.b);
167 return Rgba(res >> 16);
168}
169
182inline Rgba Bilerp(Rgba a, Rgba b, Rgba c, Rgba d, Si32 ax, Si32 ay) {
183 const Si32 axy = (ax * ay) >> 8u;
184 Ui32 aa = a.rgba & MASK_LO;
185 Ui32 bb = b.rgba & MASK_LO;
186 Ui32 cc = c.rgba & MASK_LO;
187 Ui32 dd = d.rgba & MASK_LO;
188
189 Ui32 rb = (aa + (((bb - aa) * static_cast<Ui32>(ax)
190 + (cc - aa) * static_cast<Ui32>(ay)
191 + (aa + dd - bb - cc) * static_cast<Ui32>(axy)) >> 8u))
192 & MASK_LO;
193
194 aa = (a.rgba & MASK_HI) >> 8u;
195 bb = (b.rgba & MASK_HI) >> 8u;
196 cc = (c.rgba & MASK_HI) >> 8u;
197 dd = (d.rgba & MASK_HI) >> 8u;
198
199 Ui32 gg = ((a.rgba & MASK_HI) + (
200 (bb - aa) * static_cast<Ui32>(ax)
201 + (cc - aa) * static_cast<Ui32>(ay)
202 + (aa + dd - bb - cc) * static_cast<Ui32>(axy)))
203 & MASK_HI;
204
205 return Rgba(rb | gg);
206}
207
209
210} // namespace arctic
211
212#undef MASK_BLEND
213#undef MASK_HI
214#undef MASK_LO
215
216#endif // ENGINE_RGBA_H_
Rgba Bilerp(Rgba a, Rgba b, Rgba c, Rgba d, Si32 ax, Si32 ay)
Interpolate color in a bi-linear way.
Definition: rgba.h:182
Definition: rgba.h:37
Rgba(Ui8 r_in, Ui8 g_in, Ui8 b_in, Ui8 a_in)
a = 255 is opaque, a = 0 is transparent.
Definition: rgba.h:58
Rgba(Ui32 rgba_in)
rgba_in is 32 bits containing 0xAABBGGRR. 0xff00ff00 is opaque green.
Definition: rgba.h:66