@@ -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 ) ]
@@ -47,6 +48,68 @@ impl Color {
47
48
a : self . a + ( weight * ( other. a - self . a ) ) ,
48
49
}
49
50
}
51
+ #[ inline]
52
+ pub fn blend ( & self , other : & Color ) -> Color {
53
+ Color :: from_sys ( unsafe { ( get_api ( ) . godot_color_blend ) ( self . sys ( ) , other. sys ( ) ) } )
54
+ }
55
+
56
+ #[ inline]
57
+ pub fn contrasted ( & self ) -> Color {
58
+ Color :: from_sys ( unsafe { ( get_api ( ) . godot_color_contrasted ) ( self . sys ( ) ) } )
59
+ }
60
+ #[ inline]
61
+ pub fn darkened ( & self , amount : f32 ) -> Color {
62
+ Color :: from_sys ( unsafe { ( get_api ( ) . godot_color_darkened ) ( self . sys ( ) , amount) } )
63
+ }
64
+ #[ inline]
65
+ pub fn from_hsv ( h : f32 , s : f32 , v : f32 , a : f32 ) -> Color {
66
+ let color = Color :: rgba ( 0.0 , 0.0 , 0.0 , 0.0 ) ;
67
+ Color :: from_sys ( unsafe { ( get_api ( ) . godot_color_from_hsv ) ( color. sys ( ) , h, s, v, a) } )
68
+ }
69
+ #[ inline]
70
+ pub fn gray ( & self ) -> f32 {
71
+ // Implemented as described in godot docs
72
+ ( self . r + self . b + self . g ) / 3.0
73
+ }
74
+
75
+ #[ inline]
76
+ pub fn inverted ( & self ) -> Color {
77
+ // Implementation as described in godot docs.
78
+ Color {
79
+ r : 1.0f32 - self . r ,
80
+ g : 1.0f32 - self . g ,
81
+ b : 1.0f32 - self . b ,
82
+ a : self . a ,
83
+ }
84
+ }
85
+
86
+ pub fn to_abgr32 ( & self ) -> i32 {
87
+ unsafe { ( get_api ( ) . godot_color_to_abgr32 ) ( self . sys ( ) ) }
88
+ }
89
+
90
+ pub fn to_abgr64 ( & self ) -> i32 {
91
+ unsafe { ( get_api ( ) . godot_color_to_abgr64 ) ( self . sys ( ) ) }
92
+ }
93
+
94
+ pub fn to_argb32 ( & self ) -> i32 {
95
+ unsafe { ( get_api ( ) . godot_color_to_argb32 ) ( self . sys ( ) ) }
96
+ }
97
+
98
+ pub fn to_argb64 ( & self ) -> i32 {
99
+ unsafe { ( get_api ( ) . godot_color_to_argb64 ) ( self . sys ( ) ) }
100
+ }
101
+
102
+ pub fn to_html ( & self , with_alpha : bool ) -> GodotString {
103
+ GodotString :: from_sys ( unsafe { ( get_api ( ) . godot_color_to_html ) ( self . sys ( ) , with_alpha) } )
104
+ }
105
+
106
+ pub fn to_rgba32 ( & self ) -> i32 {
107
+ unsafe { ( get_api ( ) . godot_color_to_rgba32 ) ( self . sys ( ) ) }
108
+ }
109
+
110
+ pub fn to_rgba64 ( & self ) -> i32 {
111
+ unsafe { ( get_api ( ) . godot_color_to_rgba64 ) ( self . sys ( ) ) }
112
+ }
50
113
51
114
#[ doc( hidden) ]
52
115
#[ inline]
@@ -72,3 +135,49 @@ fn color_repr() {
72
135
use std:: mem:: size_of;
73
136
assert_eq ! ( size_of:: <Color >( ) , size_of:: <sys:: godot_color>( ) ) ;
74
137
}
138
+
139
+ godot_test ! ( test_color {
140
+ // Test to_html
141
+ assert_eq!( "ffffffff" , Color :: rgba( 1.0 , 1.0 , 1.0 , 1.0 ) . to_html( true ) . to_string( ) ) ;
142
+ assert_eq!( "ffffff" , Color :: rgba( 1.0 , 1.0 , 1.0 , 1.0 ) . to_html( false ) . to_string( ) ) ;
143
+ assert_eq!( "80ffffff" , Color :: rgba( 1.0 , 1.0 , 1.0 , 0.5 ) . to_html( true ) . to_string( ) ) ;
144
+ assert_eq!( "ffffff" , Color :: rgba( 1.0 , 1.0 , 1.0 , 0.5 ) . to_html( false ) . to_string( ) ) ;
145
+ assert_eq!( "ff8000" , Color :: rgb( 1.0 , 0.5 , 0.0 ) . to_html( false ) . to_string( ) ) ;
146
+ assert_eq!( "ff0080ff" , Color :: rgb( 0.0 , 0.5 , 1.0 ) . to_html( true ) . to_string( ) ) ;
147
+ // Test Gray
148
+ // String comparison due to non-trivial way to truncate floats
149
+ use crate :: core_types:: IsEqualApprox ;
150
+ assert!( 0.4f32 . is_equal_approx( Color :: rgb( 0.2 , 0.4 , 0.6 ) . gray( ) ) ) ;
151
+ assert!( 0.5f32 . is_equal_approx( Color :: rgb( 0.1 , 0.5 , 0.9 ) . gray( ) ) ) ;
152
+ assert!( 0.9f32 . is_equal_approx( Color :: rgb( 1.0 , 1.0 , 0.7 ) . gray( ) ) ) ;
153
+ assert!( 0.42f32 . is_equal_approx( Color :: rgb( 0.6 , 0.6 , 0.06 ) . gray( ) ) ) ;
154
+ // Test invert
155
+ let inverted = Color :: rgb( 1.0 , 1.0 , 1.0 ) . inverted( ) ;
156
+ assert!( 0f32 . is_equal_approx( inverted. r) ) ;
157
+ assert!( 0f32 . is_equal_approx( inverted. g) ) ;
158
+ assert!( 0f32 . is_equal_approx( inverted. b) ) ;
159
+
160
+ let inverted = Color :: rgb( 0.95 , 0.95 , 0.95 ) . inverted( ) ;
161
+ assert!( 0.05f32 . is_equal_approx( inverted. r) ) ;
162
+ assert!( 0.05f32 . is_equal_approx( inverted. g) ) ;
163
+ assert!( 0.05f32 . is_equal_approx( inverted. b) ) ;
164
+
165
+ let inverted = Color :: rgb( 0.05 , 0.95 , 0.55 ) . inverted( ) ;
166
+ assert!( 0.95f32 . is_equal_approx( inverted. r) ) ;
167
+ assert!( 0.05f32 . is_equal_approx( inverted. g) ) ;
168
+ assert!( 0.45f32 . is_equal_approx( inverted. b) ) ;
169
+
170
+ // This is a series of sanity checks to test that the API bounds work properly.
171
+ let color = Color :: from_hsv( 1.0 , 1.0 , 1.0 , 1.0 ) ;
172
+ color. darkened( 0.20 ) ;
173
+ color. contrasted( ) ;
174
+ color. inverted( ) ;
175
+ color. to_rgba32( ) ;
176
+ color. to_rgba64( ) ;
177
+ color. to_abgr32( ) ;
178
+ color. to_abgr64( ) ;
179
+ color. to_argb32( ) ;
180
+ color. to_argb64( ) ;
181
+ let other_color = Color :: rgba( 1.0 , 1.0 , 1.0 , 1.0 ) ;
182
+ color. blend( & other_color) ;
183
+ } ) ;
0 commit comments