ncca-ngl 0.3.4__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.
- ncca/ngl/PrimData/pack_arrays.py +2 -3
- ncca/ngl/__init__.py +3 -4
- 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 +7 -0
- ncca/ngl/vec2.py +58 -292
- ncca/ngl/vec2_array.py +79 -28
- ncca/ngl/vec3.py +59 -340
- ncca/ngl/vec3_array.py +76 -23
- ncca/ngl/vec4.py +90 -190
- ncca/ngl/vec4_array.py +78 -27
- ncca/ngl/vector_base.py +542 -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 +31 -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.4.dist-info → ncca_ngl-0.5.0.dist-info}/METADATA +3 -2
- ncca_ngl-0.5.0.dist-info/RECORD +105 -0
- ncca/ngl/widgets/transformation_widget.py +0 -299
- ncca_ngl-0.3.4.dist-info/RECORD +0 -82
- {ncca_ngl-0.3.4.dist-info → ncca_ngl-0.5.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unified WebGPU pipeline with user-defined shader support.
|
|
3
|
+
Provides a single, configurable pipeline class that can handle all rendering scenarios.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import wgpu
|
|
10
|
+
|
|
11
|
+
from .base_webgpu_pipeline import BaseWebGPUPipeline
|
|
12
|
+
from .buffer_manager import UnifiedResourceManager
|
|
13
|
+
from .pipeline_config import (
|
|
14
|
+
BufferLayout,
|
|
15
|
+
PipelineConfig,
|
|
16
|
+
VertexLayoutBuilder,
|
|
17
|
+
)
|
|
18
|
+
from .shader_templates import generate_shader_code
|
|
19
|
+
from .webgpu_constants import NGLToWebGPU
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class UnifiedWebGPUPipeline(BaseWebGPUPipeline):
|
|
23
|
+
"""
|
|
24
|
+
Unified WebGPU pipeline that supports all primitive types, color modes, and custom shaders.
|
|
25
|
+
|
|
26
|
+
Features:
|
|
27
|
+
- Configurable primitive types (points, lines, triangles)
|
|
28
|
+
- Single and multi-color rendering modes
|
|
29
|
+
- User-defined shader support
|
|
30
|
+
- Billboarding for points
|
|
31
|
+
- Flexible vertex layouts
|
|
32
|
+
- MSAA support
|
|
33
|
+
- Depth testing
|
|
34
|
+
- Resource management
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, device: wgpu.GPUDevice, config: PipelineConfig):
|
|
38
|
+
"""
|
|
39
|
+
Initialize unified pipeline with configuration.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
device: WebGPU device
|
|
43
|
+
config: Pipeline configuration
|
|
44
|
+
"""
|
|
45
|
+
self.config = config
|
|
46
|
+
|
|
47
|
+
# Calculate stride if not provided
|
|
48
|
+
if config.stride == 0:
|
|
49
|
+
stride = NGLToWebGPU.stride_from_type(config.data_type)
|
|
50
|
+
else:
|
|
51
|
+
stride = config.stride
|
|
52
|
+
|
|
53
|
+
# Initialize resource manager
|
|
54
|
+
self.resources = UnifiedResourceManager(device)
|
|
55
|
+
|
|
56
|
+
# Track vertex data
|
|
57
|
+
self._vertex_buffers: Dict[str, wgpu.GPUBuffer] = {}
|
|
58
|
+
self._vertex_counts: Dict[str, int] = {}
|
|
59
|
+
self._num_vertices: int = 0
|
|
60
|
+
|
|
61
|
+
# Initialize base pipeline
|
|
62
|
+
super().__init__(
|
|
63
|
+
device=device,
|
|
64
|
+
texture_format=config.texture_format,
|
|
65
|
+
depth_format=config.depth_format,
|
|
66
|
+
msaa_sample_count=config.msaa_sample_count,
|
|
67
|
+
data_type=config.data_type,
|
|
68
|
+
stride=stride,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
def _get_shader_code(self) -> str:
|
|
72
|
+
"""Get shader code from configuration."""
|
|
73
|
+
if self.config.custom_vertex_shader or self.config.custom_fragment_shader:
|
|
74
|
+
# Use custom shaders
|
|
75
|
+
shader_config = self.config.to_shader_config()
|
|
76
|
+
shader_code = generate_shader_code(shader_config)
|
|
77
|
+
else:
|
|
78
|
+
# Use template-based shader generation
|
|
79
|
+
shader_config = self.config.to_shader_config()
|
|
80
|
+
shader_code = generate_shader_code(shader_config)
|
|
81
|
+
|
|
82
|
+
# Debug: Print shader code for triangles
|
|
83
|
+
if self.config.primitive_type.value == "triangle":
|
|
84
|
+
print(f"Generated triangle shader ({self.config.color_mode.value}):")
|
|
85
|
+
print("=" * 50)
|
|
86
|
+
print(shader_code)
|
|
87
|
+
print("=" * 50)
|
|
88
|
+
|
|
89
|
+
return shader_code
|
|
90
|
+
|
|
91
|
+
def _get_vertex_buffer_layouts(self) -> List[Dict[str, Any]]:
|
|
92
|
+
"""Get vertex buffer layouts from configuration."""
|
|
93
|
+
if self.config.buffer_layouts:
|
|
94
|
+
# Use custom buffer layouts
|
|
95
|
+
return [
|
|
96
|
+
{
|
|
97
|
+
"array_stride": layout.stride,
|
|
98
|
+
"step_mode": layout.step_mode,
|
|
99
|
+
"attributes": layout.attributes,
|
|
100
|
+
}
|
|
101
|
+
for layout in self.config.buffer_layouts
|
|
102
|
+
]
|
|
103
|
+
else:
|
|
104
|
+
# Generate default layouts based on configuration
|
|
105
|
+
return self._generate_default_vertex_layouts()
|
|
106
|
+
|
|
107
|
+
def _generate_default_vertex_layouts(self) -> List[Dict[str, Any]]:
|
|
108
|
+
"""Generate default vertex buffer layouts based on configuration."""
|
|
109
|
+
layouts = []
|
|
110
|
+
|
|
111
|
+
# Position buffer layout
|
|
112
|
+
position_layout = (
|
|
113
|
+
VertexLayoutBuilder(
|
|
114
|
+
stride=self._stride,
|
|
115
|
+
step_mode="instance",
|
|
116
|
+
)
|
|
117
|
+
.with_position(self.config.data_type, offset=0, location=0)
|
|
118
|
+
.build()
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
layouts.append(
|
|
122
|
+
{
|
|
123
|
+
"array_stride": position_layout.stride,
|
|
124
|
+
"step_mode": position_layout.step_mode,
|
|
125
|
+
"attributes": position_layout.attributes,
|
|
126
|
+
}
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Color buffer layout for multi-color mode
|
|
130
|
+
if self.config.color_mode.value == "multi":
|
|
131
|
+
color_layout = (
|
|
132
|
+
VertexLayoutBuilder(
|
|
133
|
+
stride=NGLToWebGPU.stride_from_type("Vec3"),
|
|
134
|
+
step_mode="instance",
|
|
135
|
+
)
|
|
136
|
+
.with_color("Vec3", offset=0, location=1)
|
|
137
|
+
.build()
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
layouts.append(
|
|
141
|
+
{
|
|
142
|
+
"array_stride": color_layout.stride,
|
|
143
|
+
"step_mode": color_layout.step_mode,
|
|
144
|
+
"attributes": color_layout.attributes,
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Add custom attribute layouts
|
|
149
|
+
if self.config.custom_attributes:
|
|
150
|
+
for i, attr in enumerate(self.config.custom_attributes):
|
|
151
|
+
# Start layout after position and potential color buffer
|
|
152
|
+
layout_index = len(layouts)
|
|
153
|
+
custom_layout = (
|
|
154
|
+
VertexLayoutBuilder(
|
|
155
|
+
stride=NGLToWebGPU.stride_from_type(attr.data_type),
|
|
156
|
+
step_mode=attr.step_mode,
|
|
157
|
+
)
|
|
158
|
+
.with_custom_attribute(
|
|
159
|
+
attr.data_type,
|
|
160
|
+
offset=0,
|
|
161
|
+
location=attr.location,
|
|
162
|
+
)
|
|
163
|
+
.build()
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
layouts.append(
|
|
167
|
+
{
|
|
168
|
+
"array_stride": custom_layout.stride,
|
|
169
|
+
"step_mode": custom_layout.step_mode,
|
|
170
|
+
"attributes": custom_layout.attributes,
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
return layouts
|
|
175
|
+
|
|
176
|
+
def _get_primitive_topology(self) -> wgpu.PrimitiveTopology:
|
|
177
|
+
"""Get primitive topology from configuration."""
|
|
178
|
+
return self.config.topology
|
|
179
|
+
|
|
180
|
+
def _set_default_uniforms(self) -> None:
|
|
181
|
+
"""Set default uniform values based on configuration."""
|
|
182
|
+
shader_config = self.config.to_shader_config()
|
|
183
|
+
|
|
184
|
+
# Set default MVP matrix
|
|
185
|
+
self.uniform_data["MVP"] = np.eye(4, dtype=np.float32)
|
|
186
|
+
|
|
187
|
+
# Set defaults based on primitive type and color mode
|
|
188
|
+
if self.config.primitive_type.value == "point":
|
|
189
|
+
if self.config.render_mode.value == "billboarded":
|
|
190
|
+
# View matrix for billboarding
|
|
191
|
+
self.uniform_data["ViewMatrix"] = np.eye(4, dtype=np.float32)
|
|
192
|
+
|
|
193
|
+
if self.config.color_mode.value == "single":
|
|
194
|
+
# Default white color and size
|
|
195
|
+
self.uniform_data["ColourSize"] = np.array(
|
|
196
|
+
[1.0, 1.0, 1.0, 1.0], dtype=np.float32
|
|
197
|
+
)
|
|
198
|
+
else:
|
|
199
|
+
# Default size for multi-color
|
|
200
|
+
self.uniform_data["size"] = 1.0
|
|
201
|
+
|
|
202
|
+
elif self.config.color_mode.value == "single":
|
|
203
|
+
# Default white color for non-point primitives
|
|
204
|
+
self.uniform_data["colour"] = np.array([1.0, 1.0, 1.0], dtype=np.float32)
|
|
205
|
+
|
|
206
|
+
def _get_pipeline_label(self) -> str:
|
|
207
|
+
"""Get pipeline label based on configuration."""
|
|
208
|
+
return (
|
|
209
|
+
f"unified_pipeline_{self.config.primitive_type.value}_"
|
|
210
|
+
f"{self.config.color_mode.value}_{self.config.render_mode.value}"
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
def _create_pipeline(self) -> None:
|
|
214
|
+
"""Create pipeline with custom depth stencil and rasterization state."""
|
|
215
|
+
# Create shader module
|
|
216
|
+
shader_code = self._get_shader_code()
|
|
217
|
+
shader_module = self.device.create_shader_module(code=shader_code)
|
|
218
|
+
|
|
219
|
+
# Get vertex buffer layouts
|
|
220
|
+
vertex_layouts = self._get_vertex_buffer_layouts()
|
|
221
|
+
|
|
222
|
+
# Create render pipeline
|
|
223
|
+
self.pipeline = self.device.create_render_pipeline(
|
|
224
|
+
label=self._get_pipeline_label(),
|
|
225
|
+
layout="auto",
|
|
226
|
+
vertex={
|
|
227
|
+
"module": shader_module,
|
|
228
|
+
"entry_point": "vertex_main",
|
|
229
|
+
"buffers": vertex_layouts,
|
|
230
|
+
},
|
|
231
|
+
fragment={
|
|
232
|
+
"module": shader_module,
|
|
233
|
+
"entry_point": "fragment_main",
|
|
234
|
+
"targets": [{"format": self.config.texture_format}],
|
|
235
|
+
},
|
|
236
|
+
primitive={
|
|
237
|
+
"topology": self.config.topology,
|
|
238
|
+
"cull_mode": self.config.cull_mode,
|
|
239
|
+
"front_face": self.config.front_face,
|
|
240
|
+
},
|
|
241
|
+
depth_stencil={
|
|
242
|
+
"format": self.config.depth_format,
|
|
243
|
+
"depth_write_enabled": True,
|
|
244
|
+
"depth_compare": wgpu.CompareFunction.less,
|
|
245
|
+
},
|
|
246
|
+
multisample={"count": self.config.msaa_sample_count},
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# Initialize uniform manager
|
|
250
|
+
bind_group_layout = self.pipeline.get_bind_group_layout(0)
|
|
251
|
+
self.resources.uniform_manager.initialize(
|
|
252
|
+
self.get_dtype(),
|
|
253
|
+
bind_group_layout,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
# Store reference to uniform buffer and bind group
|
|
257
|
+
self.uniform_buffer = self.resources.uniform_manager.get_uniform_buffer()
|
|
258
|
+
self.bind_group = self.resources.uniform_manager.get_bind_group()
|
|
259
|
+
|
|
260
|
+
def get_dtype(self) -> np.dtype:
|
|
261
|
+
"""Get uniform buffer data type based on configuration."""
|
|
262
|
+
fields = [("MVP", "float32", (4, 4))]
|
|
263
|
+
|
|
264
|
+
# Add fields based on configuration
|
|
265
|
+
if self.config.primitive_type.value == "point":
|
|
266
|
+
if self.config.render_mode.value == "billboarded":
|
|
267
|
+
fields.append(("ViewMatrix", "float32", (4, 4)))
|
|
268
|
+
|
|
269
|
+
if self.config.color_mode.value == "single":
|
|
270
|
+
fields.append(("ColourSize", "float32", 4))
|
|
271
|
+
else:
|
|
272
|
+
fields.append(("size", "float32"))
|
|
273
|
+
fields.extend([(f"padding{i}", "uint32") for i in range(3)])
|
|
274
|
+
|
|
275
|
+
else: # Line or Triangle
|
|
276
|
+
if self.config.color_mode.value == "single":
|
|
277
|
+
fields.extend(
|
|
278
|
+
[
|
|
279
|
+
("colour", "float32", 3),
|
|
280
|
+
("padding", "float32"),
|
|
281
|
+
]
|
|
282
|
+
)
|
|
283
|
+
else:
|
|
284
|
+
fields.extend([(f"padding{i}", "float32") for i in range(4)])
|
|
285
|
+
|
|
286
|
+
# Add custom uniform fields
|
|
287
|
+
if self.config.custom_uniforms:
|
|
288
|
+
for uniform in self.config.custom_uniforms:
|
|
289
|
+
if uniform.array_size:
|
|
290
|
+
fields.append((uniform.name, uniform.data_type, uniform.array_size))
|
|
291
|
+
else:
|
|
292
|
+
fields.append((uniform.name, uniform.data_type))
|
|
293
|
+
|
|
294
|
+
return np.dtype(fields)
|
|
295
|
+
|
|
296
|
+
def set_data(
|
|
297
|
+
self,
|
|
298
|
+
positions: Union[np.ndarray, wgpu.GPUBuffer],
|
|
299
|
+
colours: Optional[Union[np.ndarray, wgpu.GPUBuffer]] = None,
|
|
300
|
+
**kwargs,
|
|
301
|
+
) -> None:
|
|
302
|
+
"""
|
|
303
|
+
Set vertex data for rendering.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
positions: Vertex positions (numpy array or GPU buffer)
|
|
307
|
+
colours: Vertex colors for multi-color mode (numpy array or GPU buffer)
|
|
308
|
+
**kwargs: Additional vertex data based on custom attributes
|
|
309
|
+
"""
|
|
310
|
+
# Process positions
|
|
311
|
+
if isinstance(positions, wgpu.GPUBuffer):
|
|
312
|
+
self._vertex_buffers["position"] = positions
|
|
313
|
+
self._num_vertices = positions.size // self._stride
|
|
314
|
+
else:
|
|
315
|
+
self._num_vertices = len(positions)
|
|
316
|
+
self._vertex_buffers["position"] = (
|
|
317
|
+
self.resources.buffer_manager.update_buffer(
|
|
318
|
+
"position",
|
|
319
|
+
positions,
|
|
320
|
+
wgpu.BufferUsage.VERTEX | wgpu.BufferUsage.COPY_DST,
|
|
321
|
+
f"{self._get_pipeline_label()}_position_buffer",
|
|
322
|
+
)
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
# Process colors for multi-color mode
|
|
326
|
+
if self.config.color_mode.value == "multi":
|
|
327
|
+
if colours is None:
|
|
328
|
+
# Create default white colors
|
|
329
|
+
default_colours = np.ones((self._num_vertices, 3), dtype=np.float32)
|
|
330
|
+
self._vertex_buffers["colour"] = (
|
|
331
|
+
self.resources.buffer_manager.process_vertex_data(
|
|
332
|
+
"colour",
|
|
333
|
+
None,
|
|
334
|
+
default_colours,
|
|
335
|
+
padding_size=4, # Pad to vec4 for alignment
|
|
336
|
+
buffer_label=f"{self._get_pipeline_label()}_colour_buffer",
|
|
337
|
+
)
|
|
338
|
+
)
|
|
339
|
+
else:
|
|
340
|
+
self._vertex_buffers["colour"] = (
|
|
341
|
+
self.resources.buffer_manager.process_vertex_data(
|
|
342
|
+
"colour",
|
|
343
|
+
colours,
|
|
344
|
+
None,
|
|
345
|
+
padding_size=4,
|
|
346
|
+
buffer_label=f"{self._get_pipeline_label()}_colour_buffer",
|
|
347
|
+
)
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
# Process custom attributes
|
|
351
|
+
if self.config.custom_attributes:
|
|
352
|
+
for attr in self.config.custom_attributes:
|
|
353
|
+
attr_name = attr.name
|
|
354
|
+
attr_data = kwargs.get(attr_name)
|
|
355
|
+
if attr_data is not None:
|
|
356
|
+
self._vertex_buffers[attr_name] = (
|
|
357
|
+
self.resources.buffer_manager.process_vertex_data(
|
|
358
|
+
attr_name,
|
|
359
|
+
attr_data,
|
|
360
|
+
None,
|
|
361
|
+
buffer_label=f"{self._get_pipeline_label()}_{attr_name}_buffer",
|
|
362
|
+
)
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
def update_uniforms(self, **kwargs) -> None:
|
|
366
|
+
"""
|
|
367
|
+
Update uniform buffer values.
|
|
368
|
+
|
|
369
|
+
Args:
|
|
370
|
+
**kwargs: Uniform parameters
|
|
371
|
+
- mvp: 4x4 model view projection matrix
|
|
372
|
+
- view_matrix: 4x4 view matrix (for billboarding)
|
|
373
|
+
- colour: 3-element RGB color (single color mode)
|
|
374
|
+
- point_size: Point size (for points)
|
|
375
|
+
- Custom uniforms based on configuration
|
|
376
|
+
"""
|
|
377
|
+
uniforms = {}
|
|
378
|
+
|
|
379
|
+
# Map common parameter names to uniform field names
|
|
380
|
+
if "mvp" in kwargs:
|
|
381
|
+
uniforms["MVP"] = kwargs["mvp"]
|
|
382
|
+
|
|
383
|
+
if "view_matrix" in kwargs:
|
|
384
|
+
uniforms["ViewMatrix"] = kwargs["view_matrix"]
|
|
385
|
+
|
|
386
|
+
if "colour" in kwargs and self.config.color_mode.value == "single":
|
|
387
|
+
if self.config.primitive_type.value == "point":
|
|
388
|
+
uniforms["ColourSize"] = self.uniform_data["ColourSize"].copy()
|
|
389
|
+
uniforms["ColourSize"][:3] = kwargs["colour"]
|
|
390
|
+
else:
|
|
391
|
+
uniforms["colour"] = kwargs["colour"]
|
|
392
|
+
|
|
393
|
+
if "point_size" in kwargs and self.config.primitive_type.value == "point":
|
|
394
|
+
if self.config.color_mode.value == "single":
|
|
395
|
+
uniforms["ColourSize"] = self.uniform_data["ColourSize"].copy()
|
|
396
|
+
uniforms["ColourSize"][3] = kwargs["point_size"]
|
|
397
|
+
else:
|
|
398
|
+
uniforms["size"] = kwargs["point_size"]
|
|
399
|
+
|
|
400
|
+
# Add custom uniforms
|
|
401
|
+
if self.config.custom_uniforms:
|
|
402
|
+
for uniform in self.config.custom_uniforms:
|
|
403
|
+
if uniform.name in kwargs:
|
|
404
|
+
uniforms[uniform.name] = kwargs[uniform.name]
|
|
405
|
+
|
|
406
|
+
# Update uniform buffer
|
|
407
|
+
if uniforms:
|
|
408
|
+
self.resources.uniform_manager.update_uniforms(uniforms)
|
|
409
|
+
# Update base class reference
|
|
410
|
+
self.uniform_data = self.resources.uniform_manager.get_uniform_data()
|
|
411
|
+
|
|
412
|
+
def render(
|
|
413
|
+
self,
|
|
414
|
+
render_pass: wgpu.GPURenderPassEncoder,
|
|
415
|
+
num_vertices: Optional[int] = None,
|
|
416
|
+
**kwargs,
|
|
417
|
+
) -> None:
|
|
418
|
+
"""
|
|
419
|
+
Render using this pipeline.
|
|
420
|
+
|
|
421
|
+
Args:
|
|
422
|
+
render_pass: Active render pass encoder
|
|
423
|
+
num_vertices: Number of vertices to render (defaults to all)
|
|
424
|
+
**kwargs: Additional render parameters
|
|
425
|
+
"""
|
|
426
|
+
if not self._vertex_buffers.get("position"):
|
|
427
|
+
return
|
|
428
|
+
|
|
429
|
+
# Determine vertex count
|
|
430
|
+
count = num_vertices if num_vertices is not None else self._num_vertices
|
|
431
|
+
|
|
432
|
+
# Set pipeline and bind group
|
|
433
|
+
render_pass.set_pipeline(self.pipeline)
|
|
434
|
+
if self.bind_group:
|
|
435
|
+
render_pass.set_bind_group(0, self.bind_group, [], 0, 999999)
|
|
436
|
+
|
|
437
|
+
# Set vertex buffers
|
|
438
|
+
slot = 0
|
|
439
|
+
for buffer_name in ["position", "colour"]:
|
|
440
|
+
if buffer_name in self._vertex_buffers:
|
|
441
|
+
render_pass.set_vertex_buffer(slot, self._vertex_buffers[buffer_name])
|
|
442
|
+
slot += 1
|
|
443
|
+
|
|
444
|
+
# Set custom attribute buffers
|
|
445
|
+
if self.config.custom_attributes:
|
|
446
|
+
for attr in self.config.custom_attributes:
|
|
447
|
+
if attr.name in self._vertex_buffers:
|
|
448
|
+
render_pass.set_vertex_buffer(slot, self._vertex_buffers[attr.name])
|
|
449
|
+
slot += 1
|
|
450
|
+
|
|
451
|
+
# Determine vertex count for different primitives
|
|
452
|
+
if (
|
|
453
|
+
self.config.primitive_type.value == "point"
|
|
454
|
+
and self.config.render_mode.value == "billboarded"
|
|
455
|
+
):
|
|
456
|
+
# Points are rendered as 4 vertices (quad) per point
|
|
457
|
+
vertex_count = 4
|
|
458
|
+
instance_count = count
|
|
459
|
+
else:
|
|
460
|
+
vertex_count = count
|
|
461
|
+
instance_count = 1
|
|
462
|
+
|
|
463
|
+
# Issue draw call
|
|
464
|
+
render_pass.draw(vertex_count, instance_count)
|
|
465
|
+
|
|
466
|
+
def cleanup(self) -> None:
|
|
467
|
+
"""Release pipeline resources."""
|
|
468
|
+
self.resources.cleanup()
|
|
469
|
+
super().cleanup()
|
ncca/ngl/widgets/__init__.py
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
__version__ = version("ncca-ngl") # pragma: no cover
|
|
5
|
+
except PackageNotFoundError: # pragma: no cover
|
|
6
|
+
__version__ = "0.0.0"
|
|
7
|
+
|
|
8
|
+
__author__ = "Jon Macey jmacey@bournemouth.ac.uk"
|
|
9
|
+
__license__ = "MIT"
|
|
2
10
|
|
|
3
11
|
|
|
4
12
|
from .lookatwidget import LookAtWidget
|
|
@@ -9,4 +17,12 @@ from .vec2widget import Vec2Widget
|
|
|
9
17
|
from .vec3widget import Vec3Widget
|
|
10
18
|
from .vec4widget import Vec4Widget
|
|
11
19
|
|
|
12
|
-
__all__ = [
|
|
20
|
+
__all__ = [
|
|
21
|
+
"Vec2Widget",
|
|
22
|
+
"Vec3Widget",
|
|
23
|
+
"Vec4Widget",
|
|
24
|
+
"TransformWidget",
|
|
25
|
+
"LookAtWidget",
|
|
26
|
+
"RGBColourWidget",
|
|
27
|
+
"RGBAColourWidget",
|
|
28
|
+
]
|
ncca/ngl/widgets/__main__.py
CHANGED
|
@@ -11,13 +11,14 @@ from ncca.ngl.widgets import (
|
|
|
11
11
|
Vec2Widget,
|
|
12
12
|
Vec3Widget,
|
|
13
13
|
Vec4Widget,
|
|
14
|
+
__version__,
|
|
14
15
|
)
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class SimpleDialog(QDialog):
|
|
18
19
|
def __init__(self, parent=None):
|
|
19
20
|
super(SimpleDialog, self).__init__(parent)
|
|
20
|
-
self.setWindowTitle("PyNGL ncca.widgets library ")
|
|
21
|
+
self.setWindowTitle(f"PyNGL ncca.widgets library {__version__}")
|
|
21
22
|
self.setMinimumWidth(200)
|
|
22
23
|
layout = QGridLayout()
|
|
23
24
|
|
ncca/ngl/widgets/lookatwidget.py
CHANGED
|
@@ -53,6 +53,7 @@ class LookAtWidget(QFrame):
|
|
|
53
53
|
content_layout.addWidget(self._up)
|
|
54
54
|
main_layout.addWidget(self._toggle_button)
|
|
55
55
|
main_layout.addWidget(self._content_widget)
|
|
56
|
+
self._update_matrix()
|
|
56
57
|
|
|
57
58
|
def set_eye(self, eye):
|
|
58
59
|
self._eye.set_value(eye)
|
|
@@ -68,7 +69,7 @@ class LookAtWidget(QFrame):
|
|
|
68
69
|
self._toggle_button.setText(name)
|
|
69
70
|
|
|
70
71
|
def get_name(self):
|
|
71
|
-
return self._name
|
|
72
|
+
return self._name
|
|
72
73
|
|
|
73
74
|
def get_eye(self):
|
|
74
75
|
return self._eye.value
|
ncca/ngl/widgets/mat4widget.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from PySide6.QtCore import Property, QSignalBlocker, Signal
|
|
2
2
|
from PySide6.QtWidgets import QDoubleSpinBox, QFrame, QHBoxLayout, QLabel, QWidget
|
|
3
3
|
|
|
4
|
-
from ncca.ngl import Mat4
|
|
4
|
+
from ncca.ngl import Mat4
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
class Mat4ViewWidget(QFrame):
|
|
7
|
+
class Mat4ViewWidget(QFrame): ...
|
ncca/ngl/widgets/vec2widget.py
CHANGED
|
@@ -78,7 +78,7 @@ class Vec2Widget(QFrame):
|
|
|
78
78
|
Args:
|
|
79
79
|
value: The new value of the widget.
|
|
80
80
|
"""
|
|
81
|
-
with QSignalBlocker(self.x_spinbox), QSignalBlocker(self.y_spinbox)
|
|
81
|
+
with QSignalBlocker(self.x_spinbox), QSignalBlocker(self.y_spinbox):
|
|
82
82
|
self.x_spinbox.setValue(value.x)
|
|
83
83
|
self.y_spinbox.setValue(value.y)
|
|
84
84
|
self._value = value
|
ncca/ngl/widgets/vec3widget.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: ncca-ngl
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: A Python version of the NGL graphics library.
|
|
5
5
|
Author: Jon Macey
|
|
6
6
|
Author-email: Jon Macey <jmacey@bournemouth.ac.uk>
|
|
@@ -17,6 +17,7 @@ Requires-Dist: pillow
|
|
|
17
17
|
Requires-Dist: glfw>=2.9.0
|
|
18
18
|
Requires-Dist: freetype-py>=2.5.1
|
|
19
19
|
Requires-Dist: pyside6>=6.9.2
|
|
20
|
-
Requires-
|
|
20
|
+
Requires-Dist: wgpu>=0.29.0
|
|
21
|
+
Requires-Python: >=3.11
|
|
21
22
|
Project-URL: Homepage, https://github.com/NCCA/PyNGL
|
|
22
23
|
Project-URL: Issues, https://github.com/NCCA/PyNGL/issues
|