basilisk-engine 0.1.22__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.

@@ -7,56 +7,90 @@ from ..render.shader import Shader
7
7
  class Framebuffer:
8
8
  engine: ...
9
9
  """Reference to the parent engine"""
10
- fbo: mgl.Framebuffer = None
10
+ size: tuple[int] | None=None
11
+ """The dimensions of the framebuffer (x, y). Defaults to window size if None"""
12
+ scale: float=1.0
13
+ """Scaling factor applied to the size. Best for use with default size"""
14
+ texture_filter: tuple[int]=(mgl.NEAREST, mgl.NEAREST)
15
+ """The filter applied to the texture when rendering"""
16
+ fbo: mgl.Framebuffer=None
11
17
  """The core framebuffer the object provides abstraction for."""
12
- texture: mgl.Texture = None
18
+ texture: mgl.Texture=None
13
19
  """The color texture of the framebuffer"""
14
- depth: mgl.Texture = None
20
+ depth: mgl.Texture=None
15
21
  """The depth texture of the framebuffer"""
16
- size: tuple[int]
17
- """The dimensions of the framebuffer (x, y)"""
22
+ _color_attachments = None
23
+ """"""
24
+ _depth_attachment = None
25
+ """"""
18
26
 
19
- def __init__(self, engine, size: tuple[int]=None, resolution_scale: float=1.0, components: int=4, filter=(mgl.LINEAR, mgl.LINEAR)) -> None:
27
+ def __init__(self, engine: ..., size: tuple[int]=None, n_color_attachments: int=1, scale: float=1.0, linear_filter: bool=True) -> None:
20
28
  """
21
- Abstraction to the mgl framebuffer
22
- Args:
23
- engine: mgl.Engine:
24
- The parent engine
25
- size: tuple[int]:
26
- The dimensions of the framebuffer (x, y)
29
+ Abstraction of the MGL framebuffer.
30
+ Has the given number of color attachements (4-component) and 1 depth attachment.
31
+ All textures are of uniform size.
32
+ """
33
+
34
+ self.engine = engine
35
+ self.ctx = engine.ctx
36
+ self._size = size
37
+ self.scale = scale
38
+ self.texture_filter = (mgl.LINEAR, mgl.LINEAR) if linear_filter else (mgl.NEAREST, mgl.NEAREST)
39
+ self.attachments = n_color_attachments
40
+
41
+ self.load_pipeline()
42
+ self.generate_fbo()
43
+
44
+ self.engine.fbos.append(self)
45
+
46
+ def generate_fbo(self):
47
+ """
48
+ Generates fresh depth texture and color textures and creates an FBO
49
+ """
50
+
51
+ # Release existing memory
52
+ self.__del__()
53
+
54
+ # Create textures
55
+ self._color_attachments = [self.ctx.texture(self.size, components=4)]
56
+ for tex in self._color_attachments: tex.filter = self.texture_filter
57
+ self._depth_attachment = self.ctx.depth_texture(self.size)
58
+
59
+ # Create the internal fbo
60
+ self.fbo = self.ctx.framebuffer(self._color_attachments, self._depth_attachment)
61
+
62
+ def resize(self, new_size: tuple[int]=None) -> None:
63
+ """
64
+ Update set size framebuffers with the given size.
27
65
  """
28
66
 
29
- # Set attributes
30
- self.engine = engine
31
- self.ctx = engine.ctx
32
- self.components = components
33
-
34
- # Set the size
35
- self.resolution_scale = resolution_scale
36
- self._size = size
37
- self.size = self._size if self._size else self.engine.win_size
38
- self.size = (int(self.size[0] * resolution_scale), int(self.size[1] * resolution_scale))
39
-
40
- # Create the fbo
41
- self.texture = self.ctx.texture(self.size, components=self.components)
42
- self.depth = self.ctx.depth_texture(self.size)
43
- self.fbo = self.ctx.framebuffer([self.texture], self.depth)
67
+ # Check that we are not updating the size to the existing size and
68
+ if self._size and self._size == new_size: return
69
+
70
+ # If we have a set size, update with the given size
71
+ if self._size and new_size: self._size = new_size
72
+
73
+ # Update the textures and fbo
74
+ self.generate_fbo()
75
+
76
+ def load_pipeline(self) -> None:
77
+ """
78
+ Loads the shader, vbo, and vao used to display the fbo
79
+ """
44
80
 
45
81
  # Load Shaders
46
82
  self.shader = Shader(self.engine, self.engine.root + '/shaders/frame.vert', self.engine.root + '/shaders/frame.frag')
47
- self.engine.scene.shader_handler.add(self.shader)
83
+ self.engine.shader_handler.add(self.shader)
48
84
 
49
85
  # Load VAO
50
86
  self.vbo = self.ctx.buffer(np.array([[-1, -1, 0, 0, 0], [1, -1, 0, 1, 0], [1, 1, 0, 1, 1], [-1, 1, 0, 0, 1], [-1, -1, 0, 0, 0], [1, 1, 0, 1, 1]], dtype='f4'))
51
87
  self.vao = self.ctx.vertex_array(self.shader.program, [(self.vbo, '3f 2f', 'in_position', 'in_uv')], skip_errors=True)
52
88
 
53
- # Save the filter
54
- self.filter = filter
89
+ def render(self, render_target=None) -> None:
55
90
 
56
- # Add to the engine for updates
57
- self.engine.fbos.append(self)
91
+ target = render_target if render_target else self.engine.frame
58
92
 
59
- def render(self) -> None:
93
+ target.use()
60
94
  self.shader.program['screenTexture'] = 0
61
95
  self.texture.use(location=0)
62
96
  self.vao.render()
@@ -86,46 +120,170 @@ class Framebuffer:
86
120
  img = Image.frombytes('RGB', self.size, data).transpose(Image.FLIP_TOP_BOTTOM)
87
121
  img.save(f'{path}.png')
88
122
 
89
- def resize(self, size: tuple[int]=None) -> None:
123
+
124
+ @property
125
+ def size(self) -> tuple[int]:
126
+ """Size of the textures in the fbo in pixels (x: int, y: int)"""
127
+ size = self._size if self._size else self.engine.win_size
128
+ size = tuple(map((lambda x: int(x * self.scale)), size))
129
+ return size
130
+ @property
131
+ def texture(self) -> mgl.Texture:
132
+ """First color attachment in the fbo"""
133
+ return self._color_attachments[0]
134
+ @property
135
+ def color_attachments(self) -> ...:
136
+ """List of all color attachments in the fbo"""
137
+ return self._color_attachments
138
+ @property
139
+ def depth(self) -> mgl.Texture:
140
+ """Depth attachment of the fbo"""
141
+ return self._depth_attachment
142
+ @property
143
+ def data(self) -> bytes:
144
+ """Reads the data from the fbo"""
145
+ return self.fbo.read()
146
+
147
+
148
+ @size.setter
149
+ def size(self, value: tuple[int]=None) -> tuple[int]:
150
+ self.resize(value)
151
+ return self.size
152
+
153
+ def __repr__(self) -> str:
154
+ return f'<bsk.Framebuffer | size: {self.size}>'
155
+
156
+ def __del__(self) -> None:
90
157
  """
91
- Resize the buffer to the given size. None for window size
158
+ Releases all memory used by the fbo
92
159
  """
93
160
 
94
- # Release old memory
95
- self.__del__()
161
+ if self._color_attachments: [tex.release() for tex in self._color_attachments]
162
+ if self._depth_attachment: self._depth_attachment.release()
163
+ if self.fbo: self.fbo.release()
96
164
 
97
- # Set/get size attribute
98
- if size:
99
- self.size = size
100
- else:
101
- self.size = self._size if self._size else self.engine.win_size
102
- self.size = (int(self.size[0] * self.resolution_scale), int(self.size[1] * self.resolution_scale))
165
+ # class Framebuffer:
166
+ # engine: ...
167
+ # """Reference to the parent engine"""
168
+ # fbo: mgl.Framebuffer = None
169
+ # """The core framebuffer the object provides abstraction for."""
170
+ # texture: mgl.Texture = None
171
+ # """The color texture of the framebuffer"""
172
+ # depth: mgl.Texture = None
173
+ # """The depth texture of the framebuffer"""
174
+ # size: tuple[int]
175
+ # """The dimensions of the framebuffer (x, y)"""
103
176
 
104
- # Create the fbo
105
- self.texture = self.ctx.texture(self.size, components=self.components)
106
- self.depth = self.ctx.depth_texture(self.size)
107
- self.fbo = self.ctx.framebuffer([self.texture], self.depth)
177
+ # def __init__(self, engine, size: tuple[int]=None, resolution_scale: float=1.0, components: int=4, filter=(mgl.LINEAR, mgl.LINEAR)) -> None:
178
+ # """
179
+ # Abstraction to the mgl framebuffer
180
+ # Args:
181
+ # engine: mgl.Engine:
182
+ # The parent engine
183
+ # size: tuple[int]:
184
+ # The dimensions of the framebuffer (x, y)
185
+ # """
186
+
187
+ # # Set attributes
188
+ # self.engine = engine
189
+ # self.ctx = engine.ctx
190
+ # self.components = components
108
191
 
109
- self.filter = self._filter
192
+ # # Set the size
193
+ # self.resolution_scale = resolution_scale
194
+ # self._size = size
195
+ # self.size = self._size if self._size else self.engine.win_size
196
+ # self.size = (int(self.size[0] * resolution_scale), int(self.size[1] * resolution_scale))
197
+
198
+ # # Create the fbo
199
+ # self.texture = self.ctx.texture(self.size, components=self.components)
200
+ # self.depth = self.ctx.depth_texture(self.size)
201
+ # self.fbo = self.ctx.framebuffer([self.texture], self.depth)
110
202
 
111
- @property
112
- def data(self):
113
- return self.fbo.read(components=3, alignment=1)
203
+ # # Load Shaders
204
+ # self.shader = Shader(self.engine, self.engine.root + '/shaders/frame.vert', self.engine.root + '/shaders/frame.frag')
205
+ # self.engine.shader_handler.add(self.shader)
114
206
 
115
- @property
116
- def filter(self):
117
- return self.texture.filter
207
+ # # Load VAO
208
+ # self.vbo = self.ctx.buffer(np.array([[-1, -1, 0, 0, 0], [1, -1, 0, 1, 0], [1, 1, 0, 1, 1], [-1, 1, 0, 0, 1], [-1, -1, 0, 0, 0], [1, 1, 0, 1, 1]], dtype='f4'))
209
+ # self.vao = self.ctx.vertex_array(self.shader.program, [(self.vbo, '3f 2f', 'in_position', 'in_uv')], skip_errors=True)
210
+
211
+ # # Save the filter
212
+ # self.filter = filter
213
+
214
+ # # Add to the engine for updates
215
+ # self.engine.fbos.append(self)
216
+
217
+ # def render(self) -> None:
218
+ # self.shader.program['screenTexture'] = 0
219
+ # self.texture.use(location=0)
220
+ # self.vao.render()
221
+
222
+ # def use(self) -> None:
223
+ # """
224
+ # Select this framebuffer for use
225
+ # """
226
+
227
+ # self.fbo.use()
228
+
229
+ # def clear(self) -> None:
230
+ # """
231
+ # Clear all data currently in the textures (set to black)
232
+ # """
233
+
234
+ # self.fbo.clear()
235
+
236
+ # def save(self, destination: str=None) -> None:
237
+ # """
238
+ # Saves the frame as an image to the given file destination
239
+ # """
240
+
241
+ # path = destination if destination else 'screenshot'
242
+
243
+ # data = self.fbo.read(components=3, alignment=1)
244
+ # img = Image.frombytes('RGB', self.size, data).transpose(Image.FLIP_TOP_BOTTOM)
245
+ # img.save(f'{path}.png')
246
+
247
+ # def resize(self, size: tuple[int]=None) -> None:
248
+ # """
249
+ # Resize the buffer to the given size. None for window size
250
+ # """
251
+
252
+ # # Release old memory
253
+ # self.__del__()
254
+
255
+ # # Set/get size attribute
256
+ # if size:
257
+ # self.size = size
258
+ # else:
259
+ # self.size = self._size if self._size else self.engine.win_size
260
+ # self.size = (int(self.size[0] * self.resolution_scale), int(self.size[1] * self.resolution_scale))
261
+
262
+ # # Create the fbo
263
+ # self.texture = self.ctx.texture(self.size, components=self.components)
264
+ # self.depth = self.ctx.depth_texture(self.size)
265
+ # self.fbo = self.ctx.framebuffer([self.texture], self.depth)
266
+
267
+ # self.filter = self._filter
268
+
269
+ # @property
270
+ # def data(self):
271
+ # return self.fbo.read(components=3, alignment=1)
272
+
273
+ # @property
274
+ # def filter(self):
275
+ # return self.texture.filter
118
276
 
119
- @filter.setter
120
- def filter(self, value):
121
- self._filter = value
122
- self.texture.filter = value
277
+ # @filter.setter
278
+ # def filter(self, value):
279
+ # self._filter = value
280
+ # self.texture.filter = value
123
281
 
124
- def __repr__(self) -> str:
125
- return f'<bsk.Framebuffer | size: {self.size}>'
282
+ # def __repr__(self) -> str:
283
+ # return f'<bsk.Framebuffer | size: {self.size}>'
126
284
 
127
- def __del__(self) -> None:
128
- # Release any existing memory in case of a resize
129
- if self.texture: self.texture.release()
130
- if self.depth: self.depth.release()
131
- if self.fbo: self.fbo.release()
285
+ # def __del__(self) -> None:
286
+ # # Release any existing memory in case of a resize
287
+ # if self.texture: self.texture.release()
288
+ # if self.depth: self.depth.release()
289
+ # if self.fbo: self.fbo.release()
@@ -2,15 +2,12 @@ import moderngl as mgl
2
2
  import glm
3
3
  import numpy as np
4
4
 
5
-
6
5
  texture_sizes = (8, 64, 512, 1024, 2048)
7
6
 
8
7
 
9
8
  class ImageHandler():
10
- engine: any
9
+ engine: ...
11
10
  """Back refernce to the parent engine"""
12
- scene: any
13
- """Back refernce to the parent scene"""
14
11
  ctx: mgl.Context
15
12
  """Back reference to the Context used by the scene/engine"""
16
13
  images: list
@@ -18,16 +15,15 @@ class ImageHandler():
18
15
  texture_arrays: dict
19
16
  """Dictionary of textures arrays for writting textures to GPU"""
20
17
 
21
- def __init__(self, scene) -> None:
18
+ def __init__(self, engine) -> None:
22
19
  """
23
20
  Container for all the basilisk image objects in the scene.
24
21
  Handles the managment and writting of all image textures.
25
22
  """
26
23
 
27
24
  # Set back references
28
- self.scene = scene
29
- self.engine = scene.engine
30
- self.ctx = scene.engine.ctx
25
+ self.engine = engine
26
+ self.ctx = engine.ctx
31
27
 
32
28
  self.images = []
33
29
  self.texture_arrays = {size : [] for size in texture_sizes}
@@ -83,11 +79,13 @@ class ImageHandler():
83
79
  Writes all texture arrays to shaders that use images
84
80
  """
85
81
 
82
+ if not self.engine.shader_handler: return
83
+
86
84
  if regenerate: self.generate_texture_array()
87
85
 
88
86
  if not self.texture_arrays: return
89
87
 
90
- for shader in self.engine.scene.shader_handler.shaders:
88
+ for shader in self.engine.shader_handler.shaders:
91
89
  if 'textureArrays[5]' not in shader.uniforms: continue
92
90
 
93
91
  for i, size in enumerate(texture_sizes):
@@ -40,7 +40,7 @@ class LightHandler():
40
40
 
41
41
  # if not program: program = self.engine.shader.program
42
42
 
43
- for shader in self.scene.shader_handler.shaders:
43
+ for shader in self.engine.shader_handler.shaders:
44
44
  if 'numDirLights' not in shader.uniforms: continue
45
45
 
46
46
  program = shader.program
@@ -7,32 +7,28 @@ import numpy as np
7
7
  class MaterialHandler():
8
8
  engine: ...
9
9
  """Back reference to the parent engine"""
10
- scene: ...
11
- """Back reference to the parent scene"""
12
10
  ctx: mgl.Context
13
11
  """Back reference to the parent context"""
14
12
  materials: list[Material]
15
- """List containing all the materials in the scene"""
13
+ """List containing all the materials in the engine"""
16
14
  data_texture: mgl.Texture
17
- """ModernGL texture containing all the material data for materials in the scene"""
15
+ """ModernGL texture containing all the material data for materials in the engine"""
18
16
 
19
- def __init__(self, scene) -> None:
17
+ def __init__(self, engine) -> None:
20
18
  """
21
- Handles all the materials introduced to a scene.
19
+ Handles all the materials introduced to an engine.
22
20
  Writes material information to the GPU
23
21
  """
24
22
 
25
23
  # Back references
26
- self.scene = scene
27
- self.engine = scene.engine
28
- self.ctx = scene.engine.ctx
24
+ self.engine = engine
25
+ self.ctx = engine.ctx
29
26
 
30
27
  # Initialize data
31
28
  self.materials = []
32
29
  self.data_texture = None
33
- self.set_base()
34
30
 
35
- self.image_handler = ImageHandler(scene)
31
+ self.image_handler = ImageHandler(engine)
36
32
 
37
33
  def add(self, material: Material) -> None:
38
34
  """
@@ -93,7 +89,7 @@ class MaterialHandler():
93
89
 
94
90
  if not self.data_texture: return
95
91
 
96
- for shader in self.engine.scene.shader_handler.shaders:
92
+ for shader in self.engine.shader_handler.shaders:
97
93
  if 'materialsTexture' not in shader.uniforms: continue
98
94
 
99
95
  shader.program['materialsTexture'] = 9
basilisk/render/shader.py CHANGED
@@ -93,8 +93,7 @@ class Shader:
93
93
  Selects a shader for use
94
94
  """
95
95
 
96
- self.engine.scene.shader_handler.add(self)
97
- # self.engine.scene.node_handler.chunk_handler.update_all()
96
+ self.engine.shader_handler.add(self)
98
97
  self.engine.scene.node_handler.chunk_handler.swap_default(self)
99
98
 
100
99
  def write(self, name: str, value) -> None:
@@ -15,19 +15,23 @@ class ShaderHandler:
15
15
  uniform_values: dict = {}
16
16
  """Dictionary containing uniform values"""
17
17
 
18
- def __init__(self, scene) -> None:
18
+ def __init__(self, engine) -> None:
19
19
  """
20
20
  Handles all the shader programs in a basilisk scene
21
21
  """
22
22
 
23
23
  # Back references
24
- self.scene = scene
25
- self.engine = scene.engine
26
- self.ctx = scene.engine.ctx
24
+ self.engine = engine
25
+ self.ctx = engine.ctx
27
26
 
28
27
  # Initalize dictionaries
29
28
  self.shaders = set()
30
- self.add(self.engine.shader)
29
+
30
+ # Load a default shader
31
+ self.default_shader = Shader(self, self.engine.root + '/shaders/batch.vert', self.engine.root + '/shaders/batch.frag')
32
+ self.default_shader.hash = self.default_shader.hash + hash('engine_shader')
33
+ self.add(self.default_shader)
34
+ setattr(self.engine, "_shader", self.default_shader)
31
35
 
32
36
  def add(self, shader: Shader) -> None:
33
37
  """
@@ -41,14 +45,13 @@ class ShaderHandler:
41
45
 
42
46
  self.shaders.add(shader)
43
47
 
44
- if self.scene.material_handler:
45
- self.scene.light_handler.write()
46
- self.scene.material_handler.write()
47
- self.scene.material_handler.image_handler.write()
48
+ if self.engine.material_handler:
49
+ self.engine.material_handler.write()
50
+ self.engine.material_handler.image_handler.write()
48
51
 
49
52
  return shader
50
53
 
51
- def get_uniforms_values(self) -> None:
54
+ def get_uniforms_values(self, scene: ...) -> None:
52
55
  """
53
56
  Gets uniforms from various parts of the scene.
54
57
  These values are stored and used in write_all_uniforms and update_uniforms.
@@ -56,18 +59,18 @@ class ShaderHandler:
56
59
  """
57
60
 
58
61
  self.uniform_values = {
59
- 'projectionMatrix' : self.scene.camera.m_proj,
60
- 'viewMatrix' : self.scene.camera.m_view,
61
- 'cameraPosition' : self.scene.camera.position,
62
+ 'projectionMatrix' : scene.camera.m_proj,
63
+ 'viewMatrix' : scene.camera.m_view,
64
+ 'cameraPosition' : scene.camera.position,
62
65
  'viewportDimensions' : glm.vec2(self.engine.win_size),
63
66
  }
64
67
 
65
- def write(self) -> None:
68
+ def write(self, scene: ...) -> None:
66
69
  """
67
70
  Writes all of the uniforms in every shader program.
68
71
  """
69
72
 
70
- self.get_uniforms_values()
73
+ self.get_uniforms_values(scene)
71
74
  for uniform in self.uniform_values:
72
75
  for shader in self.shaders:
73
76
  if not uniform in shader.uniforms: continue # Does not write uniforms not in the shader
basilisk/render/sky.py CHANGED
@@ -11,7 +11,7 @@ class Sky:
11
11
  Handler for all skybox rendering
12
12
  """
13
13
 
14
- self.scene = engine.scene
14
+ self.engine = engine
15
15
  self.ctx = engine.ctx
16
16
 
17
17
  if not sky_texture: sky_texture = engine.root + '/bsk_assets/skybox.png'
@@ -30,7 +30,7 @@ class Sky:
30
30
  self.shader.program['skyboxTexture'] = 8
31
31
  self.texture_cube.use(location = 8)
32
32
 
33
- shader = self.scene.engine.shader
33
+ shader = self.engine.shader
34
34
  if 'skyboxTexture' not in shader.uniforms: return
35
35
  shader.program['skyboxTexture'] = 8
36
36
  self.texture_cube.use(location = 8)
@@ -107,8 +107,8 @@ class Sky:
107
107
 
108
108
  # Create a renderable vao
109
109
  self.vbo = self.ctx.buffer(vertex_data)
110
- root = self.scene.engine.root
111
- self.shader = self.scene.shader_handler.add(Shader(self.scene.engine, root + '/shaders/sky.vert', root + '/shaders/sky.frag'))
110
+ root = self.engine.root
111
+ self.shader = self.engine.shader_handler.add(Shader(self.engine, root + '/shaders/sky.vert', root + '/shaders/sky.frag'))
112
112
  self.vao = self.ctx.vertex_array(self.shader.program, [(self.vbo, '3f', 'in_position')], skip_errors=True)
113
113
 
114
114
  def __del__(self):