basilisk-engine 0.1.6__py3-none-any.whl → 0.1.8__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.
- basilisk/__init__.py +14 -13
- basilisk/audio/__init__.py +0 -0
- basilisk/audio/sound.py +32 -0
- basilisk/bsk_assets/cube.obj +48 -48
- basilisk/collisions/broad/broad_aabb.py +102 -102
- basilisk/collisions/broad/broad_bvh.py +137 -137
- basilisk/collisions/collider.py +95 -95
- basilisk/collisions/collider_handler.py +224 -224
- basilisk/collisions/narrow/contact_manifold.py +95 -95
- basilisk/collisions/narrow/dataclasses.py +34 -34
- basilisk/collisions/narrow/deprecated.py +46 -46
- basilisk/collisions/narrow/epa.py +91 -91
- basilisk/collisions/narrow/gjk.py +66 -66
- basilisk/collisions/narrow/graham_scan.py +24 -24
- basilisk/collisions/narrow/helper.py +29 -29
- basilisk/collisions/narrow/line_intersections.py +106 -106
- basilisk/collisions/narrow/sutherland_hodgman.py +75 -75
- basilisk/config.py +2 -2
- basilisk/draw/draw.py +100 -100
- basilisk/draw/draw_handler.py +179 -179
- basilisk/draw/font_renderer.py +28 -28
- basilisk/engine.py +202 -200
- basilisk/generic/abstract_bvh.py +15 -15
- basilisk/generic/abstract_custom.py +133 -133
- basilisk/generic/collisions.py +72 -72
- basilisk/generic/input_validation.py +66 -66
- basilisk/generic/math.py +6 -6
- basilisk/generic/matrices.py +35 -35
- basilisk/generic/meshes.py +72 -72
- basilisk/generic/quat.py +142 -142
- basilisk/generic/quat_methods.py +7 -7
- basilisk/generic/raycast_result.py +23 -23
- basilisk/generic/vec3.py +143 -143
- basilisk/input/mouse.py +61 -61
- basilisk/input/path.py +14 -14
- basilisk/mesh/cube.py +33 -33
- basilisk/mesh/mesh.py +230 -230
- basilisk/mesh/mesh_from_data.py +130 -130
- basilisk/mesh/model.py +271 -271
- basilisk/mesh/narrow_aabb.py +89 -89
- basilisk/mesh/narrow_bvh.py +91 -91
- basilisk/mesh/narrow_primative.py +23 -23
- basilisk/nodes/helper.py +28 -28
- basilisk/nodes/node.py +682 -682
- basilisk/nodes/node_handler.py +95 -95
- basilisk/particles/particle_handler.py +63 -63
- basilisk/particles/particle_renderer.py +87 -87
- basilisk/physics/impulse.py +112 -112
- basilisk/physics/physics_body.py +43 -43
- basilisk/physics/physics_engine.py +35 -35
- basilisk/render/batch.py +86 -86
- basilisk/render/camera.py +206 -206
- basilisk/render/chunk.py +99 -99
- basilisk/render/chunk_handler.py +154 -154
- basilisk/render/frame.py +101 -99
- basilisk/render/framebuffer.py +130 -105
- basilisk/render/image.py +87 -87
- basilisk/render/image_handler.py +122 -122
- basilisk/render/light.py +96 -96
- basilisk/render/light_handler.py +58 -58
- basilisk/render/material.py +219 -219
- basilisk/render/material_handler.py +135 -135
- basilisk/render/post_process.py +132 -132
- basilisk/render/shader.py +109 -109
- basilisk/render/shader_handler.py +79 -79
- basilisk/render/sky.py +120 -120
- basilisk/scene.py +264 -256
- basilisk/shaders/batch.frag +276 -276
- basilisk/shaders/batch.vert +115 -115
- basilisk/shaders/crt.frag +31 -31
- basilisk/shaders/draw.frag +21 -21
- basilisk/shaders/draw.vert +21 -21
- basilisk/shaders/filter.frag +22 -22
- basilisk/shaders/frame.frag +12 -12
- basilisk/shaders/frame.vert +13 -13
- basilisk/shaders/geometry.frag +8 -8
- basilisk/shaders/geometry.vert +41 -41
- basilisk/shaders/normal.frag +59 -59
- basilisk/shaders/normal.vert +96 -96
- basilisk/shaders/particle.frag +71 -71
- basilisk/shaders/particle.vert +84 -84
- basilisk/shaders/sky.frag +9 -9
- basilisk/shaders/sky.vert +13 -13
- {basilisk_engine-0.1.6.dist-info → basilisk_engine-0.1.8.dist-info}/METADATA +39 -45
- basilisk_engine-0.1.8.dist-info/RECORD +103 -0
- {basilisk_engine-0.1.6.dist-info → basilisk_engine-0.1.8.dist-info}/WHEEL +1 -1
- basilisk_engine-0.1.6.dist-info/RECORD +0 -101
- {basilisk_engine-0.1.6.dist-info → basilisk_engine-0.1.8.dist-info}/top_level.txt +0 -0
basilisk/render/framebuffer.py
CHANGED
|
@@ -1,106 +1,131 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
self.
|
|
31
|
-
self.
|
|
32
|
-
self.components = components
|
|
33
|
-
|
|
34
|
-
#
|
|
35
|
-
self.
|
|
36
|
-
self.
|
|
37
|
-
self.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
self.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
1
|
+
import numpy as np
|
|
2
|
+
import moderngl as mgl
|
|
3
|
+
from PIL import Image
|
|
4
|
+
from ..render.shader import Shader
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Framebuffer:
|
|
8
|
+
engine: ...
|
|
9
|
+
"""Reference to the parent engine"""
|
|
10
|
+
fbo: mgl.Framebuffer = None
|
|
11
|
+
"""The core framebuffer the object provides abstraction for."""
|
|
12
|
+
texture: mgl.Texture = None
|
|
13
|
+
"""The color texture of the framebuffer"""
|
|
14
|
+
depth: mgl.Texture = None
|
|
15
|
+
"""The depth texture of the framebuffer"""
|
|
16
|
+
size: tuple[int]
|
|
17
|
+
"""The dimensions of the framebuffer (x, y)"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, engine, size: tuple[int]=None, resolution_scale: float=1.0, components: int=4, filter=(mgl.LINEAR, mgl.LINEAR)) -> None:
|
|
20
|
+
"""
|
|
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)
|
|
27
|
+
"""
|
|
28
|
+
|
|
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)
|
|
44
|
+
|
|
45
|
+
# Load Shaders
|
|
46
|
+
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)
|
|
48
|
+
|
|
49
|
+
# Load VAO
|
|
50
|
+
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
|
+
self.vao = self.ctx.vertex_array(self.shader.program, [(self.vbo, '3f 2f', 'in_position', 'in_uv')], skip_errors=True)
|
|
52
|
+
|
|
53
|
+
# Save the filter
|
|
54
|
+
self.filter = filter
|
|
55
|
+
|
|
56
|
+
# Add to the engine for updates
|
|
57
|
+
self.engine.fbos.append(self)
|
|
58
|
+
|
|
59
|
+
def render(self) -> None:
|
|
60
|
+
self.shader.program['screenTexture'] = 0
|
|
61
|
+
self.texture.use(location=0)
|
|
62
|
+
self.vao.render()
|
|
63
|
+
|
|
64
|
+
def use(self) -> None:
|
|
65
|
+
"""
|
|
66
|
+
Select this framebuffer for use
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
self.fbo.use()
|
|
70
|
+
|
|
71
|
+
def clear(self) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Clear all data currently in the textures (set to black)
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
self.fbo.clear()
|
|
77
|
+
|
|
78
|
+
def save(self, destination: str=None) -> None:
|
|
79
|
+
"""
|
|
80
|
+
Saves the frame as an image to the given file destination
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
path = destination if destination else 'screenshot'
|
|
84
|
+
|
|
85
|
+
data = self.fbo.read(components=3, alignment=1)
|
|
86
|
+
img = Image.frombytes('RGB', self.size, data).transpose(Image.FLIP_TOP_BOTTOM)
|
|
87
|
+
img.save(f'{path}.png')
|
|
88
|
+
|
|
89
|
+
def resize(self, size: tuple[int]=None) -> None:
|
|
90
|
+
"""
|
|
91
|
+
Resize the buffer to the given size. None for window size
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
# Release old memory
|
|
95
|
+
self.__del__()
|
|
96
|
+
|
|
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))
|
|
103
|
+
|
|
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)
|
|
108
|
+
|
|
109
|
+
self.filter = self._filter
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def data(self):
|
|
113
|
+
return self.fbo.read(components=3, alignment=1)
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def filter(self):
|
|
117
|
+
return self.texture.filter
|
|
118
|
+
|
|
119
|
+
@filter.setter
|
|
120
|
+
def filter(self, value):
|
|
121
|
+
self._filter = value
|
|
122
|
+
self.texture.filter = value
|
|
123
|
+
|
|
124
|
+
def __repr__(self) -> str:
|
|
125
|
+
return f'<bsk.Framebuffer | size: {self.size}>'
|
|
126
|
+
|
|
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()
|
|
106
131
|
if self.fbo: self.fbo.release()
|
basilisk/render/image.py
CHANGED
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import sys
|
|
3
|
-
import numpy as np
|
|
4
|
-
import moderngl as mgl
|
|
5
|
-
import glm
|
|
6
|
-
import pygame as pg
|
|
7
|
-
from PIL import Image as PIL_Image
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
texture_sizes = (8, 64, 512, 1024, 2048)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class Image():
|
|
14
|
-
name: str
|
|
15
|
-
"""Name of the image"""
|
|
16
|
-
index: glm.ivec2
|
|
17
|
-
"""Location of the image in the texture arrays"""
|
|
18
|
-
data: np.ndarray
|
|
19
|
-
"""Array of the texture data"""
|
|
20
|
-
size: int
|
|
21
|
-
"""The width and height in pixels of the image"""
|
|
22
|
-
|
|
23
|
-
def __init__(self, path: str | os.PathLike | pg.Surface | mgl.Texture) -> None:
|
|
24
|
-
"""
|
|
25
|
-
A basilisk image object that contains a moderngl texture
|
|
26
|
-
Args:
|
|
27
|
-
path: str | os.PathLike | pg.Surface
|
|
28
|
-
The string path to the image. Can also read a pygame surface
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
# Check if the user is loading a pygame surface
|
|
32
|
-
if isinstance(path, str) or isinstance(path, os.PathLike):
|
|
33
|
-
return self._from_path(path)
|
|
34
|
-
elif isinstance(path, pg.Surface):
|
|
35
|
-
return self._from_surfaces(path)
|
|
36
|
-
elif isinstance(path, mgl.Texture):
|
|
37
|
-
return self._from_texture(path)
|
|
38
|
-
|
|
39
|
-
raise TypeError(f'Invalid path type: {type(path)}. Expected a string or os.PathLike')
|
|
40
|
-
|
|
41
|
-
def _from_path(self, path: str | os.PathLike) -> None:
|
|
42
|
-
"""
|
|
43
|
-
Loads a basilisk image from a pygame surface
|
|
44
|
-
Args:
|
|
45
|
-
"""
|
|
46
|
-
|
|
47
|
-
# Get name from path
|
|
48
|
-
self.name = path.split('/')[-1].split('\\')[-1].split('.')[0]
|
|
49
|
-
|
|
50
|
-
# Load image
|
|
51
|
-
img = PIL_Image.open(path).convert('RGBA')
|
|
52
|
-
# Set the size in one of the size buckets
|
|
53
|
-
size_buckets = texture_sizes
|
|
54
|
-
self.size = size_buckets[np.argmin(np.array([abs(size - img.size[0]) for size in size_buckets]))]
|
|
55
|
-
img = img.resize((self.size, self.size))
|
|
56
|
-
# Get the image data
|
|
57
|
-
self.data = img.tobytes()
|
|
58
|
-
|
|
59
|
-
# Default index value (to be set by image handler)
|
|
60
|
-
self.index = glm.ivec2(1, 1)
|
|
61
|
-
|
|
62
|
-
def _from_surface(self, surf: pg.Surface) -> None:
|
|
63
|
-
"""
|
|
64
|
-
Loads a basilisk image from a pygame surface
|
|
65
|
-
Args:
|
|
66
|
-
"""
|
|
67
|
-
|
|
68
|
-
# Set the size in one of the size buckets
|
|
69
|
-
size_buckets = texture_sizes
|
|
70
|
-
self.size = size_buckets[np.argmin(np.array([abs(size - surf.get_size()[0]) for size in size_buckets]))]
|
|
71
|
-
surf = pg.transform.scale(surf, (self.size, self.size)).convert_alpha()
|
|
72
|
-
# Get image data
|
|
73
|
-
self.data = pg.image.tobytes(surf, 'RGBA')
|
|
74
|
-
|
|
75
|
-
# Default index value (to be set by image handler)
|
|
76
|
-
self.index = glm.ivec2(1, 1)
|
|
77
|
-
|
|
78
|
-
def _from_texture(self, texture: mgl.Texture):
|
|
79
|
-
"""
|
|
80
|
-
|
|
81
|
-
"""
|
|
82
|
-
...
|
|
83
|
-
|
|
84
|
-
def __repr__(self) -> str:
|
|
85
|
-
"""
|
|
86
|
-
Returns a string representation of the object
|
|
87
|
-
"""
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import numpy as np
|
|
4
|
+
import moderngl as mgl
|
|
5
|
+
import glm
|
|
6
|
+
import pygame as pg
|
|
7
|
+
from PIL import Image as PIL_Image
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
texture_sizes = (8, 64, 512, 1024, 2048)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Image():
|
|
14
|
+
name: str
|
|
15
|
+
"""Name of the image"""
|
|
16
|
+
index: glm.ivec2
|
|
17
|
+
"""Location of the image in the texture arrays"""
|
|
18
|
+
data: np.ndarray
|
|
19
|
+
"""Array of the texture data"""
|
|
20
|
+
size: int
|
|
21
|
+
"""The width and height in pixels of the image"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, path: str | os.PathLike | pg.Surface | mgl.Texture) -> None:
|
|
24
|
+
"""
|
|
25
|
+
A basilisk image object that contains a moderngl texture
|
|
26
|
+
Args:
|
|
27
|
+
path: str | os.PathLike | pg.Surface
|
|
28
|
+
The string path to the image. Can also read a pygame surface
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
# Check if the user is loading a pygame surface
|
|
32
|
+
if isinstance(path, str) or isinstance(path, os.PathLike):
|
|
33
|
+
return self._from_path(path)
|
|
34
|
+
elif isinstance(path, pg.Surface):
|
|
35
|
+
return self._from_surfaces(path)
|
|
36
|
+
elif isinstance(path, mgl.Texture):
|
|
37
|
+
return self._from_texture(path)
|
|
38
|
+
|
|
39
|
+
raise TypeError(f'Invalid path type: {type(path)}. Expected a string or os.PathLike')
|
|
40
|
+
|
|
41
|
+
def _from_path(self, path: str | os.PathLike) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Loads a basilisk image from a pygame surface
|
|
44
|
+
Args:
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
# Get name from path
|
|
48
|
+
self.name = path.split('/')[-1].split('\\')[-1].split('.')[0]
|
|
49
|
+
|
|
50
|
+
# Load image
|
|
51
|
+
img = PIL_Image.open(path).convert('RGBA')
|
|
52
|
+
# Set the size in one of the size buckets
|
|
53
|
+
size_buckets = texture_sizes
|
|
54
|
+
self.size = size_buckets[np.argmin(np.array([abs(size - img.size[0]) for size in size_buckets]))]
|
|
55
|
+
img = img.resize((self.size, self.size))
|
|
56
|
+
# Get the image data
|
|
57
|
+
self.data = img.tobytes()
|
|
58
|
+
|
|
59
|
+
# Default index value (to be set by image handler)
|
|
60
|
+
self.index = glm.ivec2(1, 1)
|
|
61
|
+
|
|
62
|
+
def _from_surface(self, surf: pg.Surface) -> None:
|
|
63
|
+
"""
|
|
64
|
+
Loads a basilisk image from a pygame surface
|
|
65
|
+
Args:
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
# Set the size in one of the size buckets
|
|
69
|
+
size_buckets = texture_sizes
|
|
70
|
+
self.size = size_buckets[np.argmin(np.array([abs(size - surf.get_size()[0]) for size in size_buckets]))]
|
|
71
|
+
surf = pg.transform.scale(surf, (self.size, self.size)).convert_alpha()
|
|
72
|
+
# Get image data
|
|
73
|
+
self.data = pg.image.tobytes(surf, 'RGBA')
|
|
74
|
+
|
|
75
|
+
# Default index value (to be set by image handler)
|
|
76
|
+
self.index = glm.ivec2(1, 1)
|
|
77
|
+
|
|
78
|
+
def _from_texture(self, texture: mgl.Texture):
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
"""
|
|
82
|
+
...
|
|
83
|
+
|
|
84
|
+
def __repr__(self) -> str:
|
|
85
|
+
"""
|
|
86
|
+
Returns a string representation of the object
|
|
87
|
+
"""
|
|
88
88
|
return f'<Basilisk Image | {self.name}, ({self.size}x{self.size}), {sys.getsizeof(self.data) / 1024 / 1024:.2} mb>'
|
basilisk/render/image_handler.py
CHANGED
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
import moderngl as mgl
|
|
2
|
-
import glm
|
|
3
|
-
import numpy as np
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
texture_sizes = (8, 64, 512, 1024, 2048)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class ImageHandler():
|
|
10
|
-
engine: any
|
|
11
|
-
"""Back refernce to the parent engine"""
|
|
12
|
-
scene: any
|
|
13
|
-
"""Back refernce to the parent scene"""
|
|
14
|
-
ctx: mgl.Context
|
|
15
|
-
"""Back reference to the Context used by the scene/engine"""
|
|
16
|
-
images: list
|
|
17
|
-
"""List of basilisk Images containing all the loaded images given to the scene"""
|
|
18
|
-
texture_arrays: dict
|
|
19
|
-
"""Dictionary of textures arrays for writting textures to GPU"""
|
|
20
|
-
|
|
21
|
-
def __init__(self, scene) -> None:
|
|
22
|
-
"""
|
|
23
|
-
Container for all the basilisk image objects in the scene.
|
|
24
|
-
Handles the managment and writting of all image textures.
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
# Set back references
|
|
28
|
-
self.scene = scene
|
|
29
|
-
self.engine = scene.engine
|
|
30
|
-
self.ctx = scene.engine.ctx
|
|
31
|
-
|
|
32
|
-
self.images = []
|
|
33
|
-
self.texture_arrays = {size : [] for size in texture_sizes}
|
|
34
|
-
|
|
35
|
-
def add(self, image: any) -> None:
|
|
36
|
-
"""
|
|
37
|
-
Adds an existing basilisk image object to the handler for writting
|
|
38
|
-
Args:
|
|
39
|
-
image: bsk.Image
|
|
40
|
-
The existing image that is to be added to the scene.
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
|
-
if image in self.images: return
|
|
44
|
-
|
|
45
|
-
self.images.append(image)
|
|
46
|
-
self.write(regenerate=True)
|
|
47
|
-
|
|
48
|
-
def generate_texture_array(self) -> None:
|
|
49
|
-
"""
|
|
50
|
-
Generates texutre arrays for all the images. Updates the index of the image instance
|
|
51
|
-
"""
|
|
52
|
-
|
|
53
|
-
# Release any existsing texture arrays
|
|
54
|
-
for texture_array in self.texture_arrays.values():
|
|
55
|
-
if not texture_array: continue
|
|
56
|
-
texture_array.release()
|
|
57
|
-
|
|
58
|
-
self.texture_arrays = {size : [] for size in texture_sizes}
|
|
59
|
-
|
|
60
|
-
for image in self.images:
|
|
61
|
-
# Add the image data to the array
|
|
62
|
-
self.texture_arrays[image.size].append(image.data)
|
|
63
|
-
# Update the image index
|
|
64
|
-
image.index = glm.ivec2(texture_sizes.index(image.size), len(self.texture_arrays[image.size]) - 1)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
for size in self.texture_arrays:
|
|
68
|
-
# Check that there are textures in the bucket
|
|
69
|
-
if not len(self.texture_arrays[size]): continue
|
|
70
|
-
array_data = np.array(self.texture_arrays[size])
|
|
71
|
-
dim = (size, size, len(self.texture_arrays[size]))
|
|
72
|
-
|
|
73
|
-
# Make the array
|
|
74
|
-
self.texture_arrays[size] = self.ctx.texture_array(size=dim, components=4, data=array_data)
|
|
75
|
-
# Texture OpenGl settings
|
|
76
|
-
self.texture_arrays[size].build_mipmaps()
|
|
77
|
-
if size > 32: self.texture_arrays[size].filter = (mgl.LINEAR_MIPMAP_LINEAR, mgl.LINEAR)
|
|
78
|
-
else: self.texture_arrays[size].filter = (mgl.NEAREST, mgl.NEAREST)
|
|
79
|
-
self.texture_arrays[size].anisotropy = 32.0
|
|
80
|
-
|
|
81
|
-
def write(self, regenerate=False) -> None:
|
|
82
|
-
"""
|
|
83
|
-
Writes all texture arrays to shaders that use images
|
|
84
|
-
"""
|
|
85
|
-
|
|
86
|
-
if regenerate: self.generate_texture_array()
|
|
87
|
-
|
|
88
|
-
if not self.texture_arrays: return
|
|
89
|
-
|
|
90
|
-
for shader in self.engine.scene.shader_handler.shaders:
|
|
91
|
-
if 'textureArrays[5]' not in shader.uniforms: continue
|
|
92
|
-
|
|
93
|
-
for i, size in enumerate(texture_sizes):
|
|
94
|
-
if not size in self.texture_arrays: continue
|
|
95
|
-
if not self.texture_arrays[size]: continue
|
|
96
|
-
shader.program[f'textureArrays[{i}].array'] = i + 3
|
|
97
|
-
self.texture_arrays[size].use(location=i+3)
|
|
98
|
-
|
|
99
|
-
def get(self, identifier: str | int) -> any:
|
|
100
|
-
"""
|
|
101
|
-
Gets the basilisk image with the given name or index
|
|
102
|
-
Args:
|
|
103
|
-
identifier: str | int
|
|
104
|
-
The name string or index of the desired image
|
|
105
|
-
"""
|
|
106
|
-
|
|
107
|
-
# Simply use index if given
|
|
108
|
-
if isinstance(identifier, int): return self.images[identifier]
|
|
109
|
-
|
|
110
|
-
# Else, search the list for an image with the given name
|
|
111
|
-
for image in self.images:
|
|
112
|
-
if image.name != identifier: continue
|
|
113
|
-
return image
|
|
114
|
-
|
|
115
|
-
# No matching image found
|
|
116
|
-
return None
|
|
117
|
-
|
|
118
|
-
def __del__(self):
|
|
119
|
-
"""
|
|
120
|
-
Deallocates all texture arrays
|
|
121
|
-
"""
|
|
122
|
-
|
|
1
|
+
import moderngl as mgl
|
|
2
|
+
import glm
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
texture_sizes = (8, 64, 512, 1024, 2048)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ImageHandler():
|
|
10
|
+
engine: any
|
|
11
|
+
"""Back refernce to the parent engine"""
|
|
12
|
+
scene: any
|
|
13
|
+
"""Back refernce to the parent scene"""
|
|
14
|
+
ctx: mgl.Context
|
|
15
|
+
"""Back reference to the Context used by the scene/engine"""
|
|
16
|
+
images: list
|
|
17
|
+
"""List of basilisk Images containing all the loaded images given to the scene"""
|
|
18
|
+
texture_arrays: dict
|
|
19
|
+
"""Dictionary of textures arrays for writting textures to GPU"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, scene) -> None:
|
|
22
|
+
"""
|
|
23
|
+
Container for all the basilisk image objects in the scene.
|
|
24
|
+
Handles the managment and writting of all image textures.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
# Set back references
|
|
28
|
+
self.scene = scene
|
|
29
|
+
self.engine = scene.engine
|
|
30
|
+
self.ctx = scene.engine.ctx
|
|
31
|
+
|
|
32
|
+
self.images = []
|
|
33
|
+
self.texture_arrays = {size : [] for size in texture_sizes}
|
|
34
|
+
|
|
35
|
+
def add(self, image: any) -> None:
|
|
36
|
+
"""
|
|
37
|
+
Adds an existing basilisk image object to the handler for writting
|
|
38
|
+
Args:
|
|
39
|
+
image: bsk.Image
|
|
40
|
+
The existing image that is to be added to the scene.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
if image in self.images: return
|
|
44
|
+
|
|
45
|
+
self.images.append(image)
|
|
46
|
+
self.write(regenerate=True)
|
|
47
|
+
|
|
48
|
+
def generate_texture_array(self) -> None:
|
|
49
|
+
"""
|
|
50
|
+
Generates texutre arrays for all the images. Updates the index of the image instance
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
# Release any existsing texture arrays
|
|
54
|
+
for texture_array in self.texture_arrays.values():
|
|
55
|
+
if not texture_array: continue
|
|
56
|
+
texture_array.release()
|
|
57
|
+
|
|
58
|
+
self.texture_arrays = {size : [] for size in texture_sizes}
|
|
59
|
+
|
|
60
|
+
for image in self.images:
|
|
61
|
+
# Add the image data to the array
|
|
62
|
+
self.texture_arrays[image.size].append(image.data)
|
|
63
|
+
# Update the image index
|
|
64
|
+
image.index = glm.ivec2(texture_sizes.index(image.size), len(self.texture_arrays[image.size]) - 1)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
for size in self.texture_arrays:
|
|
68
|
+
# Check that there are textures in the bucket
|
|
69
|
+
if not len(self.texture_arrays[size]): continue
|
|
70
|
+
array_data = np.array(self.texture_arrays[size])
|
|
71
|
+
dim = (size, size, len(self.texture_arrays[size]))
|
|
72
|
+
|
|
73
|
+
# Make the array
|
|
74
|
+
self.texture_arrays[size] = self.ctx.texture_array(size=dim, components=4, data=array_data)
|
|
75
|
+
# Texture OpenGl settings
|
|
76
|
+
self.texture_arrays[size].build_mipmaps()
|
|
77
|
+
if size > 32: self.texture_arrays[size].filter = (mgl.LINEAR_MIPMAP_LINEAR, mgl.LINEAR)
|
|
78
|
+
else: self.texture_arrays[size].filter = (mgl.NEAREST, mgl.NEAREST)
|
|
79
|
+
self.texture_arrays[size].anisotropy = 32.0
|
|
80
|
+
|
|
81
|
+
def write(self, regenerate=False) -> None:
|
|
82
|
+
"""
|
|
83
|
+
Writes all texture arrays to shaders that use images
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
if regenerate: self.generate_texture_array()
|
|
87
|
+
|
|
88
|
+
if not self.texture_arrays: return
|
|
89
|
+
|
|
90
|
+
for shader in self.engine.scene.shader_handler.shaders:
|
|
91
|
+
if 'textureArrays[5]' not in shader.uniforms: continue
|
|
92
|
+
|
|
93
|
+
for i, size in enumerate(texture_sizes):
|
|
94
|
+
if not size in self.texture_arrays: continue
|
|
95
|
+
if not self.texture_arrays[size]: continue
|
|
96
|
+
shader.program[f'textureArrays[{i}].array'] = i + 3
|
|
97
|
+
self.texture_arrays[size].use(location=i+3)
|
|
98
|
+
|
|
99
|
+
def get(self, identifier: str | int) -> any:
|
|
100
|
+
"""
|
|
101
|
+
Gets the basilisk image with the given name or index
|
|
102
|
+
Args:
|
|
103
|
+
identifier: str | int
|
|
104
|
+
The name string or index of the desired image
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
# Simply use index if given
|
|
108
|
+
if isinstance(identifier, int): return self.images[identifier]
|
|
109
|
+
|
|
110
|
+
# Else, search the list for an image with the given name
|
|
111
|
+
for image in self.images:
|
|
112
|
+
if image.name != identifier: continue
|
|
113
|
+
return image
|
|
114
|
+
|
|
115
|
+
# No matching image found
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
def __del__(self):
|
|
119
|
+
"""
|
|
120
|
+
Deallocates all texture arrays
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
123
|
# [texture_array.release() for texture_array in self.texture_arrays]
|