ncca-ngl 0.3.5__py3-none-any.whl → 0.5.0__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.
Files changed (56) hide show
  1. ncca/ngl/PrimData/pack_arrays.py +2 -3
  2. ncca/ngl/__init__.py +3 -4
  3. ncca/ngl/base_mesh.py +28 -20
  4. ncca/ngl/image.py +1 -3
  5. ncca/ngl/mat2.py +79 -53
  6. ncca/ngl/mat3.py +104 -185
  7. ncca/ngl/mat4.py +144 -309
  8. ncca/ngl/prim_data.py +42 -36
  9. ncca/ngl/primitives.py +2 -2
  10. ncca/ngl/pyside_event_handling_mixin.py +0 -108
  11. ncca/ngl/quaternion.py +69 -36
  12. ncca/ngl/shader.py +0 -116
  13. ncca/ngl/shader_program.py +94 -117
  14. ncca/ngl/texture.py +5 -2
  15. ncca/ngl/util.py +0 -2
  16. ncca/ngl/vec2.py +59 -302
  17. ncca/ngl/vec2_array.py +79 -28
  18. ncca/ngl/vec3.py +60 -350
  19. ncca/ngl/vec3_array.py +76 -23
  20. ncca/ngl/vec4.py +90 -200
  21. ncca/ngl/vec4_array.py +78 -27
  22. ncca/ngl/vector_base.py +542 -0
  23. ncca/ngl/webgpu/__init__.py +20 -0
  24. ncca/ngl/webgpu/__main__.py +640 -0
  25. ncca/ngl/webgpu/__main__.py.backup +640 -0
  26. ncca/ngl/webgpu/base_webgpu_pipeline.py +354 -0
  27. ncca/ngl/webgpu/custom_shader_pipeline.py +288 -0
  28. ncca/ngl/webgpu/instanced_geometry_pipeline.py +594 -0
  29. ncca/ngl/webgpu/line_pipeline.py +405 -0
  30. ncca/ngl/webgpu/pipeline_factory.py +190 -0
  31. ncca/ngl/webgpu/pipeline_shaders.py +497 -0
  32. ncca/ngl/webgpu/point_list_pipeline.py +349 -0
  33. ncca/ngl/webgpu/point_pipeline.py +336 -0
  34. ncca/ngl/webgpu/triangle_pipeline.py +419 -0
  35. ncca/ngl/webgpu/webgpu_constants.py +31 -0
  36. ncca/ngl/webgpu/webgpu_widget.py +322 -0
  37. ncca/ngl/webgpu/wip/REFACTORING_SUMMARY.md +82 -0
  38. ncca/ngl/webgpu/wip/UNIFIED_SYSTEM.md +314 -0
  39. ncca/ngl/webgpu/wip/buffer_manager.py +396 -0
  40. ncca/ngl/webgpu/wip/pipeline_config.py +463 -0
  41. ncca/ngl/webgpu/wip/shader_constants.py +328 -0
  42. ncca/ngl/webgpu/wip/shader_templates.py +563 -0
  43. ncca/ngl/webgpu/wip/unified_examples.py +390 -0
  44. ncca/ngl/webgpu/wip/unified_factory.py +449 -0
  45. ncca/ngl/webgpu/wip/unified_pipeline.py +469 -0
  46. ncca/ngl/widgets/__init__.py +18 -2
  47. ncca/ngl/widgets/__main__.py +2 -1
  48. ncca/ngl/widgets/lookatwidget.py +2 -1
  49. ncca/ngl/widgets/mat4widget.py +2 -2
  50. ncca/ngl/widgets/vec2widget.py +1 -1
  51. ncca/ngl/widgets/vec3widget.py +1 -0
  52. {ncca_ngl-0.3.5.dist-info → ncca_ngl-0.5.0.dist-info}/METADATA +3 -2
  53. ncca_ngl-0.5.0.dist-info/RECORD +105 -0
  54. ncca/ngl/widgets/transformation_widget.py +0 -299
  55. ncca_ngl-0.3.5.dist-info/RECORD +0 -82
  56. {ncca_ngl-0.3.5.dist-info → ncca_ngl-0.5.0.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()