basilisk-engine 0.1.38__py3-none-any.whl → 0.1.39__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 (97) hide show
  1. basilisk/__init__.py +26 -26
  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 +226 -226
  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 +53 -53
  18. basilisk/draw/draw.py +100 -100
  19. basilisk/draw/draw_handler.py +178 -178
  20. basilisk/draw/font_renderer.py +28 -28
  21. basilisk/engine.py +165 -165
  22. basilisk/generic/abstract_bvh.py +15 -15
  23. basilisk/generic/abstract_custom.py +133 -133
  24. basilisk/generic/collisions.py +70 -70
  25. basilisk/generic/input_validation.py +82 -82
  26. basilisk/generic/math.py +18 -7
  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/__init__.py +0 -0
  34. basilisk/input/mouse.py +62 -0
  35. basilisk/input/path.py +14 -0
  36. basilisk/input_output/IO_handler.py +91 -91
  37. basilisk/input_output/clock.py +49 -49
  38. basilisk/input_output/keys.py +43 -43
  39. basilisk/input_output/mouse.py +90 -90
  40. basilisk/input_output/path.py +14 -14
  41. basilisk/mesh/cube.py +33 -33
  42. basilisk/mesh/mesh.py +233 -233
  43. basilisk/mesh/mesh_from_data.py +150 -150
  44. basilisk/mesh/model.py +271 -271
  45. basilisk/mesh/narrow_aabb.py +89 -89
  46. basilisk/mesh/narrow_bvh.py +91 -91
  47. basilisk/mesh/narrow_primative.py +23 -23
  48. basilisk/nodes/helper.py +28 -28
  49. basilisk/nodes/node.py +709 -704
  50. basilisk/nodes/node_handler.py +97 -97
  51. basilisk/particles/particle_handler.py +64 -64
  52. basilisk/particles/particle_renderer.py +93 -93
  53. basilisk/physics/impulse.py +112 -112
  54. basilisk/physics/physics_body.py +43 -43
  55. basilisk/physics/physics_engine.py +35 -35
  56. basilisk/render/batch.py +103 -103
  57. basilisk/render/bloom.py +107 -107
  58. basilisk/render/camera.py +260 -260
  59. basilisk/render/chunk.py +108 -108
  60. basilisk/render/chunk_handler.py +167 -167
  61. basilisk/render/frame.py +110 -110
  62. basilisk/render/framebuffer.py +202 -202
  63. basilisk/render/image.py +120 -120
  64. basilisk/render/image_handler.py +120 -120
  65. basilisk/render/light.py +96 -96
  66. basilisk/render/light_handler.py +58 -58
  67. basilisk/render/material.py +232 -232
  68. basilisk/render/material_handler.py +133 -133
  69. basilisk/render/post_process.py +146 -146
  70. basilisk/render/shader.py +134 -134
  71. basilisk/render/shader_handler.py +85 -85
  72. basilisk/render/sky.py +120 -120
  73. basilisk/scene.py +290 -290
  74. basilisk/shaders/batch.frag +289 -289
  75. basilisk/shaders/batch.vert +117 -117
  76. basilisk/shaders/bloom_downsample.frag +42 -42
  77. basilisk/shaders/bloom_frame.frag +24 -24
  78. basilisk/shaders/bloom_upsample.frag +33 -33
  79. basilisk/shaders/crt.frag +31 -31
  80. basilisk/shaders/draw.frag +25 -25
  81. basilisk/shaders/draw.vert +25 -25
  82. basilisk/shaders/filter.frag +22 -22
  83. basilisk/shaders/frame.frag +12 -12
  84. basilisk/shaders/frame.vert +13 -13
  85. basilisk/shaders/geometry.frag +10 -10
  86. basilisk/shaders/geometry.vert +41 -41
  87. basilisk/shaders/normal.frag +62 -62
  88. basilisk/shaders/normal.vert +96 -96
  89. basilisk/shaders/particle.frag +76 -76
  90. basilisk/shaders/particle.vert +86 -86
  91. basilisk/shaders/sky.frag +23 -23
  92. basilisk/shaders/sky.vert +13 -13
  93. {basilisk_engine-0.1.38.dist-info → basilisk_engine-0.1.39.dist-info}/METADATA +89 -89
  94. basilisk_engine-0.1.39.dist-info/RECORD +114 -0
  95. {basilisk_engine-0.1.38.dist-info → basilisk_engine-0.1.39.dist-info}/WHEEL +1 -1
  96. basilisk_engine-0.1.38.dist-info/RECORD +0 -111
  97. {basilisk_engine-0.1.38.dist-info → basilisk_engine-0.1.39.dist-info}/top_level.txt +0 -0
@@ -1,98 +1,98 @@
1
- import glm
2
- from .node import Node
3
- from .helper import node_is
4
- from ..render.chunk_handler import ChunkHandler
5
- from ..mesh.mesh import Mesh
6
- from ..render.material import Material
7
-
8
-
9
- class NodeHandler():
10
- scene: ...
11
- """Back reference to the scene"""
12
- nodes: list[Node]
13
- """The list of root nodes in the scene"""
14
-
15
- def __init__(self, scene):
16
- """
17
- Contains all the nodes in the scene.
18
- Handles chunking and batching of nodes
19
- """
20
-
21
- self.scene = scene
22
- self.engine = scene.engine
23
- self.nodes = []
24
- self.chunk_handler = ChunkHandler(scene)
25
-
26
- def update(self):
27
- """
28
- Updates the nodes and chunks in the scene
29
- """
30
- dt = self.scene.engine.delta_time
31
- if dt < 0.5:
32
- for node in self.nodes:
33
- # if not node.static: TODO determine better solution to this line
34
- node.update(dt)
35
- self.chunk_handler.update()
36
-
37
- def render(self):
38
- """
39
- Updates the node meshes in the scene
40
- """
41
-
42
- self.chunk_handler.render()
43
-
44
- def add(self, node: Node) -> Node:
45
- """
46
- Adds a new node to the node handler
47
- """
48
- if node in self.nodes: return
49
-
50
- for n in node.get_all(): # gets all nodes including the node to be added
51
-
52
- # Update scene Handlers
53
- self.engine.shader_handler.add(n.shader)
54
- if not n.material: n.material = self.engine.material_handler.base
55
- self.engine.material_handler.add(n.material)
56
-
57
- # Update the node attributes
58
- n.init_scene(self.scene)
59
-
60
- # Add the node to internal data
61
- self.nodes.append(n)
62
- self.chunk_handler.add(n)
63
-
64
- return node
65
-
66
- def get(self, position: glm.vec3=None, scale: glm.vec3=None, rotation: glm.quat=None, forward: glm.vec3=None, mesh: Mesh=None, material: Material=None, velocity: glm.vec3=None, rotational_velocity: glm.quat=None, physics: bool=None, mass: float=None, collisions: bool=None, static_friction: float=None, kinetic_friction: float=None, elasticity: float=None, collision_group: float=None, name: str=None, tags: list[str]=None,static: bool=None) -> Node:
67
- """
68
- Returns the first node with the given traits
69
- """
70
- for node in self.nodes:
71
- if node_is(node, position, scale, rotation, forward, mesh, material, velocity, rotational_velocity, physics, mass, collisions, static_friction, kinetic_friction, elasticity, collision_group, name, tags, static): return node
72
- return None
73
-
74
- def get_all(self, position: glm.vec3=None, scale: glm.vec3=None, rotation: glm.quat=None, forward: glm.vec3=None, mesh: Mesh=None, material: Material=None, velocity: glm.vec3=None, rotational_velocity: glm.quat=None, physics: bool=None, mass: float=None, collisions: bool=None, static_friction: float=None, kinetic_friction: float=None, elasticity: float=None, collision_group: float=None, name: str=None, tags: list[str]=None,static: bool=None) -> list[Node]:
75
- """
76
- Returns all nodes with the given traits
77
- """
78
- nodes = []
79
- for node in self.nodes:
80
- if node_is(node, position, scale, rotation, forward, mesh, material, velocity, rotational_velocity, physics, mass, collisions, static_friction, kinetic_friction, elasticity, collision_group, name, tags, static): nodes.append(node)
81
- return nodes
82
-
83
- def remove(self, node: Node) -> None:
84
- """
85
- Removes a node and all of its children from their handlers
86
- """
87
-
88
- if node == None: return
89
-
90
- # TODO add support for recursive nodes
91
- if node in self.nodes:
92
- if node.physics_body: self.scene.physics_engine.remove(node.physics_body)
93
- if node.collider: self.scene.collider_handler.remove(node.collider)
94
- self.chunk_handler.remove(node)
95
- self.nodes.remove(node)
96
- node.node_handler = None
97
-
1
+ import glm
2
+ from .node import Node
3
+ from .helper import node_is
4
+ from ..render.chunk_handler import ChunkHandler
5
+ from ..mesh.mesh import Mesh
6
+ from ..render.material import Material
7
+
8
+
9
+ class NodeHandler():
10
+ scene: ...
11
+ """Back reference to the scene"""
12
+ nodes: list[Node]
13
+ """The list of root nodes in the scene"""
14
+
15
+ def __init__(self, scene):
16
+ """
17
+ Contains all the nodes in the scene.
18
+ Handles chunking and batching of nodes
19
+ """
20
+
21
+ self.scene = scene
22
+ self.engine = scene.engine
23
+ self.nodes = []
24
+ self.chunk_handler = ChunkHandler(scene)
25
+
26
+ def update(self):
27
+ """
28
+ Updates the nodes and chunks in the scene
29
+ """
30
+ dt = self.scene.engine.delta_time
31
+ if dt < 0.5:
32
+ for node in self.nodes:
33
+ # if not node.static: TODO determine better solution to this line
34
+ node.update(dt)
35
+ self.chunk_handler.update()
36
+
37
+ def render(self):
38
+ """
39
+ Updates the node meshes in the scene
40
+ """
41
+
42
+ self.chunk_handler.render()
43
+
44
+ def add(self, node: Node) -> Node:
45
+ """
46
+ Adds a new node to the node handler
47
+ """
48
+ if node in self.nodes: return
49
+
50
+ for n in node.get_all(): # gets all nodes including the node to be added
51
+
52
+ # Update scene Handlers
53
+ self.engine.shader_handler.add(n.shader)
54
+ if not n.material: n.material = self.engine.material_handler.base
55
+ self.engine.material_handler.add(n.material)
56
+
57
+ # Update the node attributes
58
+ n.init_scene(self.scene)
59
+
60
+ # Add the node to internal data
61
+ self.nodes.append(n)
62
+ self.chunk_handler.add(n)
63
+
64
+ return node
65
+
66
+ def get(self, position: glm.vec3=None, scale: glm.vec3=None, rotation: glm.quat=None, forward: glm.vec3=None, mesh: Mesh=None, material: Material=None, velocity: glm.vec3=None, rotational_velocity: glm.quat=None, physics: bool=None, mass: float=None, collisions: bool=None, static_friction: float=None, kinetic_friction: float=None, elasticity: float=None, collision_group: float=None, name: str=None, tags: list[str]=None,static: bool=None) -> Node:
67
+ """
68
+ Returns the first node with the given traits
69
+ """
70
+ for node in self.nodes:
71
+ if node_is(node, position, scale, rotation, forward, mesh, material, velocity, rotational_velocity, physics, mass, collisions, static_friction, kinetic_friction, elasticity, collision_group, name, tags, static): return node
72
+ return None
73
+
74
+ def get_all(self, position: glm.vec3=None, scale: glm.vec3=None, rotation: glm.quat=None, forward: glm.vec3=None, mesh: Mesh=None, material: Material=None, velocity: glm.vec3=None, rotational_velocity: glm.quat=None, physics: bool=None, mass: float=None, collisions: bool=None, static_friction: float=None, kinetic_friction: float=None, elasticity: float=None, collision_group: float=None, name: str=None, tags: list[str]=None,static: bool=None) -> list[Node]:
75
+ """
76
+ Returns all nodes with the given traits
77
+ """
78
+ nodes = []
79
+ for node in self.nodes:
80
+ if node_is(node, position, scale, rotation, forward, mesh, material, velocity, rotational_velocity, physics, mass, collisions, static_friction, kinetic_friction, elasticity, collision_group, name, tags, static): nodes.append(node)
81
+ return nodes
82
+
83
+ def remove(self, node: Node) -> None:
84
+ """
85
+ Removes a node and all of its children from their handlers
86
+ """
87
+
88
+ if node == None: return
89
+
90
+ # TODO add support for recursive nodes
91
+ if node in self.nodes:
92
+ if node.physics_body: self.scene.physics_engine.remove(node.physics_body)
93
+ if node.collider: self.scene.collider_handler.remove(node.collider)
94
+ self.chunk_handler.remove(node)
95
+ self.nodes.remove(node)
96
+ node.node_handler = None
97
+
98
98
  for child in node.children: self.remove(child)
@@ -1,65 +1,65 @@
1
- from .particle_renderer import ParticleRenderer
2
- from ..mesh.mesh import Mesh
3
- from ..render.material import Material
4
- from ..generic.input_validation import validate_tuple3, validate_float
5
-
6
- class ParticleHandler:
7
- def __init__(self, scene, shader=None):
8
- """
9
- A handler for all particles in a scene
10
- """
11
-
12
- self.scene = scene
13
- self.shader = shader
14
- self.cube = Mesh(scene.engine.root + '/bsk_assets/cube.obj')
15
- self.particle_renderers = {self.cube : ParticleRenderer(scene, self.cube, self.shader)}
16
-
17
-
18
- def add(self, mesh: Mesh=None, life: float=1.0, position: tuple|float=0, material: Material=None, scale: float=1.0, velocity: tuple|float=0, acceleration: tuple|float=0) -> bool:
19
- """
20
- Add a new particle to the scene
21
- Args:
22
- mesh: Mesh
23
- The basilisk mesh of the particle
24
- life: float
25
- The duration of the particle in seconds
26
- position: tuple (x, y, z)
27
- The initial position of the particle
28
- color: tuple (r, g, b) (components out of 255)
29
- The color of the particle
30
- scale: float
31
- The overall scale factor of the particle
32
- velocity: tuple (x, y, z)
33
- The inital velocity of the particle as a vector
34
- acceleration: tuple (x, y, z)
35
- The permanent acceleration of the particle as a vector
36
- """
37
-
38
- # Get the mesh and make a new particle renderer if the mesh is new
39
- if mesh == None: mesh = self.cube
40
- elif not isinstance(mesh, Mesh): raise ValueError(f'particle_handler.add: invlaid mesh type for particle: {type(mesh)}')
41
- if mesh not in self.particle_renderers: self.particle_renderers[mesh] = ParticleRenderer(self.scene, mesh, self.shader)
42
-
43
- # Get material ID
44
- if material == None: material_index = 0
45
- elif isinstance(material, Material):
46
- self.scene.engine.material_handler.add(material)
47
- material_index = material.index
48
- else: raise ValueError(f'particle_handler.add: Invalid particle material type: {type(material)}')
49
-
50
- # Validate the 3-component vectors
51
- position = validate_tuple3('particle', 'add', position)
52
- velocity = validate_tuple3('particle', 'add', velocity)
53
- acceleration = validate_tuple3('particle', 'add', acceleration)
54
-
55
- # Validate float inputs
56
- life = validate_float('particle', 'add', life)
57
- scale = validate_float('particle', 'add', scale)
58
-
59
- # Add the particle to the renderer
60
- self.particle_renderers[mesh].add(life, position, material_index, scale, velocity, acceleration)
61
-
62
- def render(self) -> None:
63
- for renderer in self.particle_renderers.values(): renderer.render()
64
- def update(self) -> None:
1
+ from .particle_renderer import ParticleRenderer
2
+ from ..mesh.mesh import Mesh
3
+ from ..render.material import Material
4
+ from ..generic.input_validation import validate_tuple3, validate_float
5
+
6
+ class ParticleHandler:
7
+ def __init__(self, scene, shader=None):
8
+ """
9
+ A handler for all particles in a scene
10
+ """
11
+
12
+ self.scene = scene
13
+ self.shader = shader
14
+ self.cube = Mesh(scene.engine.root + '/bsk_assets/cube.obj')
15
+ self.particle_renderers = {self.cube : ParticleRenderer(scene, self.cube, self.shader)}
16
+
17
+
18
+ def add(self, mesh: Mesh=None, life: float=1.0, position: tuple|float=0, material: Material=None, scale: float=1.0, velocity: tuple|float=0, acceleration: tuple|float=0) -> bool:
19
+ """
20
+ Add a new particle to the scene
21
+ Args:
22
+ mesh: Mesh
23
+ The basilisk mesh of the particle
24
+ life: float
25
+ The duration of the particle in seconds
26
+ position: tuple (x, y, z)
27
+ The initial position of the particle
28
+ color: tuple (r, g, b) (components out of 255)
29
+ The color of the particle
30
+ scale: float
31
+ The overall scale factor of the particle
32
+ velocity: tuple (x, y, z)
33
+ The inital velocity of the particle as a vector
34
+ acceleration: tuple (x, y, z)
35
+ The permanent acceleration of the particle as a vector
36
+ """
37
+
38
+ # Get the mesh and make a new particle renderer if the mesh is new
39
+ if mesh == None: mesh = self.cube
40
+ elif not isinstance(mesh, Mesh): raise ValueError(f'particle_handler.add: invlaid mesh type for particle: {type(mesh)}')
41
+ if mesh not in self.particle_renderers: self.particle_renderers[mesh] = ParticleRenderer(self.scene, mesh, self.shader)
42
+
43
+ # Get material ID
44
+ if material == None: material_index = 0
45
+ elif isinstance(material, Material):
46
+ self.scene.engine.material_handler.add(material)
47
+ material_index = material.index
48
+ else: raise ValueError(f'particle_handler.add: Invalid particle material type: {type(material)}')
49
+
50
+ # Validate the 3-component vectors
51
+ position = validate_tuple3('particle', 'add', position)
52
+ velocity = validate_tuple3('particle', 'add', velocity)
53
+ acceleration = validate_tuple3('particle', 'add', acceleration)
54
+
55
+ # Validate float inputs
56
+ life = validate_float('particle', 'add', life)
57
+ scale = validate_float('particle', 'add', scale)
58
+
59
+ # Add the particle to the renderer
60
+ self.particle_renderers[mesh].add(life, position, material_index, scale, velocity, acceleration)
61
+
62
+ def render(self) -> None:
63
+ for renderer in self.particle_renderers.values(): renderer.render()
64
+ def update(self) -> None:
65
65
  for renderer in self.particle_renderers.values(): renderer.update()
@@ -1,94 +1,94 @@
1
- import numpy as np
2
- from ..render.shader import Shader
3
- from ..mesh.mesh import Mesh
4
- from ..render.material import Material
5
- from numba import njit
6
-
7
-
8
- @njit
9
- def update_particle_matrix(particle_instances, dt):
10
- particle_instances[:,6:9] += particle_instances[:,9:12] * dt
11
- particle_instances[:,:3] += particle_instances[:,6:9] * dt
12
- particle_instances[:,5] -= dt/3
13
- return particle_instances
14
-
15
- @njit
16
- def get_alive(particles):
17
- return particles[particles[:, 5] >= 0]
18
-
19
- update_particle_matrix(np.zeros(shape=(2, 12), dtype='f4'), 1)
20
- get_alive(np.zeros(shape=(2, 12), dtype='f4'))
21
-
22
-
23
- class ParticleRenderer:
24
- def __init__(self, scene: ..., mesh: Mesh, shader: Shader=None) -> None:
25
- """
26
- Handels and renders the particles of a single mesh type
27
- """
28
-
29
- self.scene = scene
30
- self.ctx = scene.ctx
31
- root = scene.engine.root
32
- if shader: self.shader = shader
33
- else: self.shader = Shader(scene.engine, vert=root + '/shaders/particle.vert', frag=root + '/shaders/particle.frag')
34
-
35
- scene.engine.shader_handler.add(self.shader)
36
-
37
- self.particle_cube_size = 25
38
-
39
- self.particle_instances = np.zeros(shape=(1, 12), dtype='f4')
40
- self.instance_buffer = self.ctx.buffer(reserve=(12 * 3) * (self.particle_cube_size ** 3))
41
-
42
- self.vao = self.ctx.vertex_array( self.shader.program,
43
- [(self.ctx.buffer(mesh.data), '3f 2f 3f 3f 3f', *['in_position', 'in_uv', 'in_normal', 'in_tangent', 'in_bitangent']),
44
- (self.instance_buffer, '3f 1f 1f 1f /i', 'in_instance_pos', 'in_instance_mtl', 'scale', 'life')],
45
- skip_errors=True)
46
-
47
- def render(self) -> None:
48
- """
49
- Renders the alive particles in the scene
50
- """
51
-
52
- # Get the current particles
53
- alive_particles = get_alive(self.particle_instances)
54
- n = len(alive_particles)
55
-
56
- # Write and render
57
- self.instance_buffer.write(np.array(alive_particles[:,:6], order='C'))
58
- self.vao.render(instances=n)
59
-
60
- def update(self) -> None:
61
- """
62
- Updates the particle positions based on their given properties
63
- """
64
-
65
- self.particle_instances = get_alive(self.particle_instances)
66
- self.particle_instances = update_particle_matrix(self.particle_instances, self.scene.engine.delta_time)
67
-
68
- def add(self, life=1.0, position=(0, 0, 0), material: int=0, scale=1.0, velocity=(0, 3, 0), acceleration=(0, -10, 0)) -> bool:
69
- """
70
- Add a new particle to the scene
71
- Args:
72
- life: float
73
- The duration of the particle in seconds
74
- position: tuple (x, y, z)
75
- The initial position of the particle
76
- color: tuple (r, g, b) (components out of 255)
77
- The color of the particle
78
- scale: float
79
- The overall scale factor of the particle
80
- velocity: tuple (x, y, z)
81
- The inital velocity of the particle as a vector
82
- acceleration: tuple (x, y, z)
83
- The permanent acceleration of the particle as a vector
84
- """
85
- # Check if there is already the max number of particles
86
- if len(self.particle_instances) >= (self.particle_cube_size ** 3): return False
87
- # Create and add the particle to the scene
88
- new_particle = np.array([*position, material, scale, life, *velocity, *acceleration])
89
- self.particle_instances = np.vstack([new_particle, self.particle_instances], dtype='f4')
90
-
91
-
92
- def __del__(self):
93
- self.instance_buffer.release()
1
+ import numpy as np
2
+ from ..render.shader import Shader
3
+ from ..mesh.mesh import Mesh
4
+ from ..render.material import Material
5
+ from numba import njit
6
+
7
+
8
+ @njit
9
+ def update_particle_matrix(particle_instances, dt):
10
+ particle_instances[:,6:9] += particle_instances[:,9:12] * dt
11
+ particle_instances[:,:3] += particle_instances[:,6:9] * dt
12
+ particle_instances[:,5] -= dt/3
13
+ return particle_instances
14
+
15
+ @njit
16
+ def get_alive(particles):
17
+ return particles[particles[:, 5] >= 0]
18
+
19
+ update_particle_matrix(np.zeros(shape=(2, 12), dtype='f4'), 1)
20
+ get_alive(np.zeros(shape=(2, 12), dtype='f4'))
21
+
22
+
23
+ class ParticleRenderer:
24
+ def __init__(self, scene: ..., mesh: Mesh, shader: Shader=None) -> None:
25
+ """
26
+ Handels and renders the particles of a single mesh type
27
+ """
28
+
29
+ self.scene = scene
30
+ self.ctx = scene.ctx
31
+ root = scene.engine.root
32
+ if shader: self.shader = shader
33
+ else: self.shader = Shader(scene.engine, vert=root + '/shaders/particle.vert', frag=root + '/shaders/particle.frag')
34
+
35
+ scene.engine.shader_handler.add(self.shader)
36
+
37
+ self.particle_cube_size = 25
38
+
39
+ self.particle_instances = np.zeros(shape=(1, 12), dtype='f4')
40
+ self.instance_buffer = self.ctx.buffer(reserve=(12 * 3) * (self.particle_cube_size ** 3))
41
+
42
+ self.vao = self.ctx.vertex_array( self.shader.program,
43
+ [(self.ctx.buffer(mesh.data), '3f 2f 3f 3f 3f', *['in_position', 'in_uv', 'in_normal', 'in_tangent', 'in_bitangent']),
44
+ (self.instance_buffer, '3f 1f 1f 1f /i', 'in_instance_pos', 'in_instance_mtl', 'scale', 'life')],
45
+ skip_errors=True)
46
+
47
+ def render(self) -> None:
48
+ """
49
+ Renders the alive particles in the scene
50
+ """
51
+
52
+ # Get the current particles
53
+ alive_particles = get_alive(self.particle_instances)
54
+ n = len(alive_particles)
55
+
56
+ # Write and render
57
+ self.instance_buffer.write(np.array(alive_particles[:,:6], order='C'))
58
+ self.vao.render(instances=n)
59
+
60
+ def update(self) -> None:
61
+ """
62
+ Updates the particle positions based on their given properties
63
+ """
64
+
65
+ self.particle_instances = get_alive(self.particle_instances)
66
+ self.particle_instances = update_particle_matrix(self.particle_instances, self.scene.engine.delta_time)
67
+
68
+ def add(self, life=1.0, position=(0, 0, 0), material: int=0, scale=1.0, velocity=(0, 3, 0), acceleration=(0, -10, 0)) -> bool:
69
+ """
70
+ Add a new particle to the scene
71
+ Args:
72
+ life: float
73
+ The duration of the particle in seconds
74
+ position: tuple (x, y, z)
75
+ The initial position of the particle
76
+ color: tuple (r, g, b) (components out of 255)
77
+ The color of the particle
78
+ scale: float
79
+ The overall scale factor of the particle
80
+ velocity: tuple (x, y, z)
81
+ The inital velocity of the particle as a vector
82
+ acceleration: tuple (x, y, z)
83
+ The permanent acceleration of the particle as a vector
84
+ """
85
+ # Check if there is already the max number of particles
86
+ if len(self.particle_instances) >= (self.particle_cube_size ** 3): return False
87
+ # Create and add the particle to the scene
88
+ new_particle = np.array([*position, material, scale, life, *velocity, *acceleration])
89
+ self.particle_instances = np.vstack([new_particle, self.particle_instances], dtype='f4')
90
+
91
+
92
+ def __del__(self):
93
+ self.instance_buffer.release()
94
94
  self.vao.release()