2
2
import os
3
3
from math import modf
4
4
from enum import IntEnum , IntFlag
5
- from typing import Tuple , Union , Sequence , AnyStr
5
+ from typing import Tuple , Union , Sequence , AnyStr , Optional
6
6
from ctypes import (
7
7
c_bool ,
8
8
c_char_p ,
810
810
811
811
Number = Union [int , float ]
812
812
Seq = Sequence [Number ]
813
-
813
+ VectorN = Union [ Seq , 'Vector4' , 'Vector3' , 'Vector2' ]
814
814
815
815
def _float (value ) -> float :
816
816
return float (value ) if isinstance (value , int ) else value
@@ -863,6 +863,81 @@ def _color(seq: Sequence[Number]) -> 'Color':
863
863
return Color (_float (r ), _float (r ), _float (b ), _float (q ))
864
864
865
865
866
+ def _attr_swizzle (attr : str , size : int , write : bool = False ) -> Tuple [bool , str ]:
867
+ if len (attr ) not in (1 , 2 , 3 , 4 ):
868
+ return False , "Wrong number of components to swizzle (must be 1, 2, 3 or 4; not {})." .format (len (attr ))
869
+ if size not in (2 , 3 , 4 ):
870
+ return False , "Wrong vector size (must be 2, 3 or 4; not {})." .format (size )
871
+
872
+ groups = ['xyzw' , 'uv' , 'rgba' ]
873
+ if size == 3 :
874
+ groups = ['xyz' , 'uv' , 'rgb' ]
875
+ elif size == 2 :
876
+ groups = ['xy' , 'uv' , '' ]
877
+
878
+ if attr [0 ] in groups [0 ]:
879
+ group = 0
880
+ elif attr [0 ] in groups [1 ]:
881
+ group = 1
882
+ elif attr [0 ] in groups [2 ]:
883
+ group = 2
884
+ else :
885
+ return False , "Invalid component '{}' in swizzled Vector{} attribute." .format (attr [0 ], size )
886
+
887
+ already_set = []
888
+ result = ''
889
+ for i , c in enumerate (attr ):
890
+ if c not in groups [group ]:
891
+ return False , "Invalid component '{}' in swizzled attribute." .format (c )
892
+ if write and c in already_set :
893
+ return False , "Component '{}' in swizzled attribute is set more than once." .format (c )
894
+ if write :
895
+ already_set .append (c )
896
+ result += groups [0 ][groups [group ].index (c )]
897
+ return True , result
898
+
899
+
900
+ def _values (size , * args ) -> Tuple [bool , tuple ]:
901
+ if size not in (2 , 3 , 4 ):
902
+ return False , ("Wrong vector size (must be 2, 3 or 4; not {})." .format (size ),)
903
+ # if len(values) > size:
904
+ # return False, ("Too many values ({} instead of {}).".format(size + abs(n_args), size),)
905
+
906
+ n_args = 0
907
+ result = []
908
+ for arg in args :
909
+ if isinstance (arg , (int , float )):
910
+ n_args += 1
911
+ result .append (arg )
912
+ elif isinstance (arg , Vector2 ):
913
+ n_args += 2
914
+ result .append (arg .x )
915
+ result .append (arg .y )
916
+ elif isinstance (arg , Vector3 ):
917
+ n_args += 3
918
+ result .append (arg .x )
919
+ result .append (arg .y )
920
+ result .append (arg .z )
921
+ elif isinstance (arg , Vector4 ):
922
+ n_args += 4
923
+ result .append (arg .x )
924
+ result .append (arg .y )
925
+ result .append (arg .z )
926
+ result .append (arg .w )
927
+ elif arg is None :
928
+ break
929
+ else :
930
+ try :
931
+ for v in arg :
932
+ result .append (v )
933
+ n_args += 1
934
+ except (TypeError , ValueError ):
935
+ return False , ("{} is not iterable" .format (arg .__class__ .__name__ ),)
936
+ if n_args != size :
937
+ return False , ("Too many or too few values ({} instead of {})." .format (n_args , size ),)
938
+
939
+ return True , tuple (result )
940
+
866
941
867
942
_NOARGS = []
868
943
@@ -1047,7 +1122,7 @@ def _color(seq: Sequence[Number]) -> 'Color':
1047
1122
# STRUCTURES DEFINITIONS
1048
1123
# -------------------------------------------------------------------
1049
1124
1050
- class Vector2 (Structure ):
1125
+ class _Vector2 (Structure ):
1051
1126
"""
1052
1127
Wrapper for raylib Vector2 struct:
1053
1128
@@ -1061,6 +1136,9 @@ class Vector2(Structure):
1061
1136
('y' , c_float )
1062
1137
]
1063
1138
1139
+
1140
+ class Vector2 (_Vector2 ):
1141
+
1064
1142
@classmethod
1065
1143
def zero (cls ) -> 'Vector2' :
1066
1144
return Vector2 (0. , 0. )
@@ -1069,17 +1147,54 @@ def zero(cls) -> 'Vector2':
1069
1147
def one (cls ) -> 'Vector2' :
1070
1148
return Vector2 (1. , 1. )
1071
1149
1150
+ def __init__ (self , * args ) -> None :
1151
+ is_ok , result = _values (2 , * args )
1152
+ if not is_ok :
1153
+ raise ValueError (result [0 ])
1154
+ super (Vector2 , self ).__init__ (* result )
1155
+
1072
1156
def __str__ (self ) -> str :
1073
1157
return "({}, {})" .format (self .x , self .y )
1074
1158
1075
1159
def __repr__ (self ) -> str :
1076
1160
return "{}({}, {})" .format (self .__class__ .__qualname__ , self .x , self .y )
1077
1161
1162
+ def __getattr__ (self , name : str ) -> Union [float , 'Vector2' , 'Vector3' , 'Vector4' ]:
1163
+ is_valid , result = _attr_swizzle (name , 2 )
1164
+ if is_valid :
1165
+ comps = {'x' : self .x , 'y' : self .y , 'z' : 0.0 , 'w' : 0.0 }
1166
+ n = len (result )
1167
+ v = [comps [comp ] for comp in result ]
1168
+ if n == 2 :
1169
+ return Vector2 (* v )
1170
+ if n == 3 :
1171
+ return Vector3 (* v )
1172
+ if n == 4 :
1173
+ return Vector4 (* v )
1174
+
1175
+ raise AttributeError (result )
1176
+
1177
+ def __setattr__ (self , name : str , value : Union [float , 'Vector2' , 'Vector3' , 'Vector4' ]) -> None :
1178
+ is_valid , result = _attr_swizzle (name , 2 , True ) # True for setattr, so components can't be set more than once.
1179
+ if is_valid :
1180
+ if len (name ) == 1 :
1181
+ v = float (value )
1182
+ super (Vector2 , self ).__setattr__ (result , v )
1183
+ else :
1184
+ v = _vec2 (value )
1185
+ for c in result :
1186
+ super (Vector2 , self ).__setattr__ (c , getattr (v , c ))
1187
+ else :
1188
+ raise AttributeError (result )
1189
+
1078
1190
def __getitem__ (self , key : str ) -> Union [float , 'Vector2' , 'Vector3' , 'Vector4' ]:
1079
- assert isinstance (key , str ), "key must be a str of 1 to 4 characters ('x' or 'y')."
1080
- assert 0 < len (key ) < 5 , "key must have between 1 and 4 characters ('x' or 'y')."
1081
- comps = [self .x , self .y , 0. , 0. ]
1082
- values = []
1191
+ assert isinstance (key , str , int ), "key must be a str or int."
1192
+ comps = [self .x , self .y , 0.0 , 0.0 ]
1193
+ if isinstance (key , int ):
1194
+ assert 0 <= key < 2 , "key must be an int in range [0..1]"
1195
+ return comps [key ]
1196
+ else :
1197
+ assert 0 < len (key ) < 5 , "key must have between 1 and 4 characters ('x', 'y', 'z' or 'w')."
1083
1198
for i , axis in enumerate (key ):
1084
1199
values .append ({
1085
1200
'x' : self .x ,
@@ -1204,7 +1319,7 @@ def __imul__(self, other: Union['Vector2', Seq]) -> 'Vector2':
1204
1319
Vector2Ptr = POINTER (Vector2 )
1205
1320
1206
1321
1207
- class Vector3 (Structure ):
1322
+ class _Vector3 (Structure ):
1208
1323
"""
1209
1324
Wrapper for raylib Vector3 struct:
1210
1325
@@ -1220,6 +1335,9 @@ class Vector3(Structure):
1220
1335
('z' , c_float ),
1221
1336
]
1222
1337
1338
+
1339
+ class Vector3 (_Vector3 ):
1340
+
1223
1341
@classmethod
1224
1342
def zero (cls ) -> 'Vector3' :
1225
1343
return Vector3 (0. , 0. , 0. )
@@ -1228,16 +1346,54 @@ def zero(cls) -> 'Vector3':
1228
1346
def one (cls ) -> 'Vector3' :
1229
1347
return Vector3 (1. , 1. , 1. )
1230
1348
1349
+ def __init__ (self , * args ) -> None :
1350
+ is_ok , result = _values (3 , * args )
1351
+ if not is_ok :
1352
+ raise ValueError (result [0 ])
1353
+ super (Vector3 , self ).__init__ (* result )
1354
+
1231
1355
def __str__ (self ) -> str :
1232
1356
return "({}, {}, {})" .format (self .x , self .y , self .z )
1233
1357
1234
1358
def __repr__ (self ) -> str :
1235
1359
return "{}({}, {}, {})" .format (self .__class__ .__qualname__ , self .x , self .y , self .z )
1236
1360
1361
+ def __getattr__ (self , name : str ) -> Union [float , 'Vector2' , 'Vector3' , 'Vector4' ]:
1362
+ is_valid , result = _attr_swizzle (name , 3 )
1363
+ if is_valid :
1364
+ comps = {'x' : self .x , 'y' : self .y , 'z' : self .z , 'w' : 0.0 }
1365
+ n = len (result )
1366
+ v = [comps [comp ] for comp in result ]
1367
+ if n == 2 :
1368
+ return Vector2 (* v )
1369
+ if n == 3 :
1370
+ return Vector3 (* v )
1371
+ if n == 4 :
1372
+ return Vector4 (* v )
1373
+
1374
+ raise AttributeError (result )
1375
+
1376
+ def __setattr__ (self , name : str , value : Union [float , 'Vector2' , 'Vector3' , 'Vector4' ]) -> None :
1377
+ is_valid , result = _attr_swizzle (name , 3 , True ) # True for setattr, so components can't be set more than once.
1378
+ if is_valid :
1379
+ if len (name ) == 1 :
1380
+ v = float (value )
1381
+ super (Vector3 , self ).__setattr__ (result , v )
1382
+ else :
1383
+ v = _vec3 (value )
1384
+ for c in result :
1385
+ super (Vector3 , self ).__setattr__ (c , getattr (v , c ))
1386
+ else :
1387
+ raise AttributeError (result )
1388
+
1237
1389
def __getitem__ (self , key : str ) -> Union [float , 'Vector2' , 'Vector3' , 'Vector4' ]:
1238
- assert isinstance (key , str ), "key must be a str of 1 to 4 characters ('x', 'y', or 'z')."
1239
- assert 0 < len (key ) < 5 , "key must have between 1 and 4 characters ('x', 'y', or 'z')."
1240
- comps = [self .x , self .y , self .z , 0. ]
1390
+ assert isinstance (key , str , int ), "key must be a str or int."
1391
+ comps = [self .x , self .y , self .z , 0.0 ]
1392
+ if isinstance (key , int ):
1393
+ assert 0 <= key < 3 , "key must be an int in range [0..2]"
1394
+ return comps [key ]
1395
+ else :
1396
+ assert 0 < len (key ) < 5 , "key must have between 1 and 3 characters ('x', 'y' or 'z')."
1241
1397
values = []
1242
1398
for i , axis in enumerate (key ):
1243
1399
values .append ({
@@ -1377,7 +1533,7 @@ def __imul__(self, other: Union['Vector3', Seq]) -> 'Vector3':
1377
1533
Vector3Ptr = POINTER (Vector3 )
1378
1534
1379
1535
1380
- class Vector4 (Structure ):
1536
+ class _Vector4 (Structure ):
1381
1537
"""
1382
1538
Wrapper for raylib Vector4 struct:
1383
1539
@@ -1395,24 +1551,68 @@ class Vector4(Structure):
1395
1551
('w' , c_float ),
1396
1552
]
1397
1553
1554
+ class Vector4 (_Vector4 ):
1555
+
1398
1556
@classmethod
1399
1557
def zero (cls ) -> 'Vector4' :
1400
- return Vector2 (0. , 0. , 0. , 1. )
1558
+ return Vector4 (0. , 0. , 0. , 1. )
1401
1559
1402
1560
@classmethod
1403
1561
def one (cls ) -> 'Vector4' :
1404
1562
return Vector2 (1. , 1. , 1. , 1. )
1405
1563
1564
+ def __init__ (self , * args ) -> None :
1565
+ is_ok , result = _values (4 , * args )
1566
+ if not is_ok :
1567
+ raise ValueError (result [0 ])
1568
+ super (Vector4 , self ).__init__ (* result )
1569
+
1406
1570
def __str__ (self ) -> str :
1407
1571
return "({}, {}, {}, {})" .format (self .x , self .y , self .z , self .w )
1408
1572
1409
1573
def __repr__ (self ) -> str :
1410
1574
return "{}({}, {}, {}, {})" .format (self .__class__ .__qualname__ , self .x , self .y , self .z , self .w )
1411
1575
1576
+ def __getattr__ (self , name : str ) -> Union [float , 'Vector2' , 'Vector3' , 'Vector4' ]:
1577
+ is_valid , result = _attr_swizzle (name , 4 )
1578
+ if is_valid :
1579
+ comps = {'x' : self .x , 'y' : self .y , 'z' : self .z , 'w' : self .w }
1580
+ n = len (result )
1581
+ v = [comps [comp ] for comp in result ]
1582
+ if n == 2 :
1583
+ return Vector2 (* v )
1584
+ if n == 3 :
1585
+ return Vector3 (* v )
1586
+ if n == 4 :
1587
+ return Vector4 (* v )
1588
+
1589
+ raise AttributeError (result )
1590
+
1591
+ def __setattr__ (self , name : str , value : Union [float , 'Vector2' , 'Vector3' , 'Vector4' ]) -> None :
1592
+ is_valid , result = _attr_swizzle (name , 4 , True ) # True for setattr, so components can't be set more than once.
1593
+ if is_valid :
1594
+ if len (name ) == 1 :
1595
+ v = float (value )
1596
+ super (Vector4 , self ).__setattr__ (result , v )
1597
+ else :
1598
+ is_valid , v = _values (len (name ), * value )
1599
+ print ('::' , value )
1600
+ if is_valid :
1601
+ for i , c in enumerate (result ):
1602
+ super (Vector4 , self ).__setattr__ (c , v [i ])
1603
+ else :
1604
+ raise ValueError (v [0 ]) # thisline
1605
+ else :
1606
+ raise AttributeError (result )
1607
+
1412
1608
def __getitem__ (self , key : str ) -> Union [float , 'Vector2' , 'Vector3' , 'Vector4' ]:
1413
- assert isinstance (key , str ), "key must be a str of 1 to 4 characters ('x', 'y', 'z' or 'w')."
1414
- assert 0 < len (key ) < 5 , "key must have between 1 and 4 characters ('x', 'y', 'z' or 'w')."
1609
+ assert isinstance (key , str , int ), "key must be a str or int."
1415
1610
comps = [self .x , self .y , self .z , self .w ]
1611
+ if isinstance (key , int ):
1612
+ assert 0 <= key < 4 , "key must be an int in range [0..3]"
1613
+ return comps [key ]
1614
+ else :
1615
+ assert 0 < len (key ) < 5 , "key must have between 1 and 4 characters ('x', 'y', 'z' or 'w')."
1416
1616
values = []
1417
1617
for i , axis in enumerate (key ):
1418
1618
values .append ({
@@ -4758,3 +4958,8 @@ def set_audio_stream_volume(stream: AudioStream, volume: float) -> None:
4758
4958
def set_audio_stream_pitch (stream : AudioStream , pitch : float ) -> None :
4759
4959
"""Set pitch for audio stream (1.0 is base level)"""
4760
4960
return _rl .SetAudioStreamPitch (stream , _float (pitch ))
4961
+
4962
+ a = Vector4 (Vector2 (10 , 0 ), 100 , 20 )
4963
+ b = Vector4 .zero ()
4964
+ b .rgba = 0.0 , a .rg , 1.0
4965
+ a .xyzw = (10 , (20 , 40 )), 1.0
0 commit comments