Skip to content

Commit 50a9c0c

Browse files
committed
Vectors now support vector swizzling.
1 parent 56027ba commit 50a9c0c

File tree

1 file changed

+113
-172
lines changed

1 file changed

+113
-172
lines changed

raylibpy/__init__.py

Lines changed: 113 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import os
33
from math import modf
44
from enum import IntEnum, IntFlag
5-
from typing import Tuple, Union, Sequence, AnyStr, Optional
5+
from typing import Tuple, List, Union, Sequence, AnyStr, Optional, Iterator, Type
66
from ctypes import (
77
c_bool,
88
c_char_p,
@@ -896,47 +896,14 @@ def _attr_swizzle(attr: str, size: int, write: bool=False) -> Tuple[bool, str]:
896896
result += groups[0][groups[group].index(c)]
897897
return True, result
898898

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
899+
def _flatten(filter_types: List[Type], *values, map_to: Optional[Type]=None) -> list:
907900
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
901+
for v in values:
902+
if isinstance(v, filter_types):
903+
result.append(map_to(v) if map_to is not None else v)
929904
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)
905+
result.extend(_flatten(filter_types, *v, map_to=map_to))
906+
return result
940907

941908

942909
_NOARGS = []
@@ -1148,9 +1115,9 @@ def one(cls) -> 'Vector2':
11481115
return Vector2(1., 1.)
11491116

11501117
def __init__(self, *args) -> None:
1151-
is_ok, result = _values(2, *args)
1152-
if not is_ok:
1153-
raise ValueError(result[0])
1118+
result = _flatten((int, float), *args, map_to=float)
1119+
if len(result) != 2:
1120+
raise ValueError("Too many or too few initializers ({} instead of 2).".format(len(result)))
11541121
super(Vector2, self).__init__(*result)
11551122

11561123
def __str__(self) -> str:
@@ -1181,45 +1148,42 @@ def __setattr__(self, name: str, value: Union[float, 'Vector2', 'Vector3', 'Vect
11811148
v = float(value)
11821149
super(Vector2, self).__setattr__(result, v)
11831150
else:
1184-
v = _vec2(value)
1185-
for c in result:
1186-
super(Vector2, self).__setattr__(c, getattr(v, c))
1151+
values = _flatten((int, float), *value, map_to=float)
1152+
if len(name) != len(values):
1153+
raise ValueError("Too many or too few values ({} instead of {}".format(
1154+
len(values), len(name)
1155+
))
1156+
for i, c in enumerate(result):
1157+
super(Vector2, self).__setattr__(c, float(values[i]))
11871158
else:
11881159
raise AttributeError(result)
11891160

1190-
def __getitem__(self, key: str) -> Union[float, 'Vector2', 'Vector3', 'Vector4']:
1191-
assert isinstance(key, str, int), "key must be a str or int."
1192-
comps = [self.x, self.y, 0.0, 0.0]
1161+
def __len__(self) -> int:
1162+
return 2
1163+
1164+
def __iter__(self) -> Iterator[float]:
1165+
return (self.x, self.y).__iter__()
1166+
1167+
def __getitem__(self, key: Union[str, int, slice]) -> Union[float, Seq]:
1168+
assert isinstance(key, (str, int, slice)), "KeyTypeError: {} not supported as subscription key.".format(key.__class__.__name__)
1169+
1170+
if isinstance(key, (int, slice)):
1171+
return [self.x, self.y][key]
1172+
elif isinstance(key, str):
1173+
return {'x': self.x, 'y': self.y}[key]
1174+
1175+
def __setitem__(self, key: Union[str, int], value: Number) -> None:
1176+
assert isinstance(key, (str, int)), "KeyTypeError: {} not supported as subscription key.".format(key.__class__.__name__)
1177+
11931178
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')."
1198-
for i, axis in enumerate(key):
1199-
values.append({
1200-
'x': self.x,
1201-
'y': self.y,
1202-
'X': -self.x if self.x > 0 else +self.x,
1203-
'Y': -self.y if self.y > 0 else +self.y,
1204-
'0': 0.,
1205-
'1': 1.,
1206-
'/': comps[i] / 2.,
1207-
'*': comps[i] * 2.,
1208-
'^': comps[i] ** 2.,
1209-
'.': 1. / comps[i],
1210-
'+': 1. if comps[i] > 0 else (0. if comps[i] == 0. else -1.),
1211-
'?': 1. if comps[i] != 0. else 0.,
1212-
'>': max(self.x, self.y),
1213-
'<': min(self.x, self.y),
1214-
'#': modf(comps[i])[0],
1215-
'%': modf(comps[i])[1],
1216-
}[axis])
1217-
return {
1218-
1: values[0],
1219-
2: Vector2(*values),
1220-
3: Vector3(*values),
1221-
4: Vector4(*values),
1222-
}[len(values)]
1179+
a = [self.x, self.y]
1180+
a[key] = value
1181+
self.x, self.y = a
1182+
elif isinstance(key, str):
1183+
a = {'x': self.x, 'y': self.y}
1184+
assert key in a, "KeyError: invalid key '{}'.".format(key)
1185+
a[key] = value
1186+
self.x, self.y = tuple(a.values())
12231187

12241188
def __pos__(self) -> 'Vector2':
12251189
return Vector2(+self.x, +self.y)
@@ -1347,9 +1311,9 @@ def one(cls) -> 'Vector3':
13471311
return Vector3(1., 1., 1.)
13481312

13491313
def __init__(self, *args) -> None:
1350-
is_ok, result = _values(3, *args)
1351-
if not is_ok:
1352-
raise ValueError(result[0])
1314+
result = _flatten((int, float), *args, map_to=float)
1315+
if len(result) != 3:
1316+
raise ValueError("Too many or too few initializers ({} instead of 3).".format(len(result)))
13531317
super(Vector3, self).__init__(*result)
13541318

13551319
def __str__(self) -> str:
@@ -1380,48 +1344,42 @@ def __setattr__(self, name: str, value: Union[float, 'Vector2', 'Vector3', 'Vect
13801344
v = float(value)
13811345
super(Vector3, self).__setattr__(result, v)
13821346
else:
1383-
v = _vec3(value)
1384-
for c in result:
1385-
super(Vector3, self).__setattr__(c, getattr(v, c))
1347+
values = _flatten((int, float), *value, map_to=float)
1348+
if len(name) != len(values):
1349+
raise ValueError("Too many or too few values ({} instead of {}".format(
1350+
len(values), len(name)
1351+
))
1352+
for i, c in enumerate(result):
1353+
super(Vector3, self).__setattr__(c, float(values[i]))
13861354
else:
13871355
raise AttributeError(result)
13881356

1389-
def __getitem__(self, key: str) -> Union[float, 'Vector2', 'Vector3', 'Vector4']:
1390-
assert isinstance(key, str, int), "key must be a str or int."
1391-
comps = [self.x, self.y, self.z, 0.0]
1357+
def __len__(self) -> int:
1358+
return 3
1359+
1360+
def __iter__(self) -> Iterator[float]:
1361+
return (self.x, self.y, self.w).__iter__()
1362+
1363+
def __getitem__(self, key: Union[str, int, slice]) -> Union[float, Seq]:
1364+
assert isinstance(key, (str, int, slice)), "KeyTypeError: {} not supported as subscription key.".format(key.__class__.__name__)
1365+
1366+
if isinstance(key, (int, slice)):
1367+
return [self.x, self.y, self.z][key]
1368+
elif isinstance(key, str):
1369+
return {'x': self.x, 'y': self.y, 'z': self.z}[key]
1370+
1371+
def __setitem__(self, key: Union[str, int], value: Number) -> None:
1372+
assert isinstance(key, (str, int)), "KeyTypeError: {} not supported as subscription key.".format(key.__class__.__name__)
1373+
13921374
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')."
1397-
values = []
1398-
for i, axis in enumerate(key):
1399-
values.append({
1400-
'x': self.x,
1401-
'y': self.y,
1402-
'z': self.z,
1403-
'X': -self.x if self.x > 0. else +self.x,
1404-
'Y': -self.y if self.y > 0. else +self.y,
1405-
'Z': -self.z if self.z > 0. else +self.z,
1406-
'0': 0.,
1407-
'1': 1.,
1408-
'/': comps[i] / 2.,
1409-
'*': comps[i] * 2.,
1410-
'^': comps[i] ** 2.,
1411-
'.': 1. / comps[i],
1412-
'+': 1. if comps[i] > 0 else (0. if comps[i] == 0. else -1.),
1413-
'?': 1. if comps[i] != 0. else 0.,
1414-
'>': max(self.x, self.y, self.z),
1415-
'<': min(self.x, self.y, self.z),
1416-
'#': modf(comps[i])[0],
1417-
'%': modf(comps[i])[1],
1418-
}[axis])
1419-
return {
1420-
1: values[0],
1421-
2: Vector2(values[0], values[1]),
1422-
3: Vector3(values[0], values[1], values[2]),
1423-
4: Vector4(values[0], values[1], values[2], 1.),
1424-
}[len(values)]
1375+
a = [self.x, self.y, self.z]
1376+
a[key] = value
1377+
self.x, self.y, self.z = a
1378+
elif isinstance(key, str):
1379+
a = {'x': self.x, 'y': self.y, 'z': self.z}
1380+
assert key in a, "KeyError: invalid key '{}'.".format(key)
1381+
a[key] = value
1382+
self.x, self.y, self.z = tuple(a.values())
14251383

14261384
def __pos__(self) -> 'Vector3':
14271385
return Vector3(+self.x, +self.y, -self.z)
@@ -1559,12 +1517,12 @@ def zero(cls) -> 'Vector4':
15591517

15601518
@classmethod
15611519
def one(cls) -> 'Vector4':
1562-
return Vector2(1., 1., 1., 1.)
1520+
return Vector4(1., 1., 1., 1.)
15631521

15641522
def __init__(self, *args) -> None:
1565-
is_ok, result = _values(4, *args)
1566-
if not is_ok:
1567-
raise ValueError(result[0])
1523+
result = _flatten((int, float), *args, map_to=float)
1524+
if len(result) != 4:
1525+
raise ValueError("Too many or too few initializers ({} instead of 4).".format(len(result)))
15681526
super(Vector4, self).__init__(*result)
15691527

15701528
def __str__(self) -> str:
@@ -1595,54 +1553,42 @@ def __setattr__(self, name: str, value: Union[float, 'Vector2', 'Vector3', 'Vect
15951553
v = float(value)
15961554
super(Vector4, self).__setattr__(result, v)
15971555
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
1556+
values = _flatten((int, float), *value, map_to=float)
1557+
if len(name) != len(values):
1558+
raise ValueError("Too many or too few values ({} instead of {}".format(
1559+
len(values), len(name)
1560+
))
1561+
for i, c in enumerate(result):
1562+
super(Vector4, self).__setattr__(c, float(values[i]))
16051563
else:
16061564
raise AttributeError(result)
16071565

1608-
def __getitem__(self, key: str) -> Union[float, 'Vector2', 'Vector3', 'Vector4']:
1609-
assert isinstance(key, str, int), "key must be a str or int."
1610-
comps = [self.x, self.y, self.z, self.w]
1566+
def __len__(self) -> int:
1567+
return 4
1568+
1569+
def __iter__(self) -> Iterator[float]:
1570+
return (self.x, self.y, self.w, self.z).__iter__()
1571+
1572+
def __getitem__(self, key: Union[str, int, slice]) -> Union[float, Seq]:
1573+
assert isinstance(key, (str, int, slice)), "KeyTypeError: {} not supported as subscription key.".format(key.__class__.__name__)
1574+
1575+
if isinstance(key, (int, slice)):
1576+
return [self.x, self.y, self.z, self.w][key]
1577+
elif isinstance(key, str):
1578+
return {'x': self.x, 'y': self.y, 'z': self.z, 'w': self.w}[key]
1579+
1580+
def __setitem__(self, key: Union[str, int], value: Number) -> None:
1581+
assert isinstance(key, (str, int)), "KeyTypeError: {} not supported as subscription key.".format(key.__class__.__name__)
1582+
16111583
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')."
1616-
values = []
1617-
for i, axis in enumerate(key):
1618-
values.append({
1619-
'x': self.x,
1620-
'y': self.y,
1621-
'z': self.z,
1622-
'w': self.w,
1623-
'X': -self.x if self.x > 0 else +self.x,
1624-
'Y': -self.y if self.y > 0 else +self.y,
1625-
'Z': -self.z if self.z > 0 else +self.z,
1626-
'W': -self.w if self.w > 0 else +self.w,
1627-
'0': 0.,
1628-
'1': 1.,
1629-
'/': comps[i] / 2.,
1630-
'*': comps[i] * 2.,
1631-
'^': comps[i] ** 2.,
1632-
'.': 1. / comps[i],
1633-
'+': 1. if comps[i] > 0 else (0. if comps[i] == 0. else -1.),
1634-
'?': 1. if comps[i] != 0. else 0.,
1635-
'>': max(self.x, self.y, self.z),
1636-
'<': min(self.x, self.y, self.z),
1637-
'#': modf(comps[i])[0],
1638-
'%': modf(comps[i])[1],
1639-
}[axis])
1640-
return {
1641-
1: values[0],
1642-
2: Vector2(values[0], values[1]),
1643-
3: Vector3(values[0], values[1], values[2]),
1644-
4: Vector4(values[0], values[1], values[2], values[3]),
1645-
}[len(values)]
1584+
a = [self.x, self.y, self.z, self.w]
1585+
a[key] = value
1586+
self.x, self.y, self.z, self.w = a
1587+
elif isinstance(key, str):
1588+
a = {'x': self.x, 'y': self.y, 'z': self.z, 'w': self.w}
1589+
assert key in a, "KeyError: invalid key '{}'.".format(key)
1590+
a[key] = value
1591+
self.x, self.y, self.z, self.w = tuple(a.values())
16461592

16471593
def __pos__(self) -> 'Vector4':
16481594
return Vector4(+self.x, +self.y, -self.z, 1.)
@@ -4958,8 +4904,3 @@ def set_audio_stream_volume(stream: AudioStream, volume: float) -> None:
49584904
def set_audio_stream_pitch(stream: AudioStream, pitch: float) -> None:
49594905
"""Set pitch for audio stream (1.0 is base level)"""
49604906
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

Comments
 (0)