basilisk-engine 0.1.23__py3-none-any.whl → 0.1.24__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of basilisk-engine might be problematic. Click here for more details.

Files changed (93) hide show
  1. basilisk/__init__.py +15 -15
  2. basilisk/audio/sound.py +27 -27
  3. basilisk/bsk_assets/cube.obj +48 -48
  4. basilisk/collisions/broad/broad_aabb.py +102 -102
  5. basilisk/collisions/broad/broad_bvh.py +137 -137
  6. basilisk/collisions/collider.py +95 -95
  7. basilisk/collisions/collider_handler.py +224 -224
  8. basilisk/collisions/narrow/contact_manifold.py +95 -95
  9. basilisk/collisions/narrow/dataclasses.py +34 -34
  10. basilisk/collisions/narrow/deprecated.py +46 -46
  11. basilisk/collisions/narrow/epa.py +91 -91
  12. basilisk/collisions/narrow/gjk.py +66 -66
  13. basilisk/collisions/narrow/graham_scan.py +24 -24
  14. basilisk/collisions/narrow/helper.py +29 -29
  15. basilisk/collisions/narrow/line_intersections.py +106 -106
  16. basilisk/collisions/narrow/sutherland_hodgman.py +75 -75
  17. basilisk/config.py +3 -3
  18. basilisk/draw/draw.py +100 -100
  19. basilisk/draw/draw_handler.py +175 -175
  20. basilisk/draw/font_renderer.py +28 -28
  21. basilisk/engine.py +169 -164
  22. basilisk/generic/abstract_bvh.py +15 -15
  23. basilisk/generic/abstract_custom.py +133 -133
  24. basilisk/generic/collisions.py +72 -72
  25. basilisk/generic/input_validation.py +66 -66
  26. basilisk/generic/math.py +6 -6
  27. basilisk/generic/matrices.py +35 -35
  28. basilisk/generic/meshes.py +72 -72
  29. basilisk/generic/quat.py +142 -142
  30. basilisk/generic/quat_methods.py +7 -7
  31. basilisk/generic/raycast_result.py +26 -26
  32. basilisk/generic/vec3.py +143 -143
  33. basilisk/input_output/IO_handler.py +91 -92
  34. basilisk/input_output/clock.py +49 -49
  35. basilisk/input_output/keys.py +43 -43
  36. basilisk/input_output/mouse.py +90 -62
  37. basilisk/input_output/path.py +14 -14
  38. basilisk/mesh/cube.py +33 -33
  39. basilisk/mesh/mesh.py +230 -230
  40. basilisk/mesh/mesh_from_data.py +130 -130
  41. basilisk/mesh/model.py +271 -271
  42. basilisk/mesh/narrow_aabb.py +89 -89
  43. basilisk/mesh/narrow_bvh.py +91 -91
  44. basilisk/mesh/narrow_primative.py +23 -23
  45. basilisk/nodes/helper.py +28 -28
  46. basilisk/nodes/node.py +686 -686
  47. basilisk/nodes/node_handler.py +97 -97
  48. basilisk/particles/particle_handler.py +64 -64
  49. basilisk/particles/particle_renderer.py +92 -92
  50. basilisk/physics/impulse.py +112 -112
  51. basilisk/physics/physics_body.py +43 -43
  52. basilisk/physics/physics_engine.py +35 -35
  53. basilisk/render/batch.py +105 -105
  54. basilisk/render/camera.py +258 -267
  55. basilisk/render/chunk.py +106 -106
  56. basilisk/render/chunk_handler.py +165 -165
  57. basilisk/render/frame.py +95 -99
  58. basilisk/render/framebuffer.py +289 -132
  59. basilisk/render/image.py +87 -87
  60. basilisk/render/image_handler.py +120 -120
  61. basilisk/render/light.py +96 -96
  62. basilisk/render/light_handler.py +58 -58
  63. basilisk/render/material.py +219 -219
  64. basilisk/render/material_handler.py +131 -131
  65. basilisk/render/post_process.py +139 -139
  66. basilisk/render/shader.py +109 -109
  67. basilisk/render/shader_handler.py +83 -83
  68. basilisk/render/sky.py +120 -120
  69. basilisk/scene.py +279 -279
  70. basilisk/shaders/batch.frag +276 -276
  71. basilisk/shaders/batch.vert +115 -115
  72. basilisk/shaders/crt.frag +31 -31
  73. basilisk/shaders/draw.frag +22 -22
  74. basilisk/shaders/draw.vert +25 -25
  75. basilisk/shaders/filter.frag +22 -22
  76. basilisk/shaders/frame.frag +12 -12
  77. basilisk/shaders/frame.vert +13 -13
  78. basilisk/shaders/geometry.frag +8 -8
  79. basilisk/shaders/geometry.vert +41 -41
  80. basilisk/shaders/normal.frag +59 -59
  81. basilisk/shaders/normal.vert +96 -96
  82. basilisk/shaders/particle.frag +71 -71
  83. basilisk/shaders/particle.vert +84 -84
  84. basilisk/shaders/sky.frag +9 -9
  85. basilisk/shaders/sky.vert +13 -13
  86. {basilisk_engine-0.1.23.dist-info → basilisk_engine-0.1.24.dist-info}/METADATA +38 -45
  87. basilisk_engine-0.1.24.dist-info/RECORD +106 -0
  88. {basilisk_engine-0.1.23.dist-info → basilisk_engine-0.1.24.dist-info}/WHEEL +1 -1
  89. basilisk/input/__init__.py +0 -0
  90. basilisk/input/mouse.py +0 -62
  91. basilisk/input/path.py +0 -14
  92. basilisk_engine-0.1.23.dist-info/RECORD +0 -109
  93. {basilisk_engine-0.1.23.dist-info → basilisk_engine-0.1.24.dist-info}/top_level.txt +0 -0
basilisk/render/camera.py CHANGED
@@ -1,267 +1,258 @@
1
- import pygame as pg
2
- import glm
3
- import numpy as np
4
- from ..generic.vec3 import Vec3
5
- from ..generic.quat import Quat
6
-
7
-
8
- # Camera view constants
9
- FOV = 50 # Degrees
10
- NEAR = 0.1
11
- FAR = 350
12
-
13
- # Camera movement constants
14
- SPEED = 10
15
- SENSITIVITY = 0.15/180
16
-
17
- class Camera:
18
- engine: ...
19
- """Back reference to the parent engine"""
20
- scene: ...
21
- """Back reference to the parent scene"""
22
- aspect_ratio: float
23
- """Aspect ratio of the engine window"""
24
- position: glm.vec3
25
- """Location of the camera (maters)"""
26
-
27
- def __init__(self, position=(0, 0, 20), rotation=(1, 0, 0, 0), yaw=-90, pitch=0) -> None:
28
- """
29
- Camera object to get view and projection matricies. Movement built in
30
- """
31
-
32
- # Back references
33
- self.scene = None
34
- self.engine = None
35
- # transformations
36
- self.rotation = glm.quat(rotation)
37
- self.position = glm.vec3(position)
38
- # fov
39
- self.fov = 50
40
- # The initial aspect ratio of the screen
41
- self.aspect_ratio = 1.0
42
- # View matrix
43
- self.m_view = self.get_view_matrix()
44
- # Projection matrix
45
- self.m_proj = self.get_projection_matrix()
46
-
47
- def update(self) -> None:
48
- """
49
- Updates the camera view matrix
50
- """
51
-
52
- # self.update_camera_vectors()
53
- self.m_view = self.get_view_matrix()
54
-
55
- # def update_camera_vectors(self) -> None:
56
- # """
57
- # Computes the forward vector based on the pitch and yaw. Computes horizontal and vertical vectors with cross product.
58
- # """
59
- # yaw, pitch = glm.radians(self.yaw), glm.radians(self.pitch)
60
-
61
- # self.forward.x = glm.cos(yaw) * glm.cos(pitch)
62
- # self.forward.y = glm.sin(pitch)
63
- # self.forward.z = glm.sin(yaw) * glm.cos(pitch)
64
-
65
- # self.forward = glm.normalize(self.forward)
66
- # self.right = glm.normalize(glm.cross(self.forward, self.UP))
67
- # self.up = glm.normalize(glm.cross(self.right, self.forward))
68
-
69
- def use(self):
70
- # Updated aspect ratio of the screen
71
- self.aspect_ratio = self.engine.win_size[0] / self.engine.win_size[1]
72
- # View matrix
73
- self.m_view = self.get_view_matrix()
74
- # Projection matrix
75
- self.m_proj = self.get_projection_matrix()
76
-
77
- def get_view_matrix(self) -> glm.mat4x4:
78
- return glm.lookAt(self.position, self.position + self.forward, self.up)
79
-
80
- def get_projection_matrix(self) -> glm.mat4x4:
81
- return glm.perspective(glm.radians(self.fov), self.aspect_ratio, NEAR, FAR)
82
-
83
- def get_params(self) -> tuple:
84
- return self.engine, self.position, self.yaw, self.pitch
85
-
86
- def look_at(self, other) -> None:
87
- forward = glm.normalize(other.position - self.position)
88
- self.yaw = np.degrees(np.arctan2(forward.z, forward.x))
89
- self.pitch = np.degrees(np.arctan2(forward.y, np.sqrt(forward.x ** 2 + forward.z ** 2)))
90
-
91
- def __repr__(self):
92
- return f'<Basilisk Camera | Position: {self.position}, Direction: {self.forward}>'
93
-
94
- @property
95
- def scene(self): return self._scene
96
- @property
97
- def position(self): return self._position
98
- @property
99
- def rotation(self) -> glm.quat: return self._rotation
100
- @property
101
- def direction(self): return self.rotation * (0, 0, -1)
102
- @property
103
- def forward(self): return self.rotation * (0, 0, -1)
104
- @property
105
- def pitch(self): return glm.pitch(self.rotation)
106
- @property
107
- def yaw(self): return glm.yaw(self.rotation)
108
- @property
109
- def roll(self): return glm.roll(self.rotation)
110
- @property
111
- def UP(self):
112
- up = (self.rotation.x, self.rotation.y, self.rotation.z)
113
- up = (0, 1, 0) # TODO ensure that this works with all up vectors
114
- return glm.normalize(up) if glm.length2(up) > 1e-7 else glm.vec3(0, 1, 0)
115
- @property
116
- def right(self): return glm.normalize(glm.cross(self.forward, self.UP))
117
- @property
118
- def up(self): return glm.normalize(glm.cross(self.right, self.forward))
119
- @property
120
- def horizontal(self): return glm.normalize(glm.cross(self.UP, self.right))
121
- @property
122
- def fov(self): return self._fov
123
-
124
- @scene.setter
125
- def scene(self, value):
126
- if value == None: return
127
- self._scene = value
128
- self.engine = self._scene.engine
129
- self.use()
130
-
131
- @position.setter
132
- def position(self, value: tuple | list | glm.vec3 | np.ndarray | Vec3):
133
- if isinstance(value, glm.vec3): self._position = glm.vec3(value)
134
- elif isinstance(value, Vec3): self._position = glm.vec3(value.data)
135
- elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
136
- if len(value) != 3: raise ValueError(f'Camera: Invalid number of values for position. Expected 3, got {len(value)}')
137
- self._position = glm.vec3(value)
138
- else: raise TypeError(f'Camera: Invalid position value type {type(value)}')
139
-
140
- @rotation.setter
141
- def rotation(self, value):
142
- if isinstance(value, (glm.vec3, glm.quat)): self._rotation = glm.quat(value)
143
- elif isinstance(value, (Vec3, Quat)): self._rotation = glm.quat(value.data)
144
- elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
145
- if not (2 < len(value) < 5): raise ValueError(f'Camera: Invalid number of values for rotation. Expected 3 or 4, got {len(value)}')
146
- self._position = glm.quat(value)
147
- else:
148
- try:
149
- self._rotation = glm.quat(value)
150
- except:
151
- raise TypeError(f'Camera: Invalid rotation value type {type(value)}')
152
-
153
- @direction.setter
154
- def direction(self, value: tuple | list | glm.vec3 | np.ndarray | Vec3):
155
- if isinstance(value, glm.vec3): self.forward = glm.normalize(value)
156
- elif isinstance(value, Vec3): self.forward = glm.normalize(value.data)
157
- elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
158
- if len(value) != 3: raise ValueError(f'Camera: Invalid number of values for direction. Expected 3, got {len(value)}')
159
- self.forward = glm.normalize(value)
160
- else: raise TypeError(f'Camera: Invalid direction value type {type(value)}')
161
-
162
- @forward.setter
163
- def forward(self, value):
164
- self._rotation = glm.quatLookAt(value, self.UP)
165
-
166
- @pitch.setter
167
- def pitch(self, value):
168
- self._rotation = glm.quat((value, self.yaw, self.roll))
169
-
170
- @yaw.setter
171
- def yaw(self, value):
172
- self._rotation = glm.quat((self.pitch, value, self.roll))
173
-
174
- @roll.setter
175
- def roll(self, value):
176
- self._rotation = glm.quat((self.pitch, self.yaw, value))
177
-
178
- @UP.setter
179
- def UP(self, value):
180
- self._rotation = glm.quatLookAt(self.forward, value)
181
-
182
- @fov.setter
183
- def fov(self, value):
184
- self._fov = value
185
- if self.engine: self.use()
186
-
187
-
188
- class FreeCamera(Camera):
189
- def __init__(self, position=(0, 0, 20), rotation=(1, 0, 0, 0), yaw=-90, pitch=0):
190
- super().__init__(position, rotation, yaw, pitch)
191
-
192
- def update(self) -> None:
193
- """
194
- Updates the camera position and rotaiton based on user input
195
- """
196
-
197
- self.move()
198
- self.rotate()
199
- # self.update_camera_vectors()
200
- self.m_view = self.get_view_matrix()
201
-
202
- def rotate(self) -> None:
203
- """
204
- Rotates the camera based on the amount of mouse movement.
205
- """
206
- rel_x, rel_y = pg.mouse.get_rel()
207
-
208
- yaw_rotation = glm.angleAxis(SENSITIVITY * rel_x, -self.UP)
209
- pitch_rotation = glm.angleAxis(SENSITIVITY * rel_y, -self.right)
210
- new_rotation = yaw_rotation * pitch_rotation * self.rotation
211
-
212
- v_new = new_rotation * self.UP
213
- pitch_angle = glm.degrees(glm.acos(glm.clamp(glm.dot(v_new, self.UP), -1.0, 1.0)))
214
- self.rotation = new_rotation if pitch_angle < 89 else yaw_rotation * self.rotation
215
-
216
- def move(self) -> None:
217
- """
218
- Checks for button presses and updates vectors accordingly.
219
- """
220
- velocity = (SPEED + self.engine.keys[pg.K_CAPSLOCK] * 10) * self.engine.delta_time
221
- keys = self.engine.keys
222
- if keys[pg.K_w]:
223
- self.position += glm.normalize(glm.vec3(self.forward.x, 0, self.forward.z)) * velocity
224
- if keys[pg.K_s]:
225
- self.position -= glm.normalize(glm.vec3(self.forward.x, 0, self.forward.z)) * velocity
226
- if keys[pg.K_a]:
227
- self.position -= self.right * velocity
228
- if keys[pg.K_d]:
229
- self.position += self.right * velocity
230
- if keys[pg.K_SPACE]:
231
- self.position += self.UP * velocity
232
- if keys[pg.K_LSHIFT]:
233
- self.position -= self.UP * velocity
234
-
235
-
236
- class FollowCamera(FreeCamera):
237
- def __init__(self, parent, position=(0, 0, 20), rotation=(1, 0, 0, 0), yaw=-90, pitch=0, offset=(0, 0, 0)):
238
- super().__init__(position, rotation, yaw, pitch)
239
- self.parent = parent
240
- self.offest = glm.vec3(offset)
241
-
242
- def move(self) -> None:
243
- """
244
- Moves the camera to the parent node
245
- """
246
-
247
- self.position = self.parent.position + self.offest
248
-
249
- class OrbitCamera(FreeCamera):
250
- def __init__(self, parent, position=(0, 0, 20), rotation=(1, 0, 0, 0), yaw=-90, pitch=0, distance=5, offset=(0, 0)):
251
- self.parent = parent
252
- self.distance = distance
253
- self.offset = glm.vec2(offset)
254
- super().__init__(position, rotation, yaw, pitch)
255
-
256
- def get_view_matrix(self) -> glm.mat4x4:
257
- return glm.lookAt(self.position, self.parent.position, self.up)
258
-
259
- def move(self) -> None:
260
- """
261
- Moves the camera to the parent node
262
- """
263
- self.position = self.parent.position - glm.normalize(self.forward) * self.distance
264
-
265
- class StaticCamera(Camera):
266
- def __init__(self, position=(0, 0, 20), rotation=(1, 0, 0, 0), yaw=-90, pitch=0):
267
- super().__init__(position, rotation, yaw, pitch)
1
+ import pygame as pg
2
+ import glm
3
+ import numpy as np
4
+ from ..generic.vec3 import Vec3
5
+ from ..generic.quat import Quat
6
+
7
+
8
+ # Camera view constants
9
+ FOV = 50 # Degrees
10
+ NEAR = 0.1
11
+ FAR = 350
12
+
13
+ # Camera movement constants
14
+ SPEED = 10
15
+ SENSITIVITY = 0.15/180
16
+
17
+ class Camera:
18
+ engine: ...
19
+ """Back reference to the parent engine"""
20
+ scene: ...
21
+ """Back reference to the parent scene"""
22
+ aspect_ratio: float
23
+ """Aspect ratio of the engine window"""
24
+ position: glm.vec3
25
+ """Location of the camera (maters)"""
26
+
27
+ def __init__(self, position=(0, 0, 20), rotation=(1, 0, 0, 0)) -> None:
28
+ """
29
+ Camera object to get view and projection matricies. Movement built in
30
+ """
31
+
32
+ # Back references
33
+ self.scene = None
34
+ self.engine = None
35
+ # transformations
36
+ self.rotation = glm.quat(rotation)
37
+ self.position = glm.vec3(position)
38
+ # fov
39
+ self.fov = 50
40
+ # The initial aspect ratio of the screen
41
+ self.aspect_ratio = 1.0
42
+ # View matrix
43
+ self.m_view = self.get_view_matrix()
44
+ # Projection matrix
45
+ self.m_proj = self.get_projection_matrix()
46
+
47
+ def update(self) -> None:
48
+ """
49
+ Updates the camera view matrix
50
+ """
51
+
52
+ # self.update_camera_vectors()
53
+ self.m_view = self.get_view_matrix()
54
+
55
+ def use(self):
56
+ # Updated aspect ratio of the screen
57
+ self.aspect_ratio = self.engine.win_size[0] / self.engine.win_size[1]
58
+ # View matrix
59
+ self.m_view = self.get_view_matrix()
60
+ # Projection matrix
61
+ self.m_proj = self.get_projection_matrix()
62
+
63
+ def get_view_matrix(self) -> glm.mat4x4:
64
+ return glm.lookAt(self.position, self.position + self.forward, self.up)
65
+
66
+ def get_projection_matrix(self) -> glm.mat4x4:
67
+ return glm.perspective(glm.radians(self.fov), self.aspect_ratio, NEAR, FAR)
68
+
69
+ def get_params(self) -> tuple:
70
+ return self.engine, self.position, self.yaw, self.pitch
71
+
72
+ def look_at(self, other) -> None:
73
+ forward = glm.normalize(other.position - self.position)
74
+ self.yaw = np.degrees(np.arctan2(forward.z, forward.x))
75
+ self.pitch = np.degrees(np.arctan2(forward.y, np.sqrt(forward.x ** 2 + forward.z ** 2)))
76
+
77
+ def __repr__(self):
78
+ return f'<Basilisk Camera | Position: {self.position}, Direction: {self.forward}>'
79
+
80
+ @property
81
+ def scene(self): return self._scene
82
+ @property
83
+ def position(self): return self._position
84
+ @property
85
+ def rotation(self) -> glm.quat: return self._rotation
86
+ @property
87
+ def direction(self): return self.rotation * (0, 0, -1)
88
+ @property
89
+ def forward(self): return self.rotation * (0, 0, -1)
90
+ @property
91
+ def pitch(self): return glm.pitch(self.rotation)
92
+ @property
93
+ def yaw(self): return glm.yaw(self.rotation)
94
+ @property
95
+ def roll(self): return glm.roll(self.rotation)
96
+ @property
97
+ def UP(self):
98
+ up = (self.rotation.x, self.rotation.y, self.rotation.z)
99
+ up = (0, 1, 0) # TODO ensure that this works with all up vectors
100
+ return glm.normalize(up) if glm.length2(up) > 1e-7 else glm.vec3(0, 1, 0)
101
+ @property
102
+ def right(self): return glm.normalize(glm.cross(self.forward, self.UP))
103
+ @property
104
+ def up(self): return glm.normalize(glm.cross(self.right, self.forward))
105
+ @property
106
+ def horizontal(self): return glm.normalize(glm.cross(self.UP, self.right))
107
+ @property
108
+ def fov(self): return self._fov
109
+
110
+ @scene.setter
111
+ def scene(self, value):
112
+ if value == None: return
113
+ self._scene = value
114
+ self.engine = self._scene.engine
115
+ self.use()
116
+
117
+ @position.setter
118
+ def position(self, value: tuple | list | glm.vec3 | np.ndarray | Vec3):
119
+ if isinstance(value, glm.vec3): self._position = glm.vec3(value)
120
+ elif isinstance(value, Vec3): self._position = glm.vec3(value.data)
121
+ elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
122
+ if len(value) != 3: raise ValueError(f'Camera: Invalid number of values for position. Expected 3, got {len(value)}')
123
+ self._position = glm.vec3(value)
124
+ else: raise TypeError(f'Camera: Invalid position value type {type(value)}')
125
+
126
+ @rotation.setter
127
+ def rotation(self, value):
128
+ if isinstance(value, (glm.vec3, glm.quat)): self._rotation = glm.quat(value)
129
+ elif isinstance(value, (Vec3, Quat)): self._rotation = glm.quat(value.data)
130
+ elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
131
+ if not (2 < len(value) < 5): raise ValueError(f'Camera: Invalid number of values for rotation. Expected 3 or 4, got {len(value)}')
132
+ self._position = glm.quat(value)
133
+ else:
134
+ try:
135
+ self._rotation = glm.quat(value)
136
+ except:
137
+ raise TypeError(f'Camera: Invalid rotation value type {type(value)}')
138
+
139
+ @direction.setter
140
+ def direction(self, value: tuple | list | glm.vec3 | np.ndarray | Vec3):
141
+ if isinstance(value, glm.vec3): self.forward = glm.normalize(value)
142
+ elif isinstance(value, Vec3): self.forward = glm.normalize(value.data)
143
+ elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
144
+ if len(value) != 3: raise ValueError(f'Camera: Invalid number of values for direction. Expected 3, got {len(value)}')
145
+ self.forward = glm.normalize(value)
146
+ else: raise TypeError(f'Camera: Invalid direction value type {type(value)}')
147
+
148
+ @forward.setter
149
+ def forward(self, value):
150
+ self._rotation = glm.quatLookAt(value, self.UP)
151
+
152
+ @pitch.setter
153
+ def pitch(self, value):
154
+ self._rotation = glm.quat((value, self.yaw, self.roll))
155
+
156
+ @yaw.setter
157
+ def yaw(self, value):
158
+ self._rotation = glm.quat((self.pitch, value, self.roll))
159
+
160
+ @roll.setter
161
+ def roll(self, value):
162
+ self._rotation = glm.quat((self.pitch, self.yaw, value))
163
+
164
+ @UP.setter
165
+ def UP(self, value):
166
+ self._rotation = glm.quatLookAt(self.forward, value)
167
+
168
+ @fov.setter
169
+ def fov(self, value):
170
+ self._fov = value
171
+ if self.engine: self.use()
172
+
173
+
174
+ class FreeCamera(Camera):
175
+ def __init__(self, position=(0, 0, 20), rotation=(1, 0, 0, 0)):
176
+ super().__init__(position, rotation)
177
+
178
+ def update(self) -> None:
179
+ """
180
+ Updates the camera position and rotaiton based on user input
181
+ """
182
+
183
+ self.move()
184
+ self.rotate()
185
+ # self.update_camera_vectors()
186
+ self.m_view = self.get_view_matrix()
187
+
188
+ def rotate(self) -> None:
189
+ """
190
+ Rotates the camera based on the amount of mouse movement.
191
+ """
192
+ rel_x, rel_y = self.engine.mouse.relative
193
+
194
+ yaw_rotation = glm.angleAxis(SENSITIVITY * rel_x, -self.UP)
195
+ pitch_rotation = glm.angleAxis(SENSITIVITY * rel_y, -self.right)
196
+ new_rotation = yaw_rotation * pitch_rotation * self.rotation
197
+
198
+ v_new = new_rotation * self.UP
199
+ pitch_angle = glm.degrees(glm.acos(glm.clamp(glm.dot(v_new, self.UP), -1.0, 1.0)))
200
+ self.rotation = new_rotation if pitch_angle < 89 else yaw_rotation * self.rotation
201
+
202
+ def move(self) -> None:
203
+ """
204
+ Checks for button presses and updates vectors accordingly.
205
+ """
206
+ velocity = (SPEED + self.engine.keys[pg.K_CAPSLOCK] * 10) * self.engine.delta_time
207
+ keys = self.engine.keys
208
+ if keys[pg.K_w]:
209
+ self.position += glm.normalize(glm.vec3(self.forward.x, 0, self.forward.z)) * velocity
210
+ if keys[pg.K_s]:
211
+ self.position -= glm.normalize(glm.vec3(self.forward.x, 0, self.forward.z)) * velocity
212
+ if keys[pg.K_a]:
213
+ self.position -= self.right * velocity
214
+ if keys[pg.K_d]:
215
+ self.position += self.right * velocity
216
+ if keys[pg.K_SPACE]:
217
+ self.position += self.UP * velocity
218
+ if keys[pg.K_LSHIFT]:
219
+ self.position -= self.UP * velocity
220
+
221
+ class FixedCamera(FreeCamera):
222
+ def __init__(self, position=(0, 0, 20), rotation=(1, 0, 0, 0)):
223
+ super().__init__(position, rotation)
224
+
225
+ def move(self): pass
226
+
227
+ class FollowCamera(FreeCamera):
228
+ def __init__(self, parent, position=(0, 0, 20), rotation=(1, 0, 0, 0), offset=(0, 0, 0)):
229
+ super().__init__(position, rotation)
230
+ self.parent = parent
231
+ self.offest = glm.vec3(offset)
232
+
233
+ def move(self) -> None:
234
+ """
235
+ Moves the camera to the parent node
236
+ """
237
+
238
+ self.position = self.parent.position + self.offest
239
+
240
+ class OrbitCamera(FreeCamera):
241
+ def __init__(self, parent, position=(0, 0, 20), rotation=(1, 0, 0, 0), distance=5, offset=(0, 0)):
242
+ self.parent = parent
243
+ self.distance = distance
244
+ self.offset = glm.vec2(offset)
245
+ super().__init__(position, rotation)
246
+
247
+ def get_view_matrix(self) -> glm.mat4x4:
248
+ return glm.lookAt(self.position, self.parent.position, self.up)
249
+
250
+ def move(self) -> None:
251
+ """
252
+ Moves the camera to the parent node
253
+ """
254
+ self.position = self.parent.position - glm.normalize(self.forward) * self.distance
255
+
256
+ class StaticCamera(Camera):
257
+ def __init__(self, position=(0, 0, 20), rotation=(1, 0, 0, 0)):
258
+ super().__init__(position, rotation)