deformable 0.1.0__py3-none-win_amd64.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.
deformable/errors.py ADDED
@@ -0,0 +1,150 @@
1
+ """Status codes and the exception a failed library call raises."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import ctypes
6
+ import enum
7
+
8
+ from . import library, native
9
+
10
+
11
+ class Status(enum.IntEnum):
12
+ """The DEFORMABLE_STATUS_* codes of deformable.h."""
13
+
14
+ OK = 0
15
+ NULL_POINTER = 1
16
+ INVALID_ARGUMENT = 2
17
+ PANICKED = 3
18
+ INDEX_OUT_OF_RANGE = 4
19
+ UNKNOWN_MATERIAL = 5
20
+ UNKNOWN_OBJECT = 6
21
+ LENGTH_MISMATCH = 7
22
+ NON_FINITE_VALUE = 8
23
+ EMPTY_MESH = 9
24
+ NON_MANIFOLD_FACE = 10
25
+ DEGENERATE_TETRAHEDRON_TOO_SMALL = 11
26
+ DEGENERATE_TETRAHEDRON_FLAT = 12
27
+ DEGENERATE_TETRAHEDRON_INVERTED = 13
28
+ SCALE_OUT_OF_RANGE = 14
29
+ DEGENERATE_REGION = 15
30
+ TIME_WENT_BACKWARDS = 16
31
+ INVALID_WORKER_COUNT = 17
32
+ CANCELLED = 18
33
+ OUTPUT_TOO_LARGE = 19
34
+ DEGENERATE_POLYGON = 20
35
+ NON_MANIFOLD_EDGE = 21
36
+ OPEN_EDGE = 22
37
+ COULD_NOT_CONVERGE = 23
38
+ BAD_SCALES = 24
39
+ MESHING_FAILED = 25
40
+ NO_TETRAHEDRA = 26
41
+ INVALID_CAGE = 27
42
+ NON_POSITIVE_THICKNESS = 28
43
+ NOT_ISOMORPHIC = 29
44
+ UNKNOWN_VERTEX = 30
45
+ DUPLICATE_VERTEX = 31
46
+ MULTIPLE_BOUNDARIES = 32
47
+ DEGENERATE_FACE = 33
48
+ NULL_NORMAL = 34
49
+ EMPTY_INPUT = 35
50
+ STEP_LIMIT_REACHED = 36
51
+ INVALID_SPLINTER_CAGE = 37
52
+ EMPTY_IMAGE = 38
53
+ NO_VERTICES = 39
54
+ NO_CELLS = 40
55
+ ENDLESS_CYCLE = 41
56
+ FACE_ALREADY_SET = 42
57
+ SINGULAR_TRANSFORM = 43
58
+ LICENSE_REQUIRED = 44
59
+ TRIAL_LIMIT_EXCEEDED = 45
60
+ LICENSE_NEEDS_ONLINE = 46
61
+ LICENSE_SERVICE_UNAVAILABLE = 47
62
+ LICENSE_KEY_REJECTED = 48
63
+ LICENSE_STORAGE_FAILED = 49
64
+
65
+ @property
66
+ def is_license(self) -> bool:
67
+ """Whether the status is about the license of this device and user, rather than the call's arguments: its
68
+ message is a status line or a licensing service's answer, written for the user as it is."""
69
+ return Status.LICENSE_REQUIRED <= self <= Status.LICENSE_STORAGE_FAILED
70
+
71
+
72
+ class DeformableError(Exception):
73
+ """A library call failed: its status, the library's message and up to two element indices.
74
+
75
+ The indices name the tetrahedron, region, polygon, face, vertex or edge the failure concerns, as each status
76
+ describes in deformable.h; they are 0 when the status names none.
77
+ """
78
+
79
+ def __init__(self, status: Status | int, message: str, first_index: int = 0, second_index: int = 0):
80
+ super().__init__(f"{_status_name(status)}: {message}")
81
+ self.status = status
82
+ self.message = message
83
+ self.first_index = first_index
84
+ self.second_index = second_index
85
+
86
+
87
+ class LicenseError(DeformableError):
88
+ """The license of this device and user refused a call, or the licensing service could not be reached or refused
89
+ the key: one of the LICENSE_* statuses or TRIAL_LIMIT_EXCEEDED.
90
+
91
+ Its message is written for the user as it is, such as "Trial ended — Buy license", so a host shows `message`
92
+ alone, without the status name.
93
+ """
94
+
95
+
96
+ class LicenseRequiredError(LicenseError):
97
+ """LICENSE_REQUIRED: no usable trial or license on this device, because the trial ended or the license was
98
+ removed. The message is the license status line, such as "Trial ended — Buy license"."""
99
+
100
+
101
+ class TrialLimitExceededError(LicenseError):
102
+ """TRIAL_LIMIT_EXCEEDED: the trial allows at most `limit` tetrahedrons per simulation, and the call would have
103
+ made the simulation hold `tetrahedrons`. The message is "Trial limit: 2500 tetrahedrons"."""
104
+
105
+ @property
106
+ def tetrahedrons(self) -> int:
107
+ """The tetrahedrons the simulation would have held."""
108
+ return self.first_index
109
+
110
+ @property
111
+ def limit(self) -> int:
112
+ """The most tetrahedrons a trial simulation may hold."""
113
+ return self.second_index
114
+
115
+
116
+ def _status_name(status: Status | int) -> str:
117
+ return status.name if isinstance(status, Status) else f"status {status}"
118
+
119
+
120
+ def _status(code: int) -> Status | int:
121
+ # A newer library may return a code this package does not know yet; it is still reported, as a plain int.
122
+ try:
123
+ return Status(code)
124
+ except ValueError:
125
+ return code
126
+
127
+
128
+ def error(status: Status | int, message: str, first_index: int = 0, second_index: int = 0) -> DeformableError:
129
+ """The exception for a failure: the subclass of DeformableError that matches its status."""
130
+ if status == Status.LICENSE_REQUIRED:
131
+ error_type = LicenseRequiredError
132
+ elif status == Status.TRIAL_LIMIT_EXCEEDED:
133
+ error_type = TrialLimitExceededError
134
+ elif isinstance(status, Status) and status.is_license:
135
+ error_type = LicenseError
136
+ else:
137
+ error_type = DeformableError
138
+ return error_type(status, message, first_index, second_index)
139
+
140
+
141
+ def check(code: int) -> None:
142
+ """Raises the calling thread's last error as a DeformableError, or its license subclass, when a call returned a
143
+ failure code."""
144
+ if code == Status.OK:
145
+ return
146
+ functions = library.load()
147
+ message = functions.deformable_last_error_message().decode("utf-8", errors="replace")
148
+ details = native.ErrorDetails()
149
+ functions.deformable_last_error_details(ctypes.byref(details))
150
+ raise error(_status(code), message, details.first_index, details.second_index)
deformable/handles.py ADDED
@@ -0,0 +1,97 @@
1
+ """Ownership of the library's opaque handles."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import contextlib
6
+ import ctypes
7
+ import threading
8
+ import weakref
9
+ from collections.abc import Iterator
10
+
11
+ from . import library, native
12
+ from .errors import check
13
+
14
+
15
+ @contextlib.contextmanager
16
+ def temporary_handle(destroy_name: str) -> Iterator[native.Handle]:
17
+ """An empty handle for a call to fill, destroyed at the end of the block; a result is copied out before then."""
18
+ handle = native.Handle()
19
+ try:
20
+ yield handle
21
+ finally:
22
+ # Every _destroy function accepts NULL, so a call that failed before filling the handle needs no test here.
23
+ getattr(library.load(), destroy_name)(handle)
24
+
25
+
26
+ class OwnedHandle:
27
+ """A handle the Python object owns: destroyed by close(), at the end of a with block, or when collected.
28
+
29
+ Library calls release the global interpreter lock, so another thread may close the object while a call on it
30
+ runs. Every call therefore goes through _use(), and close() refuses new calls, then waits for the ones in flight
31
+ before destroying the handle.
32
+ """
33
+
34
+ _destroy_name = ""
35
+ _description = ""
36
+ _one_call_at_a_time = False
37
+ """True when the library forbids overlapping calls on one handle; _use() then queues them."""
38
+
39
+ def __init__(self, create_name: str):
40
+ handle = native.Handle()
41
+ check(getattr(library.load(), create_name)(ctypes.byref(handle)))
42
+ self._attach(handle)
43
+
44
+ def _attach(self, handle: native.Handle) -> None:
45
+ self._address = handle.value
46
+ self._condition = threading.Condition()
47
+ self._calls_in_flight = 0
48
+ self._close_requested = False
49
+ destroy = getattr(library.load(), self._destroy_name)
50
+ self._finalizer = weakref.finalize(self, destroy, self._address)
51
+
52
+ @classmethod
53
+ def _adopt(cls, handle: native.Handle):
54
+ owner = cls.__new__(cls)
55
+ owner._attach(handle)
56
+ return owner
57
+
58
+ @property
59
+ def closed(self) -> bool:
60
+ """True once the handle has been destroyed."""
61
+ return not self._finalizer.alive
62
+
63
+ @contextlib.contextmanager
64
+ def _use(self) -> Iterator[int]:
65
+ """The handle's address, kept alive until the block ends; lent pointers must be read inside the block."""
66
+ with self._condition:
67
+ if self._one_call_at_a_time:
68
+ self._condition.wait_for(lambda: self._calls_in_flight == 0 or self._close_requested)
69
+ if self._close_requested:
70
+ raise ValueError(f"the {self._description} is closed")
71
+ self._calls_in_flight += 1
72
+ try:
73
+ yield self._address
74
+ finally:
75
+ with self._condition:
76
+ self._calls_in_flight -= 1
77
+ self._condition.notify_all()
78
+
79
+ def _call(self, function_name: str, *arguments) -> None:
80
+ """Calls a library function with the handle first, raising DeformableError when it fails."""
81
+ with self._use() as address:
82
+ check(getattr(library.load(), function_name)(address, *arguments))
83
+
84
+ def close(self) -> None:
85
+ """Destroys the handle once the calls in flight on it end; later calls on the object raise ValueError.
86
+ Closing twice does nothing."""
87
+ with self._condition:
88
+ self._close_requested = True
89
+ self._condition.notify_all()
90
+ self._condition.wait_for(lambda: self._calls_in_flight == 0)
91
+ self._finalizer()
92
+
93
+ def __enter__(self):
94
+ return self
95
+
96
+ def __exit__(self, *exception_information) -> None:
97
+ self.close()
deformable/library.py ADDED
@@ -0,0 +1,410 @@
1
+ """Finding and loading libdeformable, the shared library of crates/ffi, with the prototype of every export.
2
+
3
+ The library is searched in this order:
4
+
5
+ 1. the file named by the DEFORMABLE_LIBRARY environment variable;
6
+ 2. the package directory, where a distribution of the package places it;
7
+ 3. target/release of the Cargo workspace this package sits in (bindings/python/deformable), where a source checkout
8
+ builds it.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import ctypes
14
+ import functools
15
+ import os
16
+ import sys
17
+ from pathlib import Path
18
+
19
+ from . import native
20
+
21
+ ENVIRONMENT_VARIABLE = "DEFORMABLE_LIBRARY"
22
+
23
+
24
+ class LibraryNotFoundError(OSError):
25
+ """No shared library was found in any of the searched places."""
26
+
27
+
28
+ def library_file_name(platform: str = sys.platform) -> str:
29
+ """The file name cargo gives the shared library on a platform (a sys.platform value)."""
30
+ if platform.startswith("win"):
31
+ return "deformable.dll"
32
+ if platform == "darwin":
33
+ return "libdeformable.dylib"
34
+ return "libdeformable.so"
35
+
36
+
37
+ def candidate_paths() -> list[Path]:
38
+ """The places searched for the shared library, in search order."""
39
+ package_directory = Path(__file__).resolve().parent
40
+ workspace_directory = package_directory.parents[2]
41
+ candidates = []
42
+ configured = os.environ.get(ENVIRONMENT_VARIABLE)
43
+ if configured:
44
+ candidates.append(Path(configured))
45
+ candidates.append(package_directory / library_file_name())
46
+ candidates.append(workspace_directory / "target" / "release" / library_file_name())
47
+ return candidates
48
+
49
+
50
+ @functools.cache
51
+ def load() -> ctypes.CDLL:
52
+ """The shared library with every export's prototype declared, loaded once per process."""
53
+ candidates = candidate_paths()
54
+ for candidate in candidates:
55
+ if candidate.is_file():
56
+ library = ctypes.CDLL(str(candidate))
57
+ declare_prototypes(library)
58
+ return library
59
+ searched = ", ".join(str(candidate) for candidate in candidates)
60
+ raise LibraryNotFoundError(
61
+ f"libdeformable not found (searched {searched}); reinstall the deformable package for this platform or set "
62
+ f"{ENVIRONMENT_VARIABLE} to its path"
63
+ )
64
+
65
+
66
+ def declare_prototypes(library: ctypes.CDLL) -> None:
67
+ """Sets the argument and result types of every export, so ctypes converts and checks each argument."""
68
+ for name, (result_type, argument_types) in PROTOTYPES.items():
69
+ function = getattr(library, name)
70
+ function.restype = result_type
71
+ function.argtypes = argument_types
72
+
73
+
74
+ def _pointer(value_type):
75
+ return ctypes.POINTER(value_type)
76
+
77
+
78
+ _handle_output = _pointer(native.Handle)
79
+ _count_output = _pointer(native.Count)
80
+ _boolean_output = _pointer(native.Boolean)
81
+ _index_output = _pointer(native.Index)
82
+
83
+
84
+ def _destroy(name: str) -> tuple[str, tuple]:
85
+ return name, (None, [native.Handle])
86
+
87
+
88
+ def _lend(element_type) -> list:
89
+ """The arguments of a function that lends one array of an object: simulation, object, array and count."""
90
+ return [native.Handle, native.Index, _pointer(_pointer(element_type)), _count_output]
91
+
92
+
93
+ PROTOTYPES: dict[str, tuple] = dict(
94
+ [
95
+ ("deformable_version", (ctypes.c_char_p, [])),
96
+ ("deformable_last_error_message", (ctypes.c_char_p, [])),
97
+ ("deformable_last_error_details", (native.Status, [_pointer(native.ErrorDetails)])),
98
+ # Declared for parity with deformable.h, which tests/test_native.py checks; the package never calls it, since
99
+ # check() reads the error right after the call that failed and the next successful call clears it.
100
+ ("deformable_last_error_clear", (native.Status, [])),
101
+ # License.
102
+ ("deformable_license_status", (native.Status, [_pointer(native.LicenseStatus)])),
103
+ ("deformable_license_refresh", (native.Status, [ctypes.c_uint32, _pointer(native.LicenseStatus)])),
104
+ (
105
+ "deformable_license_activate",
106
+ (native.Status, [_pointer(ctypes.c_char), ctypes.c_uint32, _pointer(native.LicenseStatus)]),
107
+ ),
108
+ ("deformable_license_deactivate", (native.Status, [ctypes.c_uint32, _pointer(native.LicenseStatus)])),
109
+ ("deformable_license_set_online_access", (native.Status, [native.Boolean])),
110
+ # Cancel flags.
111
+ ("deformable_cancel_flag_create", (native.Status, [_handle_output])),
112
+ _destroy("deformable_cancel_flag_destroy"),
113
+ ("deformable_cancel_flag_set", (native.Status, [native.Handle, native.Boolean])),
114
+ ("deformable_cancel_flag_is_set", (native.Status, [native.Handle, _boolean_output])),
115
+ # Meshes.
116
+ ("deformable_face_corners", (native.Status, [native.Index, _pointer(native.TriangleIndices)])),
117
+ (
118
+ "deformable_tetrahedral_mesh_view",
119
+ (native.Status, [native.Handle, _pointer(native.TetrahedralMeshView)]),
120
+ ),
121
+ _destroy("deformable_tetrahedral_mesh_destroy"),
122
+ ("deformable_polygon_mesh_view", (native.Status, [native.Handle, _pointer(native.PolygonMeshView)])),
123
+ _destroy("deformable_polygon_mesh_destroy"),
124
+ (
125
+ "deformable_triangle_surface_view",
126
+ (native.Status, [native.Handle, _pointer(native.TriangleSurfaceView)]),
127
+ ),
128
+ _destroy("deformable_triangle_surface_destroy"),
129
+ (
130
+ "deformable_boundary_faces",
131
+ (native.Status, [_pointer(native.TetrahedralMeshView), _handle_output]),
132
+ ),
133
+ (
134
+ "deformable_boundary_faces_masks",
135
+ (native.Status, [native.Handle, _pointer(_pointer(ctypes.c_uint8)), _count_output]),
136
+ ),
137
+ _destroy("deformable_boundary_faces_destroy"),
138
+ # Tools.
139
+ ("deformable_anisotropy_default", (native.Status, [_pointer(native.Anisotropy)])),
140
+ (
141
+ "deformable_triangulate_parameters_default",
142
+ (native.Status, [_pointer(native.TriangulateParameters)]),
143
+ ),
144
+ (
145
+ "deformable_triangulate",
146
+ (
147
+ native.Status,
148
+ [
149
+ _pointer(native.PolygonMeshView),
150
+ _pointer(native.FaceHole),
151
+ native.Count,
152
+ _pointer(native.TriangulateParameters),
153
+ native.Handle,
154
+ _handle_output,
155
+ ],
156
+ ),
157
+ ),
158
+ (
159
+ "deformable_triangulation_view",
160
+ (native.Status, [native.Handle, _pointer(native.TriangulationView)]),
161
+ ),
162
+ _destroy("deformable_triangulation_destroy"),
163
+ (
164
+ "deformable_tetrahedralize",
165
+ (
166
+ native.Status,
167
+ [
168
+ _pointer(native.TriangleSurfaceView),
169
+ _pointer(native.TetrahedralizeParameters),
170
+ native.Handle,
171
+ _handle_output,
172
+ ],
173
+ ),
174
+ ),
175
+ (
176
+ "deformable_tetrahedralization_view",
177
+ (native.Status, [native.Handle, _pointer(native.TetrahedralizationView)]),
178
+ ),
179
+ _destroy("deformable_tetrahedralization_destroy"),
180
+ (
181
+ "deformable_extrude",
182
+ (
183
+ native.Status,
184
+ [_pointer(native.TriangleSurfaceView), ctypes.c_double, native.Enumeration, _handle_output],
185
+ ),
186
+ ),
187
+ (
188
+ "deformable_span_layers",
189
+ (
190
+ native.Status,
191
+ [_pointer(native.TriangleSurfaceView), _pointer(native.TriangleSurfaceView), _handle_output],
192
+ ),
193
+ ),
194
+ ("deformable_autocage_parameters_default", (native.Status, [_pointer(native.AutocageParameters)])),
195
+ (
196
+ "deformable_autocage",
197
+ (
198
+ native.Status,
199
+ [
200
+ _pointer(native.PolygonMeshView),
201
+ _pointer(native.AutocageParameters),
202
+ native.Handle,
203
+ _handle_output,
204
+ ],
205
+ ),
206
+ ),
207
+ (
208
+ "deformable_splinter_image_parameters_default",
209
+ (native.Status, [_pointer(native.SplinterImageParameters)]),
210
+ ),
211
+ (
212
+ "deformable_splinters_from_image",
213
+ (
214
+ native.Status,
215
+ [_pointer(native.PixelGrid), _pointer(native.SplinterImageParameters), _handle_output],
216
+ ),
217
+ ),
218
+ ("deformable_mesh_checks_default", (native.Status, [_pointer(native.MeshChecks)])),
219
+ (
220
+ "deformable_verify_surface",
221
+ (
222
+ native.Status,
223
+ [
224
+ _pointer(native.SurfaceMeshView),
225
+ _pointer(native.FaceHole),
226
+ native.Count,
227
+ _pointer(native.MeshChecks),
228
+ _handle_output,
229
+ ],
230
+ ),
231
+ ),
232
+ (
233
+ "deformable_mesh_issue_list_issues",
234
+ (native.Status, [native.Handle, _pointer(_pointer(native.MeshIssue)), _count_output]),
235
+ ),
236
+ _destroy("deformable_mesh_issue_list_destroy"),
237
+ (
238
+ "deformable_meshes_intersect",
239
+ (
240
+ native.Status,
241
+ [_pointer(native.TetrahedralMeshView), _pointer(native.TetrahedralMeshView), _boolean_output],
242
+ ),
243
+ ),
244
+ # Simulation.
245
+ ("deformable_simulation_create", (native.Status, [_handle_output])),
246
+ _destroy("deformable_simulation_destroy"),
247
+ ("deformable_simulation_set_scale", (native.Status, [native.Handle, ctypes.c_double])),
248
+ ("deformable_simulation_set_gravity", (native.Status, [native.Handle, native.Vector3])),
249
+ ("deformable_simulation_set_worker_count", (native.Status, [native.Handle, native.Count])),
250
+ ("deformable_material_parameters_default", (native.Status, [_pointer(native.MaterialParameters)])),
251
+ ("deformable_material_preset_count", (native.Count, [])),
252
+ (
253
+ "deformable_material_preset",
254
+ (
255
+ native.Status,
256
+ [native.Count, _pointer(_pointer(ctypes.c_char)), _pointer(native.MaterialParameters)],
257
+ ),
258
+ ),
259
+ (
260
+ "deformable_material_preset_find",
261
+ (native.Status, [_pointer(ctypes.c_char), _pointer(native.MaterialParameters)]),
262
+ ),
263
+ (
264
+ "deformable_simulation_add_material",
265
+ (native.Status, [native.Handle, _pointer(native.MaterialParameters), _index_output]),
266
+ ),
267
+ (
268
+ "deformable_simulation_set_material",
269
+ (native.Status, [native.Handle, native.Index, _pointer(native.MaterialParameters)]),
270
+ ),
271
+ ("deformable_object_options_default", (native.Status, [_pointer(native.ObjectOptions)])),
272
+ (
273
+ "deformable_simulation_add_object",
274
+ (
275
+ native.Status,
276
+ [
277
+ native.Handle,
278
+ _pointer(native.TetrahedralMeshView),
279
+ _pointer(native.TetrahedronMaterials),
280
+ _pointer(native.ObjectOptions),
281
+ _index_output,
282
+ ],
283
+ ),
284
+ ),
285
+ (
286
+ "deformable_simulation_set_object_material",
287
+ (native.Status, [native.Handle, native.Index, _pointer(native.TetrahedronMaterials)]),
288
+ ),
289
+ ("deformable_simulation_remove_object", (native.Status, [native.Handle, native.Index])),
290
+ (
291
+ "deformable_simulation_set_object_disabled",
292
+ (native.Status, [native.Handle, native.Index, native.Boolean]),
293
+ ),
294
+ (
295
+ "deformable_simulation_set_self_collision",
296
+ (native.Status, [native.Handle, native.Index, native.Boolean]),
297
+ ),
298
+ (
299
+ "deformable_simulation_set_never_sleep",
300
+ (native.Status, [native.Handle, native.Index, native.Index, native.Boolean]),
301
+ ),
302
+ (
303
+ "deformable_simulation_set_glue_all",
304
+ (native.Status, [native.Handle, _pointer(native.GlueParameters)]),
305
+ ),
306
+ (
307
+ "deformable_simulation_add_glue_region",
308
+ (
309
+ native.Status,
310
+ [
311
+ native.Handle,
312
+ _pointer(native.ConvexRegion),
313
+ _pointer(native.Index),
314
+ native.Count,
315
+ _pointer(native.GlueParameters),
316
+ ],
317
+ ),
318
+ ),
319
+ (
320
+ "deformable_convex_region_contains",
321
+ (native.Status, [_pointer(native.ConvexRegion), native.Vector3, _boolean_output]),
322
+ ),
323
+ (
324
+ "deformable_simulation_drive",
325
+ (native.Status, [native.Handle, native.Index, _pointer(native.DrivenVertex), native.Count]),
326
+ ),
327
+ (
328
+ "deformable_simulation_add_force",
329
+ (native.Status, [native.Handle, native.Index, native.Index, native.Vector3]),
330
+ ),
331
+ (
332
+ "deformable_simulation_step",
333
+ (
334
+ native.Status,
335
+ [native.Handle, ctypes.c_double, ctypes.c_uint32, native.Handle, _pointer(native.StepReport)],
336
+ ),
337
+ ),
338
+ ("deformable_simulation_skip_to", (native.Status, [native.Handle, ctypes.c_double])),
339
+ ("deformable_simulation_node_positions", (native.Status, _lend(native.Vector3))),
340
+ ("deformable_simulation_node_velocities", (native.Status, _lend(native.Vector3))),
341
+ ("deformable_simulation_node_masses", (native.Status, _lend(ctypes.c_double))),
342
+ ("deformable_simulation_tetrahedron_nodes", (native.Status, _lend(native.TetrahedronIndices))),
343
+ ("deformable_simulation_tetrahedron_states", (native.Status, _lend(native.TetrahedronState))),
344
+ ("deformable_simulation_face_events", (native.Status, _lend(native.FaceEvent))),
345
+ ("deformable_simulation_awake_tetrahedron_count", (native.Status, [native.Handle, _count_output])),
346
+ (
347
+ "deformable_simulation_statistics",
348
+ (native.Status, [native.Handle, _pointer(native.SimulationStatistics)]),
349
+ ),
350
+ (
351
+ "deformable_tetrahedron_state_face_centroid",
352
+ (native.Status, [_pointer(native.TetrahedronState), native.Index, _pointer(native.Vector3)]),
353
+ ),
354
+ (
355
+ "deformable_tetrahedron_state_face_normal",
356
+ (native.Status, [_pointer(native.TetrahedronState), native.Index, _pointer(native.Vector3)]),
357
+ ),
358
+ # Material regions.
359
+ (
360
+ "deformable_material_region_indices",
361
+ (
362
+ native.Status,
363
+ [_pointer(native.TetrahedralMeshView), _pointer(native.MaterialRegion), native.Count, _handle_output],
364
+ ),
365
+ ),
366
+ (
367
+ "deformable_material_region_indices_values",
368
+ (native.Status, [native.Handle, _pointer(_pointer(native.Index)), _count_output]),
369
+ ),
370
+ _destroy("deformable_material_region_indices_destroy"),
371
+ # Render surfaces.
372
+ (
373
+ "deformable_embed_surface",
374
+ (
375
+ native.Status,
376
+ [
377
+ _pointer(native.TetrahedralMeshView),
378
+ _pointer(native.SurfaceMeshView),
379
+ _pointer(native.PreparationParameters),
380
+ _handle_output,
381
+ ],
382
+ ),
383
+ ),
384
+ (
385
+ "deformable_surface_embedding_view",
386
+ (native.Status, [native.Handle, _pointer(native.SurfaceEmbeddingView)]),
387
+ ),
388
+ (
389
+ "deformable_surface_embedding_deform",
390
+ (
391
+ native.Status,
392
+ [
393
+ native.Handle,
394
+ _pointer(native.TetrahedronState),
395
+ native.Count,
396
+ _pointer(native.AffineTransform),
397
+ _pointer(native.SkinningOptions),
398
+ native.Handle,
399
+ ],
400
+ ),
401
+ ),
402
+ _destroy("deformable_surface_embedding_destroy"),
403
+ ("deformable_deformed_surface_create", (native.Status, [_handle_output])),
404
+ (
405
+ "deformable_deformed_surface_view",
406
+ (native.Status, [native.Handle, _pointer(native.DeformedSurfaceView)]),
407
+ ),
408
+ _destroy("deformable_deformed_surface_destroy"),
409
+ ]
410
+ )