basilisk-engine 0.1.42__py3-none-any.whl → 0.1.43__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 +26 -26
- basilisk/audio/sound.py +27 -27
- 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 +225 -225
- 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 +53 -53
- basilisk/draw/draw.py +100 -100
- basilisk/draw/draw_handler.py +178 -178
- basilisk/draw/font_renderer.py +28 -28
- basilisk/engine.py +169 -171
- basilisk/generic/abstract_bvh.py +15 -15
- basilisk/generic/abstract_custom.py +133 -133
- basilisk/generic/collisions.py +70 -70
- basilisk/generic/input_validation.py +82 -82
- basilisk/generic/math.py +17 -17
- 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 +26 -26
- basilisk/generic/vec3.py +143 -143
- basilisk/input_output/IO_handler.py +91 -91
- basilisk/input_output/clock.py +49 -49
- basilisk/input_output/keys.py +43 -43
- basilisk/input_output/mouse.py +90 -90
- basilisk/input_output/path.py +14 -14
- basilisk/mesh/cube.py +33 -33
- basilisk/mesh/mesh.py +233 -233
- basilisk/mesh/mesh_from_data.py +150 -150
- 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 +709 -709
- basilisk/nodes/node_handler.py +97 -97
- basilisk/particles/particle_handler.py +64 -64
- basilisk/particles/particle_renderer.py +93 -93
- basilisk/physics/impulse.py +112 -112
- basilisk/physics/physics_body.py +43 -43
- basilisk/physics/physics_engine.py +35 -35
- basilisk/render/batch.py +103 -103
- basilisk/render/bloom.py +118 -124
- basilisk/render/camera.py +260 -260
- basilisk/render/chunk.py +113 -108
- basilisk/render/chunk_handler.py +167 -167
- basilisk/render/frame.py +130 -128
- basilisk/render/framebuffer.py +192 -212
- basilisk/render/image.py +120 -120
- basilisk/render/image_handler.py +120 -120
- basilisk/render/light.py +96 -96
- basilisk/render/light_handler.py +58 -58
- basilisk/render/material.py +232 -232
- basilisk/render/material_handler.py +133 -133
- basilisk/render/post_process.py +180 -180
- basilisk/render/shader.py +135 -134
- basilisk/render/shader_handler.py +109 -94
- basilisk/render/sky.py +119 -121
- basilisk/scene.py +287 -288
- basilisk/shaders/batch.frag +293 -293
- basilisk/shaders/batch.vert +117 -117
- basilisk/shaders/bloom_downsample.frag +23 -42
- basilisk/shaders/bloom_upsample.frag +33 -33
- basilisk/shaders/crt.frag +34 -34
- basilisk/shaders/draw.frag +27 -27
- basilisk/shaders/draw.vert +25 -25
- basilisk/shaders/filter.frag +22 -22
- basilisk/shaders/frame.frag +13 -13
- basilisk/shaders/frame.vert +13 -13
- basilisk/shaders/frame_hdr.frag +27 -27
- basilisk/shaders/geometry.frag +10 -10
- basilisk/shaders/geometry.vert +41 -41
- basilisk/shaders/normal.frag +62 -62
- basilisk/shaders/normal.vert +96 -96
- basilisk/shaders/particle.frag +81 -81
- basilisk/shaders/particle.vert +86 -86
- basilisk/shaders/sky.frag +23 -23
- basilisk/shaders/sky.vert +13 -13
- {basilisk_engine-0.1.42.dist-info → basilisk_engine-0.1.43.dist-info}/METADATA +89 -89
- basilisk_engine-0.1.43.dist-info/RECORD +111 -0
- {basilisk_engine-0.1.42.dist-info → basilisk_engine-0.1.43.dist-info}/WHEEL +1 -1
- basilisk/input/__init__.py +0 -0
- basilisk/input/mouse.py +0 -62
- basilisk/input/path.py +0 -14
- basilisk/shaders/bloom_frame.frag +0 -25
- basilisk_engine-0.1.42.dist-info/RECORD +0 -115
- {basilisk_engine-0.1.42.dist-info → basilisk_engine-0.1.43.dist-info}/top_level.txt +0 -0
|
@@ -1,134 +1,134 @@
|
|
|
1
|
-
import moderngl as mgl
|
|
2
|
-
from ..render.image_handler import ImageHandler
|
|
3
|
-
from ..render.material import Material
|
|
4
|
-
import numpy as np
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class MaterialHandler():
|
|
8
|
-
engine: ...
|
|
9
|
-
"""Back reference to the parent engine"""
|
|
10
|
-
ctx: mgl.Context
|
|
11
|
-
"""Back reference to the parent context"""
|
|
12
|
-
materials: list[Material]
|
|
13
|
-
"""List containing all the materials in the engine"""
|
|
14
|
-
data_texture: mgl.Texture
|
|
15
|
-
"""ModernGL texture containing all the material data for materials in the engine"""
|
|
16
|
-
image_handler: ImageHandler=None
|
|
17
|
-
"""Handler for all images in the game"""
|
|
18
|
-
|
|
19
|
-
def __init__(self, engine) -> None:
|
|
20
|
-
"""
|
|
21
|
-
Handles all the materials introduced to an engine.
|
|
22
|
-
Writes material information to the GPU
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
# Back references
|
|
26
|
-
self.engine = engine
|
|
27
|
-
self.ctx = engine.ctx
|
|
28
|
-
|
|
29
|
-
# Initialize data
|
|
30
|
-
self.materials = []
|
|
31
|
-
self.data_texture = None
|
|
32
|
-
|
|
33
|
-
self.image_handler = ImageHandler(engine)
|
|
34
|
-
|
|
35
|
-
def add(self, material: Material) -> None:
|
|
36
|
-
"""
|
|
37
|
-
Adds the given material to the handler if it is not already present
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
write = False
|
|
41
|
-
|
|
42
|
-
if isinstance(material, Material): material = [material]
|
|
43
|
-
|
|
44
|
-
for mtl in material:
|
|
45
|
-
# Check that the material is not already in the scene
|
|
46
|
-
if mtl in self.materials: continue
|
|
47
|
-
# Update the material's handler
|
|
48
|
-
mtl.material_handler = self
|
|
49
|
-
# Add images
|
|
50
|
-
if mtl.texture: self.image_handler.add(mtl.texture)
|
|
51
|
-
if mtl.normal: self.image_handler.add(mtl.normal)
|
|
52
|
-
|
|
53
|
-
# Add the material
|
|
54
|
-
self.materials.append(mtl)
|
|
55
|
-
|
|
56
|
-
write = True
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
# Write materials
|
|
60
|
-
if write: self.write(regenerate=True)
|
|
61
|
-
|
|
62
|
-
def generate_material_texture(self) -> None:
|
|
63
|
-
"""
|
|
64
|
-
Generates the texture that is used to write material data to the GPU
|
|
65
|
-
"""
|
|
66
|
-
|
|
67
|
-
# Check that there are materials to write
|
|
68
|
-
if len(self.materials) == 0: return
|
|
69
|
-
|
|
70
|
-
# Release existing data texture
|
|
71
|
-
if self.data_texture: self.data_texture.release()
|
|
72
|
-
|
|
73
|
-
# Create empty texture data
|
|
74
|
-
material_data = np.zeros(shape=(len(self.materials), 28), dtype="f4")
|
|
75
|
-
|
|
76
|
-
# Get data from the materials
|
|
77
|
-
for i, mtl in enumerate(self.materials):
|
|
78
|
-
mtl.index = i
|
|
79
|
-
material_data[i] = mtl.get_data()
|
|
80
|
-
|
|
81
|
-
# Create texture from data
|
|
82
|
-
material_data = np.ravel(material_data)
|
|
83
|
-
self.data_texture = self.ctx.texture((1, len(material_data)), components=1, dtype='f4', data=material_data)
|
|
84
|
-
|
|
85
|
-
def write(self, regenerate=False) -> None:
|
|
86
|
-
"""
|
|
87
|
-
Writes all material data to relavent shaders
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
self.data_texture
|
|
99
|
-
|
|
100
|
-
def get(self, identifier: str | int) -> any:
|
|
101
|
-
"""
|
|
102
|
-
Gets the basilisk material with the given name or index
|
|
103
|
-
Args:
|
|
104
|
-
identifier: str | int
|
|
105
|
-
The name string or index of the desired material
|
|
106
|
-
"""
|
|
107
|
-
|
|
108
|
-
# Simply use index if given
|
|
109
|
-
if isinstance(identifier, int): return self.materials[identifier]
|
|
110
|
-
|
|
111
|
-
# Else, search the list for an image material the given name
|
|
112
|
-
for material in self.materials:
|
|
113
|
-
if material.name != identifier: continue
|
|
114
|
-
return material
|
|
115
|
-
|
|
116
|
-
# No matching material found
|
|
117
|
-
return None
|
|
118
|
-
|
|
119
|
-
def set_base(self):
|
|
120
|
-
"""
|
|
121
|
-
Creates a base material
|
|
122
|
-
"""
|
|
123
|
-
|
|
124
|
-
self.base = Material('Base')
|
|
125
|
-
self.materials.append(self.base)
|
|
126
|
-
self.generate_material_texture()
|
|
127
|
-
self.write()
|
|
128
|
-
|
|
129
|
-
def __del__(self) -> None:
|
|
130
|
-
"""
|
|
131
|
-
Releases the material data texture
|
|
132
|
-
"""
|
|
133
|
-
|
|
1
|
+
import moderngl as mgl
|
|
2
|
+
from ..render.image_handler import ImageHandler
|
|
3
|
+
from ..render.material import Material
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MaterialHandler():
|
|
8
|
+
engine: ...
|
|
9
|
+
"""Back reference to the parent engine"""
|
|
10
|
+
ctx: mgl.Context
|
|
11
|
+
"""Back reference to the parent context"""
|
|
12
|
+
materials: list[Material]
|
|
13
|
+
"""List containing all the materials in the engine"""
|
|
14
|
+
data_texture: mgl.Texture
|
|
15
|
+
"""ModernGL texture containing all the material data for materials in the engine"""
|
|
16
|
+
image_handler: ImageHandler=None
|
|
17
|
+
"""Handler for all images in the game"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, engine) -> None:
|
|
20
|
+
"""
|
|
21
|
+
Handles all the materials introduced to an engine.
|
|
22
|
+
Writes material information to the GPU
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# Back references
|
|
26
|
+
self.engine = engine
|
|
27
|
+
self.ctx = engine.ctx
|
|
28
|
+
|
|
29
|
+
# Initialize data
|
|
30
|
+
self.materials = []
|
|
31
|
+
self.data_texture = None
|
|
32
|
+
|
|
33
|
+
self.image_handler = ImageHandler(engine)
|
|
34
|
+
|
|
35
|
+
def add(self, material: Material) -> None:
|
|
36
|
+
"""
|
|
37
|
+
Adds the given material to the handler if it is not already present
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
write = False
|
|
41
|
+
|
|
42
|
+
if isinstance(material, Material): material = [material]
|
|
43
|
+
|
|
44
|
+
for mtl in material:
|
|
45
|
+
# Check that the material is not already in the scene
|
|
46
|
+
if mtl in self.materials: continue
|
|
47
|
+
# Update the material's handler
|
|
48
|
+
mtl.material_handler = self
|
|
49
|
+
# Add images
|
|
50
|
+
if mtl.texture: self.image_handler.add(mtl.texture)
|
|
51
|
+
if mtl.normal: self.image_handler.add(mtl.normal)
|
|
52
|
+
|
|
53
|
+
# Add the material
|
|
54
|
+
self.materials.append(mtl)
|
|
55
|
+
|
|
56
|
+
write = True
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# Write materials
|
|
60
|
+
if write: self.write(regenerate=True)
|
|
61
|
+
|
|
62
|
+
def generate_material_texture(self) -> None:
|
|
63
|
+
"""
|
|
64
|
+
Generates the texture that is used to write material data to the GPU
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
# Check that there are materials to write
|
|
68
|
+
if len(self.materials) == 0: return
|
|
69
|
+
|
|
70
|
+
# Release existing data texture
|
|
71
|
+
if self.data_texture: self.data_texture.release()
|
|
72
|
+
|
|
73
|
+
# Create empty texture data
|
|
74
|
+
material_data = np.zeros(shape=(len(self.materials), 28), dtype="f4")
|
|
75
|
+
|
|
76
|
+
# Get data from the materials
|
|
77
|
+
for i, mtl in enumerate(self.materials):
|
|
78
|
+
mtl.index = i
|
|
79
|
+
material_data[i] = mtl.get_data()
|
|
80
|
+
|
|
81
|
+
# Create texture from data
|
|
82
|
+
material_data = np.ravel(material_data)
|
|
83
|
+
self.data_texture = self.ctx.texture((1, len(material_data)), components=1, dtype='f4', data=material_data)
|
|
84
|
+
|
|
85
|
+
def write(self, regenerate=False) -> None:
|
|
86
|
+
"""
|
|
87
|
+
Writes all material data to relavent shaders
|
|
88
|
+
Uses bind slot 15
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
if regenerate: self.generate_material_texture()
|
|
92
|
+
|
|
93
|
+
if not self.data_texture: return
|
|
94
|
+
|
|
95
|
+
for shader in self.engine.shader_handler.shaders:
|
|
96
|
+
if 'materialsTexture' not in shader.uniforms: continue
|
|
97
|
+
|
|
98
|
+
shader.bind(self.data_texture, 'materialsTexture', 15)
|
|
99
|
+
|
|
100
|
+
def get(self, identifier: str | int) -> any:
|
|
101
|
+
"""
|
|
102
|
+
Gets the basilisk material with the given name or index
|
|
103
|
+
Args:
|
|
104
|
+
identifier: str | int
|
|
105
|
+
The name string or index of the desired material
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
# Simply use index if given
|
|
109
|
+
if isinstance(identifier, int): return self.materials[identifier]
|
|
110
|
+
|
|
111
|
+
# Else, search the list for an image material the given name
|
|
112
|
+
for material in self.materials:
|
|
113
|
+
if material.name != identifier: continue
|
|
114
|
+
return material
|
|
115
|
+
|
|
116
|
+
# No matching material found
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
def set_base(self):
|
|
120
|
+
"""
|
|
121
|
+
Creates a base material
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
self.base = Material('Base')
|
|
125
|
+
self.materials.append(self.base)
|
|
126
|
+
self.generate_material_texture()
|
|
127
|
+
self.write()
|
|
128
|
+
|
|
129
|
+
def __del__(self) -> None:
|
|
130
|
+
"""
|
|
131
|
+
Releases the material data texture
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
134
|
if self.data_texture: self.data_texture.release()
|
basilisk/render/post_process.py
CHANGED
|
@@ -1,181 +1,181 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import moderngl as mgl
|
|
3
|
-
from .shader import Shader
|
|
4
|
-
from .image import Image
|
|
5
|
-
from .framebuffer import Framebuffer
|
|
6
|
-
|
|
7
|
-
class PostProcess:
|
|
8
|
-
engine: ...
|
|
9
|
-
"""Reference to the parent engine"""
|
|
10
|
-
ctx: mgl.Context
|
|
11
|
-
"""Reference to the parent context"""
|
|
12
|
-
shader: Shader
|
|
13
|
-
"""Shader object used by the post process"""
|
|
14
|
-
vao: mgl.VertexArray
|
|
15
|
-
"""Screenspace render vao"""
|
|
16
|
-
fbo: Framebuffer=None
|
|
17
|
-
|
|
18
|
-
def __init__(self, engine, shader_path: str=None, size: tuple=None, components: int=4, filter=(mgl.LINEAR, mgl.LINEAR)) -> None:
|
|
19
|
-
"""
|
|
20
|
-
Object to apply post processing to a texture
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
# Reference attributes
|
|
24
|
-
self.engine = engine
|
|
25
|
-
self.ctx = engine.ctx
|
|
26
|
-
|
|
27
|
-
# Size of the destination
|
|
28
|
-
self.size = size if size else engine.win_size
|
|
29
|
-
self.components = components
|
|
30
|
-
|
|
31
|
-
# Load default fragment if none given
|
|
32
|
-
if not (isinstance(shader_path, str) or isinstance(shader_path, type(None))):
|
|
33
|
-
raise ValueError(f'PostProces.apply: Invalid post process source type {type(shader_path)}. Expected string path destination of fragment shader.')
|
|
34
|
-
frag = shader_path if shader_path else self.engine.root + f'/shaders/frame.frag'
|
|
35
|
-
|
|
36
|
-
# Load Shaders
|
|
37
|
-
self.shader = Shader(self.engine, self.engine.root + f'/shaders/frame.vert', frag)
|
|
38
|
-
self.engine.shader_handler.add(self.shader)
|
|
39
|
-
|
|
40
|
-
# Load VAO
|
|
41
|
-
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'))
|
|
42
|
-
self.vao = self.ctx.vertex_array(self.shader.program, [(self.vbo, '3f 2f', 'in_position', 'in_uv')], skip_errors=True)
|
|
43
|
-
|
|
44
|
-
# Temporary render destination
|
|
45
|
-
self.fbo = Framebuffer(engine, self.size, components)
|
|
46
|
-
|
|
47
|
-
# Filter settings
|
|
48
|
-
self.filter = filter
|
|
49
|
-
self.fbo.texture.filter = self.filter
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def apply(self, sources: list[tuple[str, mgl.Texture]] | list[tuple[str, Image]] | list[tuple[str, Framebuffer]], destination: mgl.Texture | Image | Framebuffer=None) -> mgl.Texture | Image | Framebuffer:
|
|
53
|
-
"""
|
|
54
|
-
Applies a post process shader to a texture source.
|
|
55
|
-
Returns the modified texture or renders to the destination if given
|
|
56
|
-
"""
|
|
57
|
-
|
|
58
|
-
# Write all the given sources to the GPU
|
|
59
|
-
self._write_sources(sources)
|
|
60
|
-
|
|
61
|
-
# Get the redner target
|
|
62
|
-
if isinstance(destination, Framebuffer) or isinstance(destination, type(self.engine.frame)): fbo = destination
|
|
63
|
-
elif isinstance(destination, mgl.Texture): fbo = self.ctx.framebuffer([destination], None)
|
|
64
|
-
elif isinstance(destination, Image): fbo = self.ctx.framebuffer([destination.texture], None)
|
|
65
|
-
|
|
66
|
-
# Apply the post process
|
|
67
|
-
fbo.use()
|
|
68
|
-
fbo.clear()
|
|
69
|
-
self.vao.render()
|
|
70
|
-
|
|
71
|
-
# Simply return the given fbo if provided
|
|
72
|
-
if isinstance(destination, Framebuffer) or isinstance(destination, type(self.engine.frame)): return destination
|
|
73
|
-
|
|
74
|
-
# Else, need to release the data and return the texture
|
|
75
|
-
texture = fbo.color_attachments[0]
|
|
76
|
-
fbo.release()
|
|
77
|
-
return texture
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def resize(self, size: tuple=None):
|
|
81
|
-
"""
|
|
82
|
-
Resize the post process
|
|
83
|
-
"""
|
|
84
|
-
|
|
85
|
-
self.size = size if size else self.engine.win_size
|
|
86
|
-
|
|
87
|
-
def _write_sources(self, sources: list[tuple[str, mgl.Texture]] | list[tuple[str, Image]] | list[tuple[str, Framebuffer]]):
|
|
88
|
-
"""
|
|
89
|
-
Writes all given source images to the GPU
|
|
90
|
-
"""
|
|
91
|
-
|
|
92
|
-
for i, source in enumerate(sources):
|
|
93
|
-
# Get the name and data
|
|
94
|
-
name, data = source
|
|
95
|
-
|
|
96
|
-
# Extract the needed data
|
|
97
|
-
if isinstance(data, mgl.Texture): texture = data
|
|
98
|
-
elif isinstance(data, Image) or isinstance(data, Framebuffer) or isinstance(data, type(self.engine.frame)): texture = data.texture
|
|
99
|
-
else: raise ValueError(f'PostProces.apply: Invalid postprocess source type {type(source)}')
|
|
100
|
-
|
|
101
|
-
# Write the texture
|
|
102
|
-
self.shader.program[name] = i
|
|
103
|
-
texture.use(location=i)
|
|
104
|
-
|
|
105
|
-
def _render_post_process(self, source: mgl.Texture):
|
|
106
|
-
# Clear and use the fbo as a render target
|
|
107
|
-
self.fbo.use()
|
|
108
|
-
self.fbo.clear()
|
|
109
|
-
|
|
110
|
-
# Load the source texture to the shader
|
|
111
|
-
for i, src in enumerate(source):
|
|
112
|
-
self.shader.program[src[0]] = i
|
|
113
|
-
src[1].use(location=i)
|
|
114
|
-
|
|
115
|
-
# Apply the post process
|
|
116
|
-
self.vao.render()
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
def _apply_to_framebuffer(self, source: Framebuffer, detination: Framebuffer=None) -> Framebuffer:
|
|
120
|
-
"""
|
|
121
|
-
Applies a post process to a bsk.Framebuffer
|
|
122
|
-
"""
|
|
123
|
-
|
|
124
|
-
# Create a blank framebuffer
|
|
125
|
-
if not detination or detination.size != self.size:
|
|
126
|
-
fbo = Framebuffer(self.engine, self.size, self.components)
|
|
127
|
-
old_filter = None
|
|
128
|
-
fbo.texture.filter = self.filter
|
|
129
|
-
else:
|
|
130
|
-
fbo = detination
|
|
131
|
-
old_filter = fbo.texture_filter
|
|
132
|
-
fbo.texture.filter = self.filter
|
|
133
|
-
|
|
134
|
-
# Load the source texture to the shader
|
|
135
|
-
for i, src in enumerate(source):
|
|
136
|
-
self.shader.program[src[0]] = i
|
|
137
|
-
src[1].texture.use(location=i)
|
|
138
|
-
|
|
139
|
-
fbo.use()
|
|
140
|
-
fbo.clear()
|
|
141
|
-
# Apply the post process
|
|
142
|
-
self.vao.render()
|
|
143
|
-
|
|
144
|
-
# Reset filter if needed
|
|
145
|
-
if old_filter: fbo.texture.filter = old_filter
|
|
146
|
-
|
|
147
|
-
# Return the fbo for the user
|
|
148
|
-
return fbo
|
|
149
|
-
|
|
150
|
-
def _apply_to_texture(self, source: mgl.Texture, destination: mgl.Texture) -> mgl.Texture:
|
|
151
|
-
"""
|
|
152
|
-
Applies a post process to a mgl.Texture
|
|
153
|
-
"""
|
|
154
|
-
|
|
155
|
-
# Render the post processs with the given texture
|
|
156
|
-
self._render_post_process(source)
|
|
157
|
-
|
|
158
|
-
# Make a deep copy of the modified texture
|
|
159
|
-
texture = self.ctx.texture(self.fbo.size, self.fbo.components, self.fbo.data)
|
|
160
|
-
|
|
161
|
-
return texture
|
|
162
|
-
|
|
163
|
-
def _apply_to_image(self, source: Image, destination: Image) -> Image:
|
|
164
|
-
"""
|
|
165
|
-
Applies a post process to a bsk.Image
|
|
166
|
-
"""
|
|
167
|
-
|
|
168
|
-
# Create a texture from the image data
|
|
169
|
-
texture = self.ctx.texture(self.fbo.size, self.fbo.components, source.data)
|
|
170
|
-
|
|
171
|
-
# Render the post processs with the given texture
|
|
172
|
-
self._render_post_process(source)
|
|
173
|
-
|
|
174
|
-
# Make an image from the texture
|
|
175
|
-
image = Image()
|
|
176
|
-
return image
|
|
177
|
-
|
|
178
|
-
def __del__(self):
|
|
179
|
-
if self.vao: self.vao.release()
|
|
180
|
-
if self.vbo: self.vbo.release()
|
|
1
|
+
import numpy as np
|
|
2
|
+
import moderngl as mgl
|
|
3
|
+
from .shader import Shader
|
|
4
|
+
from .image import Image
|
|
5
|
+
from .framebuffer import Framebuffer
|
|
6
|
+
|
|
7
|
+
class PostProcess:
|
|
8
|
+
engine: ...
|
|
9
|
+
"""Reference to the parent engine"""
|
|
10
|
+
ctx: mgl.Context
|
|
11
|
+
"""Reference to the parent context"""
|
|
12
|
+
shader: Shader
|
|
13
|
+
"""Shader object used by the post process"""
|
|
14
|
+
vao: mgl.VertexArray
|
|
15
|
+
"""Screenspace render vao"""
|
|
16
|
+
fbo: Framebuffer=None
|
|
17
|
+
|
|
18
|
+
def __init__(self, engine, shader_path: str=None, size: tuple=None, components: int=4, filter=(mgl.LINEAR, mgl.LINEAR)) -> None:
|
|
19
|
+
"""
|
|
20
|
+
Object to apply post processing to a texture
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
# Reference attributes
|
|
24
|
+
self.engine = engine
|
|
25
|
+
self.ctx = engine.ctx
|
|
26
|
+
|
|
27
|
+
# Size of the destination
|
|
28
|
+
self.size = size if size else engine.win_size
|
|
29
|
+
self.components = components
|
|
30
|
+
|
|
31
|
+
# Load default fragment if none given
|
|
32
|
+
if not (isinstance(shader_path, str) or isinstance(shader_path, type(None))):
|
|
33
|
+
raise ValueError(f'PostProces.apply: Invalid post process source type {type(shader_path)}. Expected string path destination of fragment shader.')
|
|
34
|
+
frag = shader_path if shader_path else self.engine.root + f'/shaders/frame.frag'
|
|
35
|
+
|
|
36
|
+
# Load Shaders
|
|
37
|
+
self.shader = Shader(self.engine, self.engine.root + f'/shaders/frame.vert', frag)
|
|
38
|
+
self.engine.shader_handler.add(self.shader)
|
|
39
|
+
|
|
40
|
+
# Load VAO
|
|
41
|
+
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'))
|
|
42
|
+
self.vao = self.ctx.vertex_array(self.shader.program, [(self.vbo, '3f 2f', 'in_position', 'in_uv')], skip_errors=True)
|
|
43
|
+
|
|
44
|
+
# Temporary render destination
|
|
45
|
+
self.fbo = Framebuffer(engine, self.size, components)
|
|
46
|
+
|
|
47
|
+
# Filter settings
|
|
48
|
+
self.filter = filter
|
|
49
|
+
self.fbo.texture.filter = self.filter
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def apply(self, sources: list[tuple[str, mgl.Texture]] | list[tuple[str, Image]] | list[tuple[str, Framebuffer]], destination: mgl.Texture | Image | Framebuffer=None) -> mgl.Texture | Image | Framebuffer:
|
|
53
|
+
"""
|
|
54
|
+
Applies a post process shader to a texture source.
|
|
55
|
+
Returns the modified texture or renders to the destination if given
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
# Write all the given sources to the GPU
|
|
59
|
+
self._write_sources(sources)
|
|
60
|
+
|
|
61
|
+
# Get the redner target
|
|
62
|
+
if isinstance(destination, Framebuffer) or isinstance(destination, type(self.engine.frame)): fbo = destination
|
|
63
|
+
elif isinstance(destination, mgl.Texture): fbo = self.ctx.framebuffer([destination], None)
|
|
64
|
+
elif isinstance(destination, Image): fbo = self.ctx.framebuffer([destination.texture], None)
|
|
65
|
+
|
|
66
|
+
# Apply the post process
|
|
67
|
+
fbo.use()
|
|
68
|
+
fbo.clear()
|
|
69
|
+
self.vao.render()
|
|
70
|
+
|
|
71
|
+
# Simply return the given fbo if provided
|
|
72
|
+
if isinstance(destination, Framebuffer) or isinstance(destination, type(self.engine.frame)): return destination
|
|
73
|
+
|
|
74
|
+
# Else, need to release the data and return the texture
|
|
75
|
+
texture = fbo.color_attachments[0]
|
|
76
|
+
fbo.release()
|
|
77
|
+
return texture
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def resize(self, size: tuple=None):
|
|
81
|
+
"""
|
|
82
|
+
Resize the post process
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
self.size = size if size else self.engine.win_size
|
|
86
|
+
|
|
87
|
+
def _write_sources(self, sources: list[tuple[str, mgl.Texture]] | list[tuple[str, Image]] | list[tuple[str, Framebuffer]]):
|
|
88
|
+
"""
|
|
89
|
+
Writes all given source images to the GPU
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
for i, source in enumerate(sources):
|
|
93
|
+
# Get the name and data
|
|
94
|
+
name, data = source
|
|
95
|
+
|
|
96
|
+
# Extract the needed data
|
|
97
|
+
if isinstance(data, mgl.Texture): texture = data
|
|
98
|
+
elif isinstance(data, Image) or isinstance(data, Framebuffer) or isinstance(data, type(self.engine.frame)): texture = data.texture
|
|
99
|
+
else: raise ValueError(f'PostProces.apply: Invalid postprocess source type {type(source)}')
|
|
100
|
+
|
|
101
|
+
# Write the texture
|
|
102
|
+
self.shader.program[name] = i
|
|
103
|
+
texture.use(location=i)
|
|
104
|
+
|
|
105
|
+
def _render_post_process(self, source: mgl.Texture):
|
|
106
|
+
# Clear and use the fbo as a render target
|
|
107
|
+
self.fbo.use()
|
|
108
|
+
self.fbo.clear()
|
|
109
|
+
|
|
110
|
+
# Load the source texture to the shader
|
|
111
|
+
for i, src in enumerate(source):
|
|
112
|
+
self.shader.program[src[0]] = i
|
|
113
|
+
src[1].use(location=i)
|
|
114
|
+
|
|
115
|
+
# Apply the post process
|
|
116
|
+
self.vao.render()
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _apply_to_framebuffer(self, source: Framebuffer, detination: Framebuffer=None) -> Framebuffer:
|
|
120
|
+
"""
|
|
121
|
+
Applies a post process to a bsk.Framebuffer
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
# Create a blank framebuffer
|
|
125
|
+
if not detination or detination.size != self.size:
|
|
126
|
+
fbo = Framebuffer(self.engine, self.size, self.components)
|
|
127
|
+
old_filter = None
|
|
128
|
+
fbo.texture.filter = self.filter
|
|
129
|
+
else:
|
|
130
|
+
fbo = detination
|
|
131
|
+
old_filter = fbo.texture_filter
|
|
132
|
+
fbo.texture.filter = self.filter
|
|
133
|
+
|
|
134
|
+
# Load the source texture to the shader
|
|
135
|
+
for i, src in enumerate(source):
|
|
136
|
+
self.shader.program[src[0]] = i
|
|
137
|
+
src[1].texture.use(location=i)
|
|
138
|
+
|
|
139
|
+
fbo.use()
|
|
140
|
+
fbo.clear()
|
|
141
|
+
# Apply the post process
|
|
142
|
+
self.vao.render()
|
|
143
|
+
|
|
144
|
+
# Reset filter if needed
|
|
145
|
+
if old_filter: fbo.texture.filter = old_filter
|
|
146
|
+
|
|
147
|
+
# Return the fbo for the user
|
|
148
|
+
return fbo
|
|
149
|
+
|
|
150
|
+
def _apply_to_texture(self, source: mgl.Texture, destination: mgl.Texture) -> mgl.Texture:
|
|
151
|
+
"""
|
|
152
|
+
Applies a post process to a mgl.Texture
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
# Render the post processs with the given texture
|
|
156
|
+
self._render_post_process(source)
|
|
157
|
+
|
|
158
|
+
# Make a deep copy of the modified texture
|
|
159
|
+
texture = self.ctx.texture(self.fbo.size, self.fbo.components, self.fbo.data)
|
|
160
|
+
|
|
161
|
+
return texture
|
|
162
|
+
|
|
163
|
+
def _apply_to_image(self, source: Image, destination: Image) -> Image:
|
|
164
|
+
"""
|
|
165
|
+
Applies a post process to a bsk.Image
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
# Create a texture from the image data
|
|
169
|
+
texture = self.ctx.texture(self.fbo.size, self.fbo.components, source.data)
|
|
170
|
+
|
|
171
|
+
# Render the post processs with the given texture
|
|
172
|
+
self._render_post_process(source)
|
|
173
|
+
|
|
174
|
+
# Make an image from the texture
|
|
175
|
+
image = Image()
|
|
176
|
+
return image
|
|
177
|
+
|
|
178
|
+
def __del__(self):
|
|
179
|
+
if self.vao: self.vao.release()
|
|
180
|
+
if self.vbo: self.vbo.release()
|
|
181
181
|
if self.fbo: self.fbo.__del__()
|