@@ -2,6 +2,7 @@ use crate::private::get_api;
2
2
use crate :: sys;
3
3
use std:: mem:: transmute;
4
4
5
+ use crate :: core_types:: GodotString ;
5
6
/// RGBA color with 32 bits floating point components.
6
7
#[ repr( C ) ]
7
8
#[ derive( Copy , Clone , Debug , PartialEq ) ]
@@ -13,16 +14,44 @@ pub struct Color {
13
14
}
14
15
15
16
impl Color {
17
+ #[ deprecated]
16
18
#[ inline]
17
19
pub fn rgba ( r : f32 , g : f32 , b : f32 , a : f32 ) -> Color {
18
20
Color { r, g, b, a }
19
21
}
20
22
23
+ #[ deprecated]
21
24
#[ inline]
22
25
pub fn rgb ( r : f32 , g : f32 , b : f32 ) -> Color {
23
26
Color { r, g, b, a : 1.0 }
24
27
}
25
28
29
+ #[ inline]
30
+ pub fn from_rgba ( r : f32 , g : f32 , b : f32 , a : f32 ) -> Color {
31
+ Color { r, g, b, a }
32
+ }
33
+
34
+ #[ inline]
35
+ pub fn from_rgb ( r : f32 , g : f32 , b : f32 ) -> Color {
36
+ Color { r, g, b, a : 1.0 }
37
+ }
38
+
39
+ #[ inline]
40
+ pub fn from_hsv ( h : f32 , s : f32 , v : f32 ) -> Color {
41
+ Color :: from_hsva ( h, s, v, 1.0 )
42
+ }
43
+
44
+ #[ inline]
45
+ pub fn from_hsva ( h : f32 , s : f32 , v : f32 , a : f32 ) -> Color {
46
+ let color = Color {
47
+ r : 0.0 ,
48
+ g : 0.0 ,
49
+ b : 0.0 ,
50
+ a : 0.0 ,
51
+ } ;
52
+ Color :: from_sys ( unsafe { ( get_api ( ) . godot_color_from_hsv ) ( color. sys ( ) , h, s, v, a) } )
53
+ }
54
+
26
55
#[ inline]
27
56
pub fn h ( & self ) -> f32 {
28
57
unsafe { ( get_api ( ) . godot_color_get_h ) ( self . sys ( ) ) }
@@ -48,6 +77,132 @@ impl Color {
48
77
}
49
78
}
50
79
80
+ #[ inline]
81
+ pub fn blend ( & self , other : & Color ) -> Color {
82
+ Color :: from_sys ( unsafe { ( get_api ( ) . godot_color_blend ) ( self . sys ( ) , other. sys ( ) ) } )
83
+ }
84
+
85
+ #[ inline]
86
+ pub fn contrasted ( & self ) -> Color {
87
+ Color :: from_sys ( unsafe { ( get_api ( ) . godot_color_contrasted ) ( self . sys ( ) ) } )
88
+ }
89
+
90
+ #[ inline]
91
+ pub fn darkened ( & self , amount : f32 ) -> Color {
92
+ Color :: from_sys ( unsafe { ( get_api ( ) . godot_color_darkened ) ( self . sys ( ) , amount) } )
93
+ }
94
+
95
+ #[ inline]
96
+ pub fn gray ( & self ) -> f32 {
97
+ // Implemented as described in godot docs
98
+ ( self . r + self . b + self . g ) / 3.0
99
+ }
100
+
101
+ #[ inline]
102
+ pub fn inverted ( & self ) -> Color {
103
+ // Implementation as described in godot docs.
104
+ Color {
105
+ r : 1.0 - self . r ,
106
+ g : 1.0 - self . g ,
107
+ b : 1.0 - self . b ,
108
+ a : self . a ,
109
+ }
110
+ }
111
+
112
+ #[ inline]
113
+ pub fn to_html ( & self , with_alpha : bool ) -> GodotString {
114
+ GodotString :: from_sys ( unsafe { ( get_api ( ) . godot_color_to_html ) ( self . sys ( ) , with_alpha) } )
115
+ }
116
+
117
+ /// Returns the reverse of the RGBA32 byte representation for this color where each byte represents a component of the ABGR profile.
118
+ /// This is the byte information used when storing this color as a part of a texture.
119
+ /// # Endianness
120
+ /// On big endian architecture this is stored in ABGR byte order
121
+ /// On little endian machines this is stored in RGBA byte order
122
+ /// # Example
123
+ /// `0x00FF7FFF` would be the equivalent to `Color::from_rgba(1.0, 0.5, 1.0, 0.0)`
124
+ #[ inline]
125
+ pub fn to_abgr32 ( & self ) -> u32 {
126
+ ( ( self . a * 255.0 ) as u32 ) << 24
127
+ | ( ( self . b * 255.0 ) as u32 ) << 16
128
+ | ( ( self . g * 255.0 ) as u32 ) << 8
129
+ | ( self . r * 255.0 ) as u32
130
+ }
131
+
132
+ /// Returns the reverse of the RGBA64 byte representation for this color where each word represents represents a component of the ABGR profile.
133
+ /// This is the byte information used when storing this color as a part of a texture.
134
+ /// # Endianness
135
+ /// On big endian architecture this is stored in ABGR word order
136
+ /// On little endian machines this is stored in RGBA word order
137
+ /// # Example
138
+ /// `0x0000FFFF7FFFFFFF` would be the equivalent to `Color::from_rgba(0.0, 1.0, 0.5, 1.0)`
139
+ #[ inline]
140
+ pub fn to_abgr64 ( & self ) -> u64 {
141
+ ( ( self . a * 65535.0 ) as u64 ) << 48
142
+ | ( ( self . b * 65535.0 ) as u64 ) << 32
143
+ | ( ( self . g * 65535.0 ) as u64 ) << 16
144
+ | ( ( self . r * 65535.0 ) as u64 )
145
+ }
146
+
147
+ /// Returns the ARGB32 format representation representation for this color where each byte represents a component of the ARGB profile.
148
+ /// This is the byte information used when storing this color as a part of a texture.
149
+ /// # Endianness
150
+ /// On big endian architecture this is stored in the order ARGB byte order
151
+ /// On little endian machines this is stored in the order BGRA byte order
152
+ /// `0x0000FFFF7FFFFFFF` would be the equivalent to `Color::from_rgba(1.0, 0.5, 1.0, 0.0)`
153
+ #[ inline]
154
+ pub fn to_argb32 ( & self ) -> u32 {
155
+ ( ( self . a * 255.0 ) as u32 ) << 24
156
+ | ( ( self . r * 255.0 ) as u32 ) << 16
157
+ | ( ( self . g * 255.0 ) as u32 ) << 8
158
+ | ( self . b * 255.0 ) as u32
159
+ }
160
+
161
+ /// Returns the ARGB64 format representation for this color where each word represents a component of the ARGB profile.
162
+ /// This is the byte information used when storing this color as a part of a texture.
163
+ /// # Endianness
164
+ /// On big endian architecture this is stored in the order ARGB word order
165
+ /// On little endian machines this is stored in the order BGRA word order
166
+ /// # Example
167
+ /// `0x0000FFFF7FFFFFFF` would be the equivalent to `Color::from_rgba(1.0, 0.5, 1.0, 0.0)`
168
+ #[ inline]
169
+ pub fn to_argb64 ( & self ) -> u64 {
170
+ ( ( self . a * 65535.0 ) as u64 ) << 48
171
+ | ( ( self . r * 65535.0 ) as u64 ) << 32
172
+ | ( ( self . g * 65535.0 ) as u64 ) << 16
173
+ | ( ( self . b * 65535.0 ) as u64 )
174
+ }
175
+
176
+ /// Returns the OpenGL Texture format byte representation for this color where each byte represents a component of the RGBA profile.
177
+ /// This is the byte information used when storing this color as a part of a texture.
178
+ /// # Endianness
179
+ /// On big endian architecture this is stored in RGBA byte order
180
+ /// On little endian machines this is stored in ABGR byte order
181
+ /// # Example
182
+ /// `0x00FF7FFF` would be the equivalent to `Color::from_rgba(0.0, 1.0, 0.5, 1.0)`
183
+ #[ inline]
184
+ pub fn to_rgba32 ( & self ) -> u32 {
185
+ ( ( self . r * 255.0 ) as u32 ) << 24
186
+ | ( ( self . g * 255.0 ) as u32 ) << 16
187
+ | ( ( self . b * 255.0 ) as u32 ) << 8
188
+ | ( self . a * 255.0 ) as u32
189
+ }
190
+
191
+ /// Returns the OpenGL Texture format byte representation for this color where each byte represents a component of the RGBA profile.
192
+ /// This is the byte information used when storing this color as a part of a texture.
193
+ /// # Endianness
194
+ /// On big endian architecture this is stored in RGBA word order
195
+ /// On little endian machines this is stored in ABGR word order
196
+ /// # Example
197
+ /// `0x0000FFFF7FFFFFFF` would be the equivalent to `Color::from_rgba(0.0, 1.0, 0.5, 1.0)`
198
+ #[ inline]
199
+ pub fn to_rgba64 ( & self ) -> u64 {
200
+ ( ( self . r * 65535.0 ) as u64 ) << 48
201
+ | ( ( self . g * 65535.0 ) as u64 ) << 32
202
+ | ( ( self . b * 65535.0 ) as u64 ) << 16
203
+ | ( ( self . a * 65535.0 ) as u64 )
204
+ }
205
+
51
206
#[ doc( hidden) ]
52
207
#[ inline]
53
208
pub fn sys ( & self ) -> & sys:: godot_color {
@@ -72,3 +227,60 @@ fn color_repr() {
72
227
use std:: mem:: size_of;
73
228
assert_eq ! ( size_of:: <Color >( ) , size_of:: <sys:: godot_color>( ) ) ;
74
229
}
230
+
231
+ #[ test]
232
+ fn color_to_pixel_color_formats ( ) {
233
+ let color = Color :: from_rgba ( 1.0 , 0.5 , 1.0 , 0.0 ) ;
234
+ assert_eq ! ( 0xFF7FFF00 , color. to_rgba32( ) ) ;
235
+ assert_eq ! ( 0xFFFF7FFFFFFF0000 , color. to_rgba64( ) ) ;
236
+ assert_eq ! ( 0x00FF7FFF , color. to_abgr32( ) ) ;
237
+ assert_eq ! ( 0x0000FFFF7FFFFFFF , color. to_abgr64( ) ) ;
238
+ assert_eq ! ( 0x00FF7FFF , color. to_argb32( ) ) ;
239
+ assert_eq ! ( 0x0000FFFF7FFFFFFF , color. to_argb64( ) ) ;
240
+ }
241
+
242
+ godot_test ! ( test_color {
243
+ // Test to_html
244
+ assert_eq!( "ffffffff" , Color :: from_rgba( 1.0 , 1.0 , 1.0 , 1.0 ) . to_html( true ) . to_string( ) ) ;
245
+ assert_eq!( "ffffff" , Color :: from_rgba( 1.0 , 1.0 , 1.0 , 1.0 ) . to_html( false ) . to_string( ) ) ;
246
+ assert_eq!( "80ffffff" , Color :: from_rgba( 1.0 , 1.0 , 1.0 , 0.5 ) . to_html( true ) . to_string( ) ) ;
247
+ assert_eq!( "ffffff" , Color :: from_rgba( 1.0 , 1.0 , 1.0 , 0.5 ) . to_html( false ) . to_string( ) ) ;
248
+ assert_eq!( "ff8000" , Color :: from_rgb( 1.0 , 0.5 , 0.0 ) . to_html( false ) . to_string( ) ) ;
249
+ assert_eq!( "ff0080ff" , Color :: from_rgb( 0.0 , 0.5 , 1.0 ) . to_html( true ) . to_string( ) ) ;
250
+ // Test Gray
251
+ // String comparison due to non-trivial way to truncate floats
252
+ use crate :: core_types:: IsEqualApprox ;
253
+ assert!( 0.4f32 . is_equal_approx( Color :: from_rgb( 0.2 , 0.4 , 0.6 ) . gray( ) ) ) ;
254
+ assert!( 0.5f32 . is_equal_approx( Color :: from_rgb( 0.1 , 0.5 , 0.9 ) . gray( ) ) ) ;
255
+ assert!( 0.9f32 . is_equal_approx( Color :: from_rgb( 1.0 , 1.0 , 0.7 ) . gray( ) ) ) ;
256
+ assert!( 0.42f32 . is_equal_approx( Color :: from_rgb( 0.6 , 0.6 , 0.06 ) . gray( ) ) ) ;
257
+ // Test invert
258
+ let inverted = Color :: from_rgb( 1.0 , 1.0 , 1.0 ) . inverted( ) ;
259
+ assert!( 0f32 . is_equal_approx( inverted. r) ) ;
260
+ assert!( 0f32 . is_equal_approx( inverted. g) ) ;
261
+ assert!( 0f32 . is_equal_approx( inverted. b) ) ;
262
+
263
+ let inverted = Color :: from_rgb( 0.95 , 0.95 , 0.95 ) . inverted( ) ;
264
+ assert!( 0.05f32 . is_equal_approx( inverted. r) ) ;
265
+ assert!( 0.05f32 . is_equal_approx( inverted. g) ) ;
266
+ assert!( 0.05f32 . is_equal_approx( inverted. b) ) ;
267
+
268
+ let inverted = Color :: from_rgb( 0.05 , 0.95 , 0.55 ) . inverted( ) ;
269
+ assert!( 0.95f32 . is_equal_approx( inverted. r) ) ;
270
+ assert!( 0.05f32 . is_equal_approx( inverted. g) ) ;
271
+ assert!( 0.45f32 . is_equal_approx( inverted. b) ) ;
272
+
273
+ // This is a series of sanity checks to test that the API bounds work properly.
274
+ let hsv_color = Color :: from_hsv( 0.75 , 0.5 , 0.25 ) ;
275
+ let color = Color :: from_hsva( 0.75 , 0.5 , 0.25 , 1.0 ) ;
276
+ assert_eq!( hsv_color, color) ;
277
+ let color = Color :: from_rgb( 0.75 , 0.5 , 0.25 ) ;
278
+ assert_eq!( Color :: from_rgb( 0.25 , 0.5 , 0.75 ) , color. inverted( ) ) ;
279
+ // Following results were derived from the godot engine code based on the RGB values of 0.75, 0.5, 0.25 respectively.
280
+ assert_eq!( Color :: from_rgb( 0.25 , 0.00 , 0.75 ) , color. contrasted( ) ) ;
281
+ assert_eq!( Color :: from_rgba( 0.60 , 0.40 , 0.20 , 1.0 ) , color. darkened( 0.20 ) ) ;
282
+ // Check that the blend values are correct.
283
+ let color = Color :: from_rgba( 0.0 , 1.0 , 0.5 , 1.0 ) ;
284
+ let other_color = Color :: from_rgba( 1.0 , 0.0 , 0.5 , 1.0 ) ;
285
+ assert_eq!( Color :: from_rgba( 1.0 , 0.0 , 0.5 , 1.0 ) , color. blend( & other_color) ) ;
286
+ } ) ;
0 commit comments