@@ -42,6 +42,38 @@ fn to_srgba(color: &Color) -> Srgba {
4242 color. to_srgba ( )
4343}
4444
45+ fn components ( color : & Color ) -> [ f32 ; 4 ] {
46+ use bevy:: color:: ColorToComponents ;
47+ match * color {
48+ Color :: Srgba ( c) => c. to_f32_array ( ) ,
49+ Color :: LinearRgba ( c) => c. to_f32_array ( ) ,
50+ Color :: Hsla ( c) => c. to_f32_array ( ) ,
51+ Color :: Hsva ( c) => c. to_f32_array ( ) ,
52+ Color :: Hwba ( c) => c. to_f32_array ( ) ,
53+ Color :: Laba ( c) => c. to_f32_array ( ) ,
54+ Color :: Lcha ( c) => c. to_f32_array ( ) ,
55+ Color :: Oklaba ( c) => c. to_f32_array ( ) ,
56+ Color :: Oklcha ( c) => c. to_f32_array ( ) ,
57+ Color :: Xyza ( c) => c. to_f32_array ( ) ,
58+ }
59+ }
60+
61+ fn components_no_alpha ( color : & Color ) -> [ f32 ; 3 ] {
62+ use bevy:: color:: ColorToComponents ;
63+ match * color {
64+ Color :: Srgba ( c) => c. to_f32_array_no_alpha ( ) ,
65+ Color :: LinearRgba ( c) => c. to_f32_array_no_alpha ( ) ,
66+ Color :: Hsla ( c) => c. to_f32_array_no_alpha ( ) ,
67+ Color :: Hsva ( c) => c. to_f32_array_no_alpha ( ) ,
68+ Color :: Hwba ( c) => c. to_f32_array_no_alpha ( ) ,
69+ Color :: Laba ( c) => c. to_f32_array_no_alpha ( ) ,
70+ Color :: Lcha ( c) => c. to_f32_array_no_alpha ( ) ,
71+ Color :: Oklaba ( c) => c. to_f32_array_no_alpha ( ) ,
72+ Color :: Oklcha ( c) => c. to_f32_array_no_alpha ( ) ,
73+ Color :: Xyza ( c) => c. to_f32_array_no_alpha ( ) ,
74+ }
75+ }
76+
4577#[ pymethods]
4678impl PyColor {
4779 // Varargs ctor for positional calls like color(255, 0, 0). ColorLike handles single-value extraction.
@@ -151,54 +183,44 @@ impl PyColor {
151183 parse_hex ( s) . map ( Self )
152184 }
153185
154- fn to_srgba ( & self ) -> ( f32 , f32 , f32 , f32 ) {
155- let s: Srgba = self . 0 . into ( ) ;
156- ( s. red , s. green , s. blue , s. alpha )
186+ fn to_srgba ( & self ) -> Self {
187+ Self ( Color :: Srgba ( self . 0 . into ( ) ) )
157188 }
158189
159- fn to_linear ( & self ) -> ( f32 , f32 , f32 , f32 ) {
160- let l: LinearRgba = self . 0 . into ( ) ;
161- ( l. red , l. green , l. blue , l. alpha )
190+ fn to_linear ( & self ) -> Self {
191+ Self ( Color :: LinearRgba ( self . 0 . into ( ) ) )
162192 }
163193
164- fn to_hsla ( & self ) -> ( f32 , f32 , f32 , f32 ) {
165- let h: Hsla = self . 0 . into ( ) ;
166- ( h. hue , h. saturation , h. lightness , h. alpha )
194+ fn to_hsla ( & self ) -> Self {
195+ Self ( Color :: Hsla ( self . 0 . into ( ) ) )
167196 }
168197
169- fn to_hsva ( & self ) -> ( f32 , f32 , f32 , f32 ) {
170- let h: Hsva = self . 0 . into ( ) ;
171- ( h. hue , h. saturation , h. value , h. alpha )
198+ fn to_hsva ( & self ) -> Self {
199+ Self ( Color :: Hsva ( self . 0 . into ( ) ) )
172200 }
173201
174- fn to_hwba ( & self ) -> ( f32 , f32 , f32 , f32 ) {
175- let h: Hwba = self . 0 . into ( ) ;
176- ( h. hue , h. whiteness , h. blackness , h. alpha )
202+ fn to_hwba ( & self ) -> Self {
203+ Self ( Color :: Hwba ( self . 0 . into ( ) ) )
177204 }
178205
179- fn to_oklab ( & self ) -> ( f32 , f32 , f32 , f32 ) {
180- let o: Oklaba = self . 0 . into ( ) ;
181- ( o. lightness , o. a , o. b , o. alpha )
206+ fn to_oklab ( & self ) -> Self {
207+ Self ( Color :: Oklaba ( self . 0 . into ( ) ) )
182208 }
183209
184- fn to_oklch ( & self ) -> ( f32 , f32 , f32 , f32 ) {
185- let o: Oklcha = self . 0 . into ( ) ;
186- ( o. lightness , o. chroma , o. hue , o. alpha )
210+ fn to_oklch ( & self ) -> Self {
211+ Self ( Color :: Oklcha ( self . 0 . into ( ) ) )
187212 }
188213
189- fn to_lab ( & self ) -> ( f32 , f32 , f32 , f32 ) {
190- let l: Laba = self . 0 . into ( ) ;
191- ( l. lightness , l. a , l. b , l. alpha )
214+ fn to_lab ( & self ) -> Self {
215+ Self ( Color :: Laba ( self . 0 . into ( ) ) )
192216 }
193217
194- fn to_lch ( & self ) -> ( f32 , f32 , f32 , f32 ) {
195- let l: Lcha = self . 0 . into ( ) ;
196- ( l. lightness , l. chroma , l. hue , l. alpha )
218+ fn to_lch ( & self ) -> Self {
219+ Self ( Color :: Lcha ( self . 0 . into ( ) ) )
197220 }
198221
199- fn to_xyz ( & self ) -> ( f32 , f32 , f32 , f32 ) {
200- let x: Xyza = self . 0 . into ( ) ;
201- ( x. x , x. y , x. z , x. alpha )
222+ fn to_xyz ( & self ) -> Self {
223+ Self ( Color :: Xyza ( self . 0 . into ( ) ) )
202224 }
203225
204226 #[ getter]
@@ -317,39 +339,39 @@ impl PyColor {
317339 }
318340
319341 fn to_vec3 ( & self ) -> crate :: math:: PyVec3 {
320- let s = to_srgba ( & self . 0 ) ;
321- crate :: math:: PyVec3 ( bevy:: math:: Vec3 :: new ( s . red , s . green , s . blue ) )
342+ let c = components_no_alpha ( & self . 0 ) ;
343+ crate :: math:: PyVec3 ( bevy:: math:: Vec3 :: from_array ( c ) )
322344 }
323345
324346 fn to_vec4 ( & self ) -> PyVec4 {
325- let s = to_srgba ( & self . 0 ) ;
326- PyVec4 ( bevy:: math:: Vec4 :: new ( s . red , s . green , s . blue , s . alpha ) )
347+ let c = components ( & self . 0 ) ;
348+ PyVec4 ( bevy:: math:: Vec4 :: from_array ( c ) )
327349 }
328350
329351 fn to_list ( & self ) -> Vec < f32 > {
330- let s = to_srgba ( & self . 0 ) ;
331- vec ! [ s. red, s. green, s. blue, s. alpha]
352+ components ( & self . 0 ) . to_vec ( )
332353 }
333354
334355 fn to_tuple < ' py > ( & self , py : Python < ' py > ) -> Bound < ' py , PyTuple > {
335- let s = to_srgba ( & self . 0 ) ;
336- PyTuple :: new ( py, [ s. red , s. green , s. blue , s. alpha ] ) . unwrap ( )
356+ PyTuple :: new ( py, components ( & self . 0 ) ) . unwrap ( )
337357 }
338358
339359 fn __repr__ ( & self ) -> String {
340- let s = to_srgba ( & self . 0 ) ;
341- format ! ( "Color({}, {}, {}, {})" , s . red , s . green , s . blue , s . alpha )
360+ let c = components ( & self . 0 ) ;
361+ format ! ( "Color({}, {}, {}, {})" , c [ 0 ] , c [ 1 ] , c [ 2 ] , c [ 3 ] )
342362 }
343363
344364 fn __str__ ( & self ) -> String {
345365 self . __repr__ ( )
346366 }
347367
348368 fn __eq__ ( & self , other : & Self ) -> bool {
369+ // Compare in sRGBA so colors in different spaces can be equal
349370 to_srgba ( & self . 0 ) == to_srgba ( & other. 0 )
350371 }
351372
352373 fn __hash__ ( & self ) -> u64 {
374+ // Hash in sRGBA so equal colors hash the same regardless of space
353375 let s = to_srgba ( & self . 0 ) ;
354376 let mut hasher = std:: collections:: hash_map:: DefaultHasher :: new ( ) ;
355377 hash_f32 ( s. red , & mut hasher) ;
@@ -364,21 +386,17 @@ impl PyColor {
364386 }
365387
366388 fn __getitem__ ( & self , idx : isize ) -> PyResult < f32 > {
367- let s = to_srgba ( & self . 0 ) ;
389+ let c = components ( & self . 0 ) ;
368390 let idx = if idx < 0 { 4 + idx } else { idx } ;
369- match idx {
370- 0 => Ok ( s. red ) ,
371- 1 => Ok ( s. green ) ,
372- 2 => Ok ( s. blue ) ,
373- 3 => Ok ( s. alpha ) ,
374- _ => Err ( PyTypeError :: new_err ( "index out of range" ) ) ,
391+ if idx < 0 || idx >= 4 {
392+ return Err ( PyTypeError :: new_err ( "index out of range" ) ) ;
375393 }
394+ Ok ( c[ idx as usize ] )
376395 }
377396
378397 fn __iter__ ( slf : PyRef < ' _ , Self > ) -> PyVecIter {
379- let s = to_srgba ( & slf. 0 ) ;
380398 PyVecIter {
381- values : vec ! [ s . red , s . green , s . blue , s . alpha ] ,
399+ values : components ( & slf . 0 ) . to_vec ( ) ,
382400 index : 0 ,
383401 }
384402 }
@@ -432,7 +450,7 @@ mod tests {
432450 #[ test]
433451 fn test_hex_roundtrip ( ) {
434452 let c = parse_hex ( "#FF00FF" ) . unwrap ( ) ;
435- let s = c . to_srgba ( ) ;
453+ let s = to_srgba ( & c ) ;
436454 assert ! ( ( s. red - 1.0 ) . abs( ) < 0.01 ) ;
437455 assert ! ( ( s. green - 0.0 ) . abs( ) < 0.01 ) ;
438456 assert ! ( ( s. blue - 1.0 ) . abs( ) < 0.01 ) ;
@@ -442,7 +460,7 @@ mod tests {
442460 #[ test]
443461 fn test_hex_with_alpha ( ) {
444462 let c = parse_hex ( "#FF000080" ) . unwrap ( ) ;
445- let s = c . to_srgba ( ) ;
463+ let s = to_srgba ( & c ) ;
446464 assert ! ( ( s. red - 1.0 ) . abs( ) < 0.01 ) ;
447465 assert ! ( ( s. alpha - 128.0 / 255.0 ) . abs( ) < 0.01 ) ;
448466 }
@@ -500,7 +518,7 @@ mod tests {
500518 assert ! ( s. green < 0.01 ) ;
501519 assert ! ( s. blue < 0.01 ) ;
502520
503- let ( h, sat, l, a) = c. to_hsla ( ) ;
521+ let [ h, sat, l, a] = components ( & c. to_hsla ( ) . 0 ) ;
504522 assert ! ( ( h - 0.0 ) . abs( ) < 0.5 ) ;
505523 assert ! ( ( sat - 1.0 ) . abs( ) < 0.01 ) ;
506524 assert ! ( ( l - 0.5 ) . abs( ) < 0.01 ) ;
@@ -510,7 +528,7 @@ mod tests {
510528 #[ test]
511529 fn test_oklch_roundtrip ( ) {
512530 let c = PyColor :: oklch ( 0.7 , 0.15 , 30.0 , 1.0 ) ;
513- let ( l, ch, h, a) = c. to_oklch ( ) ;
531+ let [ l, ch, h, a] = components ( & c. to_oklch ( ) . 0 ) ;
514532 assert ! ( ( l - 0.7 ) . abs( ) < 0.01 ) ;
515533 assert ! ( ( ch - 0.15 ) . abs( ) < 0.01 ) ;
516534 assert ! ( ( h - 30.0 ) . abs( ) < 0.5 ) ;
@@ -520,7 +538,7 @@ mod tests {
520538 #[ test]
521539 fn test_linear_roundtrip ( ) {
522540 let c = PyColor :: linear ( 0.5 , 0.25 , 0.1 , 0.8 ) ;
523- let ( r, g, b, a) = c. to_linear ( ) ;
541+ let [ r, g, b, a] = components ( & c. to_linear ( ) . 0 ) ;
524542 assert ! ( ( r - 0.5 ) . abs( ) < 0.01 ) ;
525543 assert ! ( ( g - 0.25 ) . abs( ) < 0.01 ) ;
526544 assert ! ( ( b - 0.1 ) . abs( ) < 0.01 ) ;
0 commit comments