ncca-ngl 0.3.5__py3-none-any.whl → 0.5.1__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.
- ncca/ngl/PrimData/pack_arrays.py +2 -3
- ncca/ngl/__init__.py +5 -5
- ncca/ngl/base_mesh.py +28 -20
- ncca/ngl/image.py +1 -3
- ncca/ngl/mat2.py +79 -53
- ncca/ngl/mat3.py +104 -185
- ncca/ngl/mat4.py +144 -309
- ncca/ngl/prim_data.py +42 -36
- ncca/ngl/primitives.py +2 -2
- ncca/ngl/pyside_event_handling_mixin.py +0 -108
- ncca/ngl/quaternion.py +69 -36
- ncca/ngl/shader.py +0 -116
- ncca/ngl/shader_program.py +94 -117
- ncca/ngl/texture.py +5 -2
- ncca/ngl/util.py +50 -0
- ncca/ngl/vec2.py +59 -302
- ncca/ngl/vec2_array.py +79 -28
- ncca/ngl/vec3.py +60 -350
- ncca/ngl/vec3_array.py +76 -23
- ncca/ngl/vec4.py +90 -200
- ncca/ngl/vec4_array.py +78 -27
- ncca/ngl/vector_base.py +548 -0
- ncca/ngl/webgpu/__init__.py +20 -0
- ncca/ngl/webgpu/__main__.py +640 -0
- ncca/ngl/webgpu/__main__.py.backup +640 -0
- ncca/ngl/webgpu/base_webgpu_pipeline.py +354 -0
- ncca/ngl/webgpu/custom_shader_pipeline.py +288 -0
- ncca/ngl/webgpu/instanced_geometry_pipeline.py +594 -0
- ncca/ngl/webgpu/line_pipeline.py +405 -0
- ncca/ngl/webgpu/pipeline_factory.py +190 -0
- ncca/ngl/webgpu/pipeline_shaders.py +497 -0
- ncca/ngl/webgpu/point_list_pipeline.py +349 -0
- ncca/ngl/webgpu/point_pipeline.py +336 -0
- ncca/ngl/webgpu/triangle_pipeline.py +419 -0
- ncca/ngl/webgpu/webgpu_constants.py +33 -0
- ncca/ngl/webgpu/webgpu_widget.py +322 -0
- ncca/ngl/webgpu/wip/REFACTORING_SUMMARY.md +82 -0
- ncca/ngl/webgpu/wip/UNIFIED_SYSTEM.md +314 -0
- ncca/ngl/webgpu/wip/buffer_manager.py +396 -0
- ncca/ngl/webgpu/wip/pipeline_config.py +463 -0
- ncca/ngl/webgpu/wip/shader_constants.py +328 -0
- ncca/ngl/webgpu/wip/shader_templates.py +563 -0
- ncca/ngl/webgpu/wip/unified_examples.py +390 -0
- ncca/ngl/webgpu/wip/unified_factory.py +449 -0
- ncca/ngl/webgpu/wip/unified_pipeline.py +469 -0
- ncca/ngl/widgets/__init__.py +18 -2
- ncca/ngl/widgets/__main__.py +2 -1
- ncca/ngl/widgets/lookatwidget.py +2 -1
- ncca/ngl/widgets/mat4widget.py +2 -2
- ncca/ngl/widgets/vec2widget.py +1 -1
- ncca/ngl/widgets/vec3widget.py +1 -0
- {ncca_ngl-0.3.5.dist-info → ncca_ngl-0.5.1.dist-info}/METADATA +3 -2
- ncca_ngl-0.5.1.dist-info/RECORD +105 -0
- ncca/ngl/widgets/transformation_widget.py +0 -299
- ncca_ngl-0.3.5.dist-info/RECORD +0 -82
- {ncca_ngl-0.3.5.dist-info → ncca_ngl-0.5.1.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generic line rendering pipeline for WebGPU.
|
|
3
|
+
Handles line rendering with customizable color and projection.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Optional, Tuple
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import wgpu
|
|
10
|
+
|
|
11
|
+
from .base_webgpu_pipeline import BaseWebGPUPipeline
|
|
12
|
+
from .pipeline_shaders import LINE_SHADER_MULTI_COLOURED, LINE_SHADER_SINGLE_COLOUR
|
|
13
|
+
from .webgpu_constants import NGLToWebGPU
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BaseLinePipeline(BaseWebGPUPipeline):
|
|
17
|
+
"""Base class for line rendering pipelines."""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
device: wgpu.GPUDevice,
|
|
22
|
+
data_type: str = "Vec3",
|
|
23
|
+
texture_format: wgpu.TextureFormat = wgpu.TextureFormat.rgba8unorm,
|
|
24
|
+
depth_format: wgpu.TextureFormat = wgpu.TextureFormat.depth24plus,
|
|
25
|
+
msaa_sample_count: int = 4,
|
|
26
|
+
stride: int = 0,
|
|
27
|
+
topology: wgpu.PrimitiveTopology = wgpu.PrimitiveTopology.line_list,
|
|
28
|
+
):
|
|
29
|
+
"""
|
|
30
|
+
Initialize the base line pipeline.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
device: WebGPU device
|
|
34
|
+
texture_format: Color attachment format
|
|
35
|
+
depth_format: Depth attachment format
|
|
36
|
+
msaa_sample_count: Number of MSAA samples
|
|
37
|
+
stride: The stride of the vertex buffer. If 0, it is inferred from data_type.
|
|
38
|
+
topology: Primitive topology (line_list or line_strip)
|
|
39
|
+
"""
|
|
40
|
+
self._topology = topology
|
|
41
|
+
super().__init__(
|
|
42
|
+
device=device,
|
|
43
|
+
texture_format=texture_format,
|
|
44
|
+
depth_format=depth_format,
|
|
45
|
+
msaa_sample_count=msaa_sample_count,
|
|
46
|
+
data_type=data_type,
|
|
47
|
+
stride=stride,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
def _get_primitive_topology(self) -> wgpu.PrimitiveTopology:
|
|
51
|
+
"""Line pipelines use configurable topology."""
|
|
52
|
+
return self._topology
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class LinePipelineMultiColour(BaseLinePipeline):
|
|
56
|
+
"""
|
|
57
|
+
A reusable pipeline for rendering lines in WebGPU with per-vertex colors.
|
|
58
|
+
|
|
59
|
+
Features:
|
|
60
|
+
- Line strips or line segments
|
|
61
|
+
- Per-vertex colors
|
|
62
|
+
- MVP matrix support
|
|
63
|
+
- MSAA support
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def __init__(
|
|
67
|
+
self,
|
|
68
|
+
device: wgpu.GPUDevice,
|
|
69
|
+
data_type: str = "Vec3",
|
|
70
|
+
texture_format: wgpu.TextureFormat = wgpu.TextureFormat.rgba8unorm,
|
|
71
|
+
depth_format: wgpu.TextureFormat = wgpu.TextureFormat.depth24plus,
|
|
72
|
+
msaa_sample_count: int = 4,
|
|
73
|
+
stride: int = 0,
|
|
74
|
+
topology: wgpu.PrimitiveTopology = wgpu.PrimitiveTopology.line_list,
|
|
75
|
+
):
|
|
76
|
+
"""
|
|
77
|
+
Initialize the line rendering pipeline.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
device: WebGPU device
|
|
81
|
+
texture_format: Color attachment format
|
|
82
|
+
depth_format: Depth attachment format
|
|
83
|
+
msaa_sample_count: Number of MSAA samples
|
|
84
|
+
stride: The stride of the vertex buffer. If 0, it is inferred from data_type.
|
|
85
|
+
topology: Primitive topology (line_list or line_strip)
|
|
86
|
+
"""
|
|
87
|
+
# Pipeline-specific buffer tracking
|
|
88
|
+
self.vertex_buffer: Optional[wgpu.GPUBuffer] = None
|
|
89
|
+
self.color_buffer: Optional[wgpu.GPUBuffer] = None
|
|
90
|
+
self.num_vertices: int = 0
|
|
91
|
+
|
|
92
|
+
super().__init__(
|
|
93
|
+
device=device,
|
|
94
|
+
texture_format=texture_format,
|
|
95
|
+
depth_format=depth_format,
|
|
96
|
+
msaa_sample_count=msaa_sample_count,
|
|
97
|
+
data_type=data_type,
|
|
98
|
+
stride=stride,
|
|
99
|
+
topology=topology,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def get_dtype(self) -> np.dtype:
|
|
103
|
+
"""Get the data type of the pipeline."""
|
|
104
|
+
return np.dtype(
|
|
105
|
+
[
|
|
106
|
+
("MVP", "float32", (4, 4)),
|
|
107
|
+
]
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def _get_shader_code(self) -> str:
|
|
111
|
+
"""Get the WGSL shader code for this pipeline."""
|
|
112
|
+
return LINE_SHADER_MULTI_COLOURED
|
|
113
|
+
|
|
114
|
+
def _get_vertex_buffer_layouts(self):
|
|
115
|
+
"""Get vertex buffer layout configurations for the pipeline."""
|
|
116
|
+
return [
|
|
117
|
+
{
|
|
118
|
+
"array_stride": self._stride,
|
|
119
|
+
"step_mode": wgpu.VertexStepMode.vertex,
|
|
120
|
+
"attributes": [
|
|
121
|
+
{
|
|
122
|
+
"format": NGLToWebGPU.vertex_format(self._data_type),
|
|
123
|
+
"offset": 0,
|
|
124
|
+
"shader_location": 0,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"array_stride": NGLToWebGPU.stride_from_type("Vec3"),
|
|
130
|
+
"step_mode": wgpu.VertexStepMode.vertex,
|
|
131
|
+
"attributes": [
|
|
132
|
+
{
|
|
133
|
+
"format": NGLToWebGPU.vertex_format("Vec3"),
|
|
134
|
+
"offset": 0,
|
|
135
|
+
"shader_location": 1,
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
def _set_default_uniforms(self) -> None:
|
|
142
|
+
"""Set default values for uniform data."""
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
def _get_pipeline_label(self) -> str:
|
|
146
|
+
"""Get the label for the pipeline."""
|
|
147
|
+
return "line_pipeline_multi_coloured"
|
|
148
|
+
|
|
149
|
+
def set_data(self, positions=None, colors=None, **kwargs) -> None:
|
|
150
|
+
"""
|
|
151
|
+
Set the line data for rendering.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
positions: Nx2/Nx3 array of line positions or a pre-existing GPUBuffer.
|
|
155
|
+
colors: Nx3 array of line colors (RGB) or a pre-existing GPUBuffer.
|
|
156
|
+
"""
|
|
157
|
+
if positions is not None:
|
|
158
|
+
if isinstance(positions, wgpu.GPUBuffer):
|
|
159
|
+
self.vertex_buffer = positions
|
|
160
|
+
self.num_vertices = positions.size // self._stride
|
|
161
|
+
else: # numpy array
|
|
162
|
+
self.vertex_buffer, buffer_size = self._create_or_update_buffer(
|
|
163
|
+
self.vertex_buffer,
|
|
164
|
+
positions,
|
|
165
|
+
wgpu.BufferUsage.VERTEX | wgpu.BufferUsage.COPY_DST,
|
|
166
|
+
"line_pipeline_multi_coloured_position_buffer",
|
|
167
|
+
)
|
|
168
|
+
self.num_vertices = buffer_size // self._stride
|
|
169
|
+
|
|
170
|
+
if colors is not None:
|
|
171
|
+
if isinstance(colors, wgpu.GPUBuffer):
|
|
172
|
+
self.color_buffer = colors
|
|
173
|
+
else:
|
|
174
|
+
color_result = self._process_vertex_data(
|
|
175
|
+
colors,
|
|
176
|
+
None,
|
|
177
|
+
padding_size=4, # Pad to vec4 for alignment
|
|
178
|
+
buffer_label="line_pipeline_multi_coloured_colour_buffer",
|
|
179
|
+
)
|
|
180
|
+
if isinstance(color_result, wgpu.GPUBuffer):
|
|
181
|
+
self.color_buffer = color_result
|
|
182
|
+
elif color_result:
|
|
183
|
+
self.color_buffer = color_result[0]
|
|
184
|
+
else:
|
|
185
|
+
self.color_buffer = None
|
|
186
|
+
|
|
187
|
+
def update_uniforms(self, **kwargs) -> None:
|
|
188
|
+
"""
|
|
189
|
+
Update uniform buffer values.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
**kwargs: Pipeline-specific uniform parameters
|
|
193
|
+
- mvp: 4x4 projection matrix
|
|
194
|
+
"""
|
|
195
|
+
if "mvp" in kwargs and kwargs["mvp"] is not None:
|
|
196
|
+
self.uniform_data["MVP"] = kwargs["mvp"]
|
|
197
|
+
|
|
198
|
+
self.device.queue.write_buffer(
|
|
199
|
+
self.uniform_buffer, 0, self.uniform_data.tobytes()
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
def render(self, render_pass: wgpu.GPURenderPassEncoder, **kwargs) -> None:
|
|
203
|
+
"""
|
|
204
|
+
Render the lines.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
render_pass: Active render pass encoder
|
|
208
|
+
**kwargs: Pipeline-specific render parameters
|
|
209
|
+
- num_vertices: Number of vertices to render (defaults to all)
|
|
210
|
+
"""
|
|
211
|
+
num_vertices = kwargs.get("num_vertices", None)
|
|
212
|
+
|
|
213
|
+
if self.vertex_buffer is None or self.color_buffer is None:
|
|
214
|
+
return
|
|
215
|
+
|
|
216
|
+
count = num_vertices if num_vertices is not None else self.num_vertices
|
|
217
|
+
|
|
218
|
+
render_pass.set_pipeline(self.pipeline)
|
|
219
|
+
if self.bind_group:
|
|
220
|
+
render_pass.set_bind_group(0, self.bind_group, [], 0, 999999)
|
|
221
|
+
render_pass.set_vertex_buffer(0, self.vertex_buffer)
|
|
222
|
+
render_pass.set_vertex_buffer(1, self.color_buffer)
|
|
223
|
+
render_pass.draw(count)
|
|
224
|
+
|
|
225
|
+
def cleanup(self) -> None:
|
|
226
|
+
"""Release resources."""
|
|
227
|
+
if self.vertex_buffer:
|
|
228
|
+
self.vertex_buffer.destroy()
|
|
229
|
+
if self.color_buffer:
|
|
230
|
+
self.color_buffer.destroy()
|
|
231
|
+
super().cleanup()
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class LinePipelineSingleColour(BaseLinePipeline):
|
|
235
|
+
"""
|
|
236
|
+
A reusable pipeline for rendering lines in WebGPU with single color.
|
|
237
|
+
|
|
238
|
+
Features:
|
|
239
|
+
- Line strips or line segments
|
|
240
|
+
- Single color for all lines
|
|
241
|
+
- MVP matrix support
|
|
242
|
+
- MSAA support
|
|
243
|
+
"""
|
|
244
|
+
|
|
245
|
+
def __init__(
|
|
246
|
+
self,
|
|
247
|
+
device: wgpu.GPUDevice,
|
|
248
|
+
data_type: str = "Vec3",
|
|
249
|
+
texture_format: wgpu.TextureFormat = wgpu.TextureFormat.rgba8unorm,
|
|
250
|
+
depth_format: wgpu.TextureFormat = wgpu.TextureFormat.depth24plus,
|
|
251
|
+
msaa_sample_count: int = 4,
|
|
252
|
+
stride: int = 0,
|
|
253
|
+
topology: wgpu.PrimitiveTopology = wgpu.PrimitiveTopology.line_list,
|
|
254
|
+
colour: Tuple[float, float, float] = (1.0, 1.0, 1.0),
|
|
255
|
+
):
|
|
256
|
+
"""
|
|
257
|
+
Initialize line rendering pipeline.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
device: WebGPU device
|
|
261
|
+
texture_format: Color attachment format
|
|
262
|
+
depth_format: Depth attachment format
|
|
263
|
+
msaa_sample_count: Number of MSAA samples
|
|
264
|
+
stride: The stride of the vertex buffer. If 0, it is inferred from data_type.
|
|
265
|
+
topology: Primitive topology (line_list or line_strip)
|
|
266
|
+
colour: RGB color tuple for lines (default white)
|
|
267
|
+
"""
|
|
268
|
+
# Pipeline-specific buffer tracking
|
|
269
|
+
self.vertex_buffer: Optional[wgpu.GPUBuffer] = None
|
|
270
|
+
self.num_vertices: int = 0
|
|
271
|
+
self._colour = np.array(colour, dtype=np.float32)
|
|
272
|
+
|
|
273
|
+
super().__init__(
|
|
274
|
+
device=device,
|
|
275
|
+
texture_format=texture_format,
|
|
276
|
+
depth_format=depth_format,
|
|
277
|
+
msaa_sample_count=msaa_sample_count,
|
|
278
|
+
data_type=data_type,
|
|
279
|
+
stride=stride,
|
|
280
|
+
topology=topology,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
def get_dtype(self) -> np.dtype:
|
|
284
|
+
"""Get the data type of the pipeline."""
|
|
285
|
+
return np.dtype(
|
|
286
|
+
[
|
|
287
|
+
("MVP", "float32", (4, 4)),
|
|
288
|
+
("Colour", "float32", 3),
|
|
289
|
+
("padding", "float32", 1),
|
|
290
|
+
]
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
def _get_shader_code(self) -> str:
|
|
294
|
+
"""Get the WGSL shader code for this pipeline."""
|
|
295
|
+
return LINE_SHADER_SINGLE_COLOUR
|
|
296
|
+
|
|
297
|
+
def _get_vertex_buffer_layouts(self):
|
|
298
|
+
"""Get vertex buffer layout configurations for the pipeline."""
|
|
299
|
+
return [
|
|
300
|
+
{
|
|
301
|
+
"array_stride": self._stride,
|
|
302
|
+
"step_mode": wgpu.VertexStepMode.vertex,
|
|
303
|
+
"attributes": [
|
|
304
|
+
{
|
|
305
|
+
"format": NGLToWebGPU.vertex_format(self._data_type),
|
|
306
|
+
"offset": 0,
|
|
307
|
+
"shader_location": 0,
|
|
308
|
+
},
|
|
309
|
+
],
|
|
310
|
+
},
|
|
311
|
+
]
|
|
312
|
+
|
|
313
|
+
def _set_default_uniforms(self) -> None:
|
|
314
|
+
"""Set default values for uniform data."""
|
|
315
|
+
pass
|
|
316
|
+
|
|
317
|
+
def _get_pipeline_label(self) -> str:
|
|
318
|
+
"""Get the label for the pipeline."""
|
|
319
|
+
return "line_pipeline_single_colour"
|
|
320
|
+
|
|
321
|
+
def set_data(self, positions=None, colors=None, **kwargs) -> None:
|
|
322
|
+
"""
|
|
323
|
+
Set the line data for rendering.
|
|
324
|
+
|
|
325
|
+
Args:
|
|
326
|
+
positions: Nx2/Nx3 array of line positions or a pre-existing GPUBuffer.
|
|
327
|
+
colors: Ignored for single colour pipeline
|
|
328
|
+
"""
|
|
329
|
+
if positions is not None:
|
|
330
|
+
if isinstance(positions, wgpu.GPUBuffer):
|
|
331
|
+
self.vertex_buffer = positions
|
|
332
|
+
self.num_vertices = positions.size // self._stride
|
|
333
|
+
else: # numpy array
|
|
334
|
+
self.vertex_buffer, buffer_size = self._create_or_update_buffer(
|
|
335
|
+
self.vertex_buffer,
|
|
336
|
+
positions,
|
|
337
|
+
wgpu.BufferUsage.VERTEX | wgpu.BufferUsage.COPY_DST,
|
|
338
|
+
"line_pipeline_single_colour_position_buffer",
|
|
339
|
+
)
|
|
340
|
+
self.num_vertices = buffer_size // self._stride
|
|
341
|
+
|
|
342
|
+
def update_uniforms(self, **kwargs) -> None:
|
|
343
|
+
"""
|
|
344
|
+
Update uniform buffer values.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
**kwargs: Pipeline-specific uniform parameters
|
|
348
|
+
- mvp: 4x4 projection matrix
|
|
349
|
+
- colour: RGB color tuple
|
|
350
|
+
"""
|
|
351
|
+
if "mvp" in kwargs and kwargs["mvp"] is not None:
|
|
352
|
+
self.uniform_data["MVP"] = kwargs["mvp"]
|
|
353
|
+
|
|
354
|
+
if "colour" in kwargs and kwargs["colour"] is not None:
|
|
355
|
+
colour = np.array(kwargs["colour"], dtype=np.float32)
|
|
356
|
+
if colour.shape == (3,):
|
|
357
|
+
self.uniform_data["Colour"] = colour
|
|
358
|
+
self._colour = colour
|
|
359
|
+
|
|
360
|
+
self.device.queue.write_buffer(
|
|
361
|
+
self.uniform_buffer, 0, self.uniform_data.tobytes()
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
def set_color(self, colour: Tuple[float, float, float]) -> None:
|
|
365
|
+
"""
|
|
366
|
+
Set the color for the lines.
|
|
367
|
+
|
|
368
|
+
Args:
|
|
369
|
+
colour: RGB color tuple
|
|
370
|
+
"""
|
|
371
|
+
colour_array = np.array(colour, dtype=np.float32)
|
|
372
|
+
if colour_array.shape == (3,):
|
|
373
|
+
self.uniform_data["Colour"] = colour_array
|
|
374
|
+
self._colour = colour_array
|
|
375
|
+
self.device.queue.write_buffer(
|
|
376
|
+
self.uniform_buffer, 0, self.uniform_data.tobytes()
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
def render(self, render_pass: wgpu.GPURenderPassEncoder, **kwargs) -> None:
|
|
380
|
+
"""
|
|
381
|
+
Render the lines.
|
|
382
|
+
|
|
383
|
+
Args:
|
|
384
|
+
render_pass: Active render pass encoder
|
|
385
|
+
**kwargs: Pipeline-specific render parameters
|
|
386
|
+
- num_vertices: Number of vertices to render (defaults to all)
|
|
387
|
+
"""
|
|
388
|
+
num_vertices = kwargs.get("num_vertices", None)
|
|
389
|
+
|
|
390
|
+
if self.vertex_buffer is None:
|
|
391
|
+
return
|
|
392
|
+
|
|
393
|
+
count = num_vertices if num_vertices is not None else self.num_vertices
|
|
394
|
+
|
|
395
|
+
render_pass.set_pipeline(self.pipeline)
|
|
396
|
+
if self.bind_group:
|
|
397
|
+
render_pass.set_bind_group(0, self.bind_group, [], 0, 999999)
|
|
398
|
+
render_pass.set_vertex_buffer(0, self.vertex_buffer)
|
|
399
|
+
render_pass.draw(count)
|
|
400
|
+
|
|
401
|
+
def cleanup(self) -> None:
|
|
402
|
+
"""Release resources."""
|
|
403
|
+
if self.vertex_buffer:
|
|
404
|
+
self.vertex_buffer.destroy()
|
|
405
|
+
super().cleanup()
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Extensible factory for WebGPU pipelines It will create several default pipelines used in demos
|
|
3
|
+
and allow the user to create custom pipelines.
|
|
4
|
+
Provides abstract base class and factory for creating various pipeline types.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import Any, Dict, Optional, Type
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
import wgpu
|
|
12
|
+
|
|
13
|
+
from .base_webgpu_pipeline import BaseWebGPUPipeline
|
|
14
|
+
from .point_pipeline import PointPipelineMultiColour, PointPipelineSingleColour
|
|
15
|
+
from .point_list_pipeline import (
|
|
16
|
+
PointListPipelineMultiColour,
|
|
17
|
+
PointListPipelineSingleColour,
|
|
18
|
+
)
|
|
19
|
+
from .point_list_pipeline import (
|
|
20
|
+
PointListPipelineMultiColour,
|
|
21
|
+
PointListPipelineSingleColour,
|
|
22
|
+
)
|
|
23
|
+
from .line_pipeline import LinePipelineMultiColour, LinePipelineSingleColour
|
|
24
|
+
from .triangle_pipeline import TrianglePipelineMultiColour, TrianglePipelineSingleColour
|
|
25
|
+
from .instanced_geometry_pipeline import (
|
|
26
|
+
InstancedGeometryPipelineMultiColour,
|
|
27
|
+
InstancedGeometryPipelineSingleColour,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class PipelineType(Enum):
|
|
32
|
+
"""Enumeration of available pipeline types."""
|
|
33
|
+
|
|
34
|
+
MULTI_COLOURED_LINES = "multi_coloured_lines"
|
|
35
|
+
SINGLE_COLOUR_LINES = "single_colour_lines"
|
|
36
|
+
MULTI_COLOURED_POINTS = "multi_coloured_points"
|
|
37
|
+
SINGLE_COLOUR_POINTS = "single_colour_points"
|
|
38
|
+
MULTI_COLOURED_TRIANGLES = "multi_coloured_triangles"
|
|
39
|
+
SINGLE_COLOUR_TRIANGLES = "single_colour_triangles"
|
|
40
|
+
TRIANGLE_LIST_MULTI_COLOURED = "triangle_list_multi_coloured"
|
|
41
|
+
TRIANGLE_LIST_SINGLE_COLOUR = "triangle_list_single_colour"
|
|
42
|
+
TRIANGLE_STRIP_MULTI_COLOURED = "triangle_strip_multi_coloured"
|
|
43
|
+
TRIANGLE_STRIP_SINGLE_COLOUR = "triangle_strip_single_colour"
|
|
44
|
+
POINT_LIST_MULTI_COLOURED = "point_list_multi_coloured"
|
|
45
|
+
POINT_LIST_SINGLE_COLOUR = "point_list_single_colour"
|
|
46
|
+
MULTI_COLOURED_INSTANCED_GEOMETRY = "multi_coloured_instanced_geometry"
|
|
47
|
+
SINGLE_COLOUR_INSTANCED_GEOMETRY = "single_colour_instanced_geometry"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# Backward compatibility alias
|
|
51
|
+
BasePipeline = BaseWebGPUPipeline
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class _PipelineFactory:
|
|
55
|
+
"""
|
|
56
|
+
Factory for creating pipeline instances with various configurations.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def __init__(self):
|
|
60
|
+
"""Initialize the pipeline factory with default pipeline types."""
|
|
61
|
+
self._pipeline_registry: Dict[PipelineType, Type[BasePipeline]] = {}
|
|
62
|
+
self.register_pipeline(
|
|
63
|
+
PipelineType.MULTI_COLOURED_POINTS, PointPipelineMultiColour
|
|
64
|
+
)
|
|
65
|
+
self.register_pipeline(
|
|
66
|
+
PipelineType.SINGLE_COLOUR_POINTS, PointPipelineSingleColour
|
|
67
|
+
)
|
|
68
|
+
self.register_pipeline(
|
|
69
|
+
PipelineType.MULTI_COLOURED_LINES, LinePipelineMultiColour
|
|
70
|
+
)
|
|
71
|
+
self.register_pipeline(
|
|
72
|
+
PipelineType.SINGLE_COLOUR_LINES, LinePipelineSingleColour
|
|
73
|
+
)
|
|
74
|
+
self.register_pipeline(
|
|
75
|
+
PipelineType.MULTI_COLOURED_TRIANGLES, TrianglePipelineMultiColour
|
|
76
|
+
)
|
|
77
|
+
self.register_pipeline(
|
|
78
|
+
PipelineType.SINGLE_COLOUR_TRIANGLES, TrianglePipelineSingleColour
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Create wrapper classes for specific topology types
|
|
82
|
+
class TriangleListMultiColour(TrianglePipelineMultiColour):
|
|
83
|
+
def __init__(self, device):
|
|
84
|
+
super().__init__(device, topology=wgpu.PrimitiveTopology.triangle_list)
|
|
85
|
+
|
|
86
|
+
class TriangleListSingleColour(TrianglePipelineSingleColour):
|
|
87
|
+
def __init__(self, device):
|
|
88
|
+
super().__init__(device, topology=wgpu.PrimitiveTopology.triangle_list)
|
|
89
|
+
|
|
90
|
+
class TriangleStripMultiColour(TrianglePipelineMultiColour):
|
|
91
|
+
def __init__(self, device):
|
|
92
|
+
super().__init__(device, topology=wgpu.PrimitiveTopology.triangle_strip)
|
|
93
|
+
|
|
94
|
+
class TriangleStripSingleColour(TrianglePipelineSingleColour):
|
|
95
|
+
def __init__(self, device):
|
|
96
|
+
super().__init__(device, topology=wgpu.PrimitiveTopology.triangle_strip)
|
|
97
|
+
|
|
98
|
+
self.register_pipeline(
|
|
99
|
+
PipelineType.TRIANGLE_LIST_MULTI_COLOURED, TriangleListMultiColour
|
|
100
|
+
)
|
|
101
|
+
self.register_pipeline(
|
|
102
|
+
PipelineType.TRIANGLE_LIST_SINGLE_COLOUR, TriangleListSingleColour
|
|
103
|
+
)
|
|
104
|
+
self.register_pipeline(
|
|
105
|
+
PipelineType.TRIANGLE_STRIP_MULTI_COLOURED, TriangleStripMultiColour
|
|
106
|
+
)
|
|
107
|
+
self.register_pipeline(
|
|
108
|
+
PipelineType.TRIANGLE_STRIP_SINGLE_COLOUR, TriangleStripSingleColour
|
|
109
|
+
)
|
|
110
|
+
self.register_pipeline(
|
|
111
|
+
PipelineType.SINGLE_COLOUR_TRIANGLES, TrianglePipelineSingleColour
|
|
112
|
+
)
|
|
113
|
+
self.register_pipeline(
|
|
114
|
+
PipelineType.TRIANGLE_LIST_MULTI_COLOURED,
|
|
115
|
+
lambda device: TrianglePipelineMultiColour(
|
|
116
|
+
device, topology=wgpu.PrimitiveTopology.triangle_list
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
self.register_pipeline(
|
|
120
|
+
PipelineType.TRIANGLE_LIST_SINGLE_COLOUR,
|
|
121
|
+
lambda device: TrianglePipelineSingleColour(
|
|
122
|
+
device, topology=wgpu.PrimitiveTopology.triangle_list
|
|
123
|
+
),
|
|
124
|
+
)
|
|
125
|
+
self.register_pipeline(
|
|
126
|
+
PipelineType.TRIANGLE_STRIP_MULTI_COLOURED,
|
|
127
|
+
lambda device: TrianglePipelineMultiColour(
|
|
128
|
+
device, topology=wgpu.PrimitiveTopology.triangle_strip
|
|
129
|
+
),
|
|
130
|
+
)
|
|
131
|
+
self.register_pipeline(
|
|
132
|
+
PipelineType.TRIANGLE_STRIP_SINGLE_COLOUR,
|
|
133
|
+
lambda device: TrianglePipelineSingleColour(
|
|
134
|
+
device, topology=wgpu.PrimitiveTopology.triangle_strip
|
|
135
|
+
),
|
|
136
|
+
)
|
|
137
|
+
self.register_pipeline(
|
|
138
|
+
PipelineType.POINT_LIST_MULTI_COLOURED, PointListPipelineMultiColour
|
|
139
|
+
)
|
|
140
|
+
self.register_pipeline(
|
|
141
|
+
PipelineType.POINT_LIST_SINGLE_COLOUR, PointListPipelineSingleColour
|
|
142
|
+
)
|
|
143
|
+
self.register_pipeline(
|
|
144
|
+
PipelineType.MULTI_COLOURED_INSTANCED_GEOMETRY,
|
|
145
|
+
InstancedGeometryPipelineMultiColour,
|
|
146
|
+
)
|
|
147
|
+
self.register_pipeline(
|
|
148
|
+
PipelineType.SINGLE_COLOUR_INSTANCED_GEOMETRY,
|
|
149
|
+
InstancedGeometryPipelineSingleColour,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def register_pipeline(
|
|
153
|
+
self, pipeline_type: PipelineType, pipeline_class: Type[BaseWebGPUPipeline]
|
|
154
|
+
) -> None:
|
|
155
|
+
"""
|
|
156
|
+
Register a custom pipeline type.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
pipeline_type: Enum identifier for the pipeline
|
|
160
|
+
pipeline_class: Pipeline class to register
|
|
161
|
+
"""
|
|
162
|
+
self._pipeline_registry[pipeline_type] = pipeline_class
|
|
163
|
+
|
|
164
|
+
def create_pipeline(
|
|
165
|
+
self, device: wgpu.GPUDevice, pipeline_type: PipelineType, **kwargs
|
|
166
|
+
) -> BaseWebGPUPipeline:
|
|
167
|
+
"""
|
|
168
|
+
Create a pipeline instance.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
device: WebGPU device
|
|
172
|
+
pipeline_type: Type of pipeline to create
|
|
173
|
+
**kwargs: Pipeline-specific configuration parameters
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
Configured pipeline instance
|
|
177
|
+
|
|
178
|
+
Raises:
|
|
179
|
+
ValueError: If pipeline type is not registered
|
|
180
|
+
"""
|
|
181
|
+
if pipeline_type not in self._pipeline_registry:
|
|
182
|
+
raise ValueError(
|
|
183
|
+
f"Unknown pipeline type: {pipeline_type}. Available types: {list(self._pipeline_registry.keys())}"
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
pipeline_class = self._pipeline_registry[pipeline_type]
|
|
187
|
+
return pipeline_class(device, **kwargs)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
PipelineFactory = _PipelineFactory()
|