1 /*
2  * DQt - D bindings for the Qt Toolkit
3  *
4  * GNU Lesser General Public License Usage
5  * This file may be used under the terms of the GNU Lesser
6  * General Public License version 3 as published by the Free Software
7  * Foundation and appearing in the file LICENSE.LGPL3 included in the
8  * packaging of this file. Please review the following information to
9  * ensure the GNU Lesser General Public License version 3 requirements
10  * will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
11  */
12 module qt.gui.rgba64;
13 extern(C++):
14 
15 import qt.config;
16 import qt.core.global;
17 import qt.core.typeinfo;
18 import qt.helpers;
19 
20 /// Binding for C++ class [QRgba64](https://doc.qt.io/qt-6/qrgba64.html).
21 @Q_PRIMITIVE_TYPE extern(C++, class) struct QRgba64 {
22 private:
23     quint64 rgba;
24 
25     // Make sure that the representation always has the order: red green blue alpha, independent
26     // of byte order. This way, vector operations that assume 4 16-bit values see the correct ones.
27     mixin("enum Shifts {"
28         ~ (versionIsSet!("BigEndian") ? q{
29     /+ #if Q_BYTE_ORDER == Q_BIG_ENDIAN +/
30             RedShift = 48,
31             GreenShift = 32,
32             BlueShift = 16,
33             AlphaShift = 0
34         }:q{
35     /+ #else +/ // little endian:
36             RedShift = 0,
37             GreenShift = 16,
38             BlueShift = 32,
39             AlphaShift = 48
40         /+ #endif +/
41         })
42         ~ "}"
43     );
44 
45     /+ explicit +/ /+ Q_ALWAYS_INLINE +/ pragma(inline, true) this(quint64 c)
46     {
47         this.rgba = c;
48     }
49 public:
50     /+ QRgba64() = default; +/
51 
52     static QRgba64 fromRgba64(quint64 c)
53     {
54         return QRgba64(c);
55     }
56     static QRgba64 fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha)
57     {
58         return fromRgba64(quint64(red)   << Shifts.RedShift
59                         | quint64(green) << Shifts.GreenShift
60                         | quint64(blue)  << Shifts.BlueShift
61                         | quint64(alpha) << Shifts.AlphaShift);
62     }
63     static QRgba64 fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha)
64     {
65         QRgba64 rgb64 = fromRgba64(red, green, blue, alpha);
66         // Expand the range so that 0x00 maps to 0x0000 and 0xff maps to 0xffff.
67         rgb64.rgba |= rgb64.rgba << 8;
68         return rgb64;
69     }
70 /+    static QRgba64 fromArgb32(uint rgb)
71     {
72         return fromRgba(cast(quint8)(rgb >> 16), cast(quint8)(rgb >> 8), cast(quint8)(rgb), cast(quint8)(rgb >> 24));
73     }
74 +/
75     bool isOpaque() const
76     {
77         return (rgba & alphaMask()) == alphaMask();
78     }
79     bool isTransparent() const
80     {
81         return (rgba & alphaMask()) == 0;
82     }
83 
84     quint16 red()   const { return cast(quint16)(rgba >> Shifts.RedShift);   }
85     quint16 green() const { return cast(quint16)(rgba >> Shifts.GreenShift); }
86     quint16 blue()  const { return cast(quint16)(rgba >> Shifts.BlueShift);  }
87     quint16 alpha() const { return cast(quint16)(rgba >> Shifts.AlphaShift); }
88     void setRed(quint16 _red)     { rgba = (rgba & ~(0xffffuL << Shifts.RedShift))   | (quint64(_red) << Shifts.RedShift); }
89     void setGreen(quint16 _green) { rgba = (rgba & ~(0xffffuL << Shifts.GreenShift)) | (quint64(_green) << Shifts.GreenShift); }
90     void setBlue(quint16 _blue)   { rgba = (rgba & ~(0xffffuL << Shifts.BlueShift))  | (quint64(_blue) << Shifts.BlueShift); }
91     void setAlpha(quint16 _alpha) { rgba = (rgba & ~(0xffffuL << Shifts.AlphaShift)) | (quint64(_alpha) << Shifts.AlphaShift); }
92 
93     quint8 red8()   const { return div_257(red()); }
94     quint8 green8() const { return div_257(green()); }
95     quint8 blue8()  const { return div_257(blue()); }
96     quint8 alpha8() const { return div_257(alpha()); }
97     uint toArgb32() const
98     {
99 /+ #if defined(__cpp_constexpr) && __cpp_constexpr-0 >= 201304 +/
100         quint64 br = rgba & 0xffff0000ffffuL;
101         quint64 ag = (rgba >> 16) & 0xffff0000ffffuL;
102         br += 0x8000000080uL;
103         ag += 0x8000000080uL;
104         br = (br - ((br >> 8) & 0xffff0000ffffuL)) >> 8;
105         ag = (ag - ((ag >> 8) & 0xffff0000ffffuL));
106 /+ #if Q_BYTE_ORDER == Q_BIG_ENDIAN +/
107         static if(versionIsSet!("BigEndian"))
108         {
109             return cast(uint)(((br << 24) & 0xff000000)
110                  | ((ag >> 24) & 0xff0000)
111                  | ((br >> 24) & 0xff00)
112                  | ((ag >> 8)  & 0xff));
113         }
114         else
115         {
116     /+ #else +/
117             return cast(uint)(((ag >> 16) & 0xff000000)
118                  | ((br << 16) & 0xff0000)
119                  | (ag         & 0xff00)
120                  | ((br >> 32) & 0xff));
121         }
122 /+ #endif
123 #else
124         return uint((alpha8() << 24) | (red8() << 16) | (green8() << 8) | blue8());
125 #endif +/
126     }
127     ushort toRgb16() const
128     {
129         return cast(ushort)((red() & 0xf800) | ((green() >> 10) << 5) | (blue() >> 11));
130     }
131 
132     QRgba64 premultiplied() const
133     {
134         if (isOpaque())
135             return this;
136         if (isTransparent())
137             return QRgba64.fromRgba64(0);
138         const(quint64) a = alpha();
139         quint64 br = (rgba & 0xffff0000ffffuL) * a;
140         quint64 ag = ((rgba >> 16) & 0xffff0000ffffuL) * a;
141         br = (br + ((br >> 16) & 0xffff0000ffffuL) + 0x800000008000uL);
142         ag = (ag + ((ag >> 16) & 0xffff0000ffffuL) + 0x800000008000uL);
143         static if(versionIsSet!("BigEndian"))
144         {
145             ag = ag & 0xffff0000ffff0000uL;
146             br = (br >> 16) & 0xffff00000000uL;
147             return fromRgba64(a | br | ag);
148         }
149         else
150         {
151             br = (br >> 16) & 0xffff0000ffffuL;
152             ag = ag & 0xffff0000uL;
153             return fromRgba64((a << 48) | br | ag);
154         }
155     }
156 
157 /+    QRgba64 unpremultiplied() const
158     {
159         static if(configValue!"Q_PROCESSOR_WORDSIZE" < 8)
160         {
161             return unpremultiplied_32bit();
162         }
163         else
164         {
165             return unpremultiplied_64bit();
166         }
167     }
168 +/
169     /+auto opCast(T : quint64)() const
170     {
171         return rgba;
172     }+/
173 
174     /+ref QRgba64 operator =(quint64 _rgba)/+ noexcept+/
175     {
176         rgba = _rgba;
177         return this;
178     }+/
179 
180 private:
181     /+ Q_ALWAYS_INLINE +/ pragma(inline, true) static quint64 alphaMask() { return 0xffffuL << Shifts.AlphaShift; }
182 
183     /+ Q_ALWAYS_INLINE +/ pragma(inline, true) static quint8 div_257_floor(uint x) { return cast(quint8)((x - (x >> 8)) >> 8); }
184     /+ Q_ALWAYS_INLINE +/ pragma(inline, true) static quint8 div_257(quint16 x) { return div_257_floor(x + 128U); }
185     /+ Q_ALWAYS_INLINE +/ pragma(inline, true) QRgba64 unpremultiplied_32bit() const
186     {
187         if (isOpaque() || isTransparent())
188             return this;
189         const(quint32) a = alpha();
190         const(quint16) r = cast(quint16)((red()   * 0xffff + a/2) / a);
191         const(quint16) g = cast(quint16)((green() * 0xffff + a/2) / a);
192         const(quint16) b = cast(quint16)((blue()  * 0xffff + a/2) / a);
193         return fromRgba64(r, g, b, cast(quint16)(a));
194     }
195     /+ Q_ALWAYS_INLINE +/ pragma(inline, true) QRgba64 unpremultiplied_64bit() const
196     {
197         if (isOpaque() || isTransparent())
198             return this;
199         const(quint64) a = alpha();
200         const(quint64) fa = (0xffff00008000uL + a/2) / a;
201         const(quint16) r = cast(quint16)((red()   * fa + 0x80000000) >> 32);
202         const(quint16) g = cast(quint16)((green() * fa + 0x80000000) >> 32);
203         const(quint16) b = cast(quint16)((blue()  * fa + 0x80000000) >> 32);
204         return fromRgba64(r, g, b, cast(quint16)(a));
205     }
206     mixin(CREATE_CONVENIENCE_WRAPPERS);
207 }
208 
209 /+ Q_DECLARE_TYPEINFO(QRgba64, Q_PRIMITIVE_TYPE); +/
210 
211 pragma(inline, true) QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
212 {
213     return QRgba64.fromRgba64(r, g, b, a);
214 }
215 
216 pragma(inline, true) QRgba64 qRgba64(quint64 c)
217 {
218     return QRgba64.fromRgba64(c);
219 }
220 
221 /+pragma(inline, true) QRgba64 qPremultiply(QRgba64 c)
222 {
223     return c.premultiplied();
224 }
225 
226 pragma(inline, true) QRgba64 qUnpremultiply(QRgba64 c)
227 {
228     return c.unpremultiplied();
229 }
230 
231 pragma(inline, true) uint qRed(QRgba64 rgb)
232 { return rgb.red8(); }
233 
234 pragma(inline, true) uint qGreen(QRgba64 rgb)
235 { return rgb.green8(); }
236 
237 pragma(inline, true) uint qBlue(QRgba64 rgb)
238 { return rgb.blue8(); }
239 
240 pragma(inline, true) uint qAlpha(QRgba64 rgb)
241 { return rgb.alpha8(); }
242 +/
243