@francisdb/vpin-wasm 0.28.2 → 0.30.0
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.
- package/README.md +82 -13
- package/package.json +1 -1
- package/vpin.d.ts +276 -25
- package/vpin.js +298 -29
- package/vpin_bg.wasm +0 -0
- package/vpin_bg.wasm.d.ts +3 -0
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ npm install @francisdb/vpin-wasm
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
|
-
import init, { extract, assemble, obj_to_mesh, mesh_to_obj } from '@francisdb/vpin-wasm';
|
|
14
|
+
import init, { extract, assemble, obj_to_mesh, mesh_to_obj, AxisConvention } from '@francisdb/vpin-wasm';
|
|
15
15
|
|
|
16
16
|
await init();
|
|
17
17
|
```
|
|
@@ -35,7 +35,7 @@ const files = extract(vpxBytes, (message) => {
|
|
|
35
35
|
- `data: Uint8Array` - VPX file bytes
|
|
36
36
|
- `callback?: (message: string) => void` - Optional progress callback
|
|
37
37
|
|
|
38
|
-
**Returns:** `Record<string, Uint8Array>` -
|
|
38
|
+
**Returns:** `VpxFileMap` (`Record<string, Uint8Array>`) - file paths to contents
|
|
39
39
|
|
|
40
40
|
### assemble(files, callback?)
|
|
41
41
|
|
|
@@ -57,12 +57,47 @@ const vpxBytes = assemble(files, (message) => {
|
|
|
57
57
|
|
|
58
58
|
**Parameters:**
|
|
59
59
|
|
|
60
|
-
- `files: Record<string, Uint8Array>` -
|
|
60
|
+
- `files: VpxFileMap` (`Record<string, Uint8Array>`) - file paths to contents
|
|
61
61
|
- `callback?: (message: string) => void` - Optional progress callback
|
|
62
62
|
|
|
63
63
|
**Returns:** `Uint8Array` - VPX file bytes
|
|
64
64
|
|
|
65
|
-
###
|
|
65
|
+
### export_glb(files, options?, callback?)
|
|
66
|
+
|
|
67
|
+
Exports a whole table to a GLB (binary glTF 2.0) file. Takes the same
|
|
68
|
+
extracted-file map `assemble` takes; call `extract` first if you only
|
|
69
|
+
have `.vpx` bytes.
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
const files = extract(vpxBytes);
|
|
73
|
+
const glb = export_glb(files, { exportInvisibleItems: false }, (message) => {
|
|
74
|
+
console.log(message);
|
|
75
|
+
});
|
|
76
|
+
// glb is a Uint8Array with model/gltf-binary content
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The output follows the glTF conventions - Y-up right-handed axes and
|
|
80
|
+
meters - so it opens correctly in Blender and other viewers with
|
|
81
|
+
default import settings. It contains generated meshes for every part
|
|
82
|
+
type, PBR materials from the table's material list, embedded textures,
|
|
83
|
+
and the three VPX view cameras.
|
|
84
|
+
|
|
85
|
+
Sound entries (`/vpx/sounds.json`, `/vpx/sounds/*`) are ignored - the
|
|
86
|
+
exporter never reads them, and skipping them keeps peak wasm memory
|
|
87
|
+
down on sound-heavy tables. A map without them works too.
|
|
88
|
+
|
|
89
|
+
**Parameters:**
|
|
90
|
+
|
|
91
|
+
- `files: VpxFileMap` (`Record<string, Uint8Array>`) - file paths to contents
|
|
92
|
+
- `options?: GlbExportOptions` - `{ exportInvisibleItems?: boolean }`;
|
|
93
|
+
when `true`, invisible items are exported with the
|
|
94
|
+
`KHR_node_visibility` extension instead of skipped (needs viewer
|
|
95
|
+
support; leave off for Blender). Default `false`.
|
|
96
|
+
- `callback?: (message: string) => void` - Optional progress callback
|
|
97
|
+
|
|
98
|
+
**Returns:** `Uint8Array` - GLB file bytes
|
|
99
|
+
|
|
100
|
+
### obj_to_mesh(data, options?) / mesh_to_obj(name, positions, texCoords, normals, indices, options?)
|
|
66
101
|
|
|
67
102
|
Renderer-friendly mesh I/O. `obj_to_mesh` parses any flavor of OBJ
|
|
68
103
|
(n-gons fan-triangulated, mismatched `v/vt/vn` corners deduplicated)
|
|
@@ -71,7 +106,9 @@ JS-side OBJ parser needed.
|
|
|
71
106
|
|
|
72
107
|
```typescript
|
|
73
108
|
const objBytes = files['/vpx/gameitems/Primitive.MyMesh.obj'];
|
|
74
|
-
const mesh = obj_to_mesh(objBytes);
|
|
109
|
+
const mesh = obj_to_mesh(objBytes); // defaults: vpinball convention, scale 1.0
|
|
110
|
+
// or e.g. for a Blender-exported OBJ:
|
|
111
|
+
// const mesh = obj_to_mesh(objBytes, { axes: AxisConvention.YUpRightHanded });
|
|
75
112
|
|
|
76
113
|
// mesh.name: string
|
|
77
114
|
// mesh.positions: Float32Array (length = 3 * vertCount, x,y,z,...)
|
|
@@ -95,20 +132,52 @@ const obj = mesh_to_obj(mesh.name, mesh.positions, mesh.texCoords, mesh.normals,
|
|
|
95
132
|
files['/vpx/gameitems/Primitive.MyMesh.obj'] = obj;
|
|
96
133
|
```
|
|
97
134
|
|
|
135
|
+
### mesh_to_glb(name, positions, texCoords, normals, indices, options?)
|
|
136
|
+
|
|
137
|
+
The GLB sibling of `mesh_to_obj` - serializes a single mesh as a
|
|
138
|
+
binary glTF 2.0 file, for handing one primitive's mesh to a DCC tool.
|
|
139
|
+
There is no axis option: glTF mandates Y-up right-handed, so the
|
|
140
|
+
vpx-internal input is always converted the same way `export_glb`
|
|
141
|
+
converts the whole table (texture coordinates pass through unchanged -
|
|
142
|
+
glTF's UV origin matches vpx's, unlike OBJ's).
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
const glb = mesh_to_glb(mesh.name, mesh.positions, mesh.texCoords, mesh.normals, mesh.indices);
|
|
146
|
+
// glb is a Uint8Array with model/gltf-binary content
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`options.unitScale` (default `1.0`) multiplies positions. A
|
|
150
|
+
primitive's local mesh coordinates are arbitrary units (the table
|
|
151
|
+
scales them by the primitive's Size at render), so no unit conversion
|
|
152
|
+
is applied by default.
|
|
153
|
+
|
|
98
154
|
The published wasm bundle is built with `wasm-bindgen --weak-refs`, so
|
|
99
155
|
the Rust-owned memory backing each `mesh` is reclaimed automatically
|
|
100
156
|
via `FinalizationRegistry` when the JS wrapper is garbage-collected.
|
|
101
157
|
You may call `mesh.free()` explicitly for deterministic cleanup of
|
|
102
158
|
large meshes, but it is not required.
|
|
103
159
|
|
|
104
|
-
**Coordinate convention:** the mesh data is in vpx-internal
|
|
105
|
-
`
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
160
|
+
**Coordinate convention:** the mesh data is always in vpx-internal
|
|
161
|
+
form; `options.axes` names the convention of the OBJ side:
|
|
162
|
+
|
|
163
|
+
- `AxisConvention.ZDownRightHanded` (default) - vpinball's exported OBJ
|
|
164
|
+
convention (vertex/normal Z negated, V coordinate flipped,
|
|
165
|
+
per-triangle corner order reversed). This is what `extract` writes
|
|
166
|
+
and `assemble` reads, so it is the right choice for OBJs from the
|
|
167
|
+
extracted file map. Round-trip
|
|
168
|
+
`obj_to_mesh -> edit -> mesh_to_obj -> assemble` preserves vpx data
|
|
169
|
+
by construction.
|
|
170
|
+
- `AxisConvention.YUpRightHanded` - the Blender / DCC default (Y-Z
|
|
171
|
+
swap, V flip, winding reverse). Use this to hand a Blender-exported
|
|
172
|
+
OBJ straight to `obj_to_mesh`, or to write an OBJ that opens upright
|
|
173
|
+
in Blender with default import settings.
|
|
174
|
+
- `AxisConvention.ZUpLeftHanded` - vpx-internal values verbatim, no
|
|
175
|
+
transforms.
|
|
176
|
+
|
|
177
|
+
`options.unitScale` (default `1.0`) multiplies positions (on the vpx
|
|
178
|
+
side for `obj_to_mesh`, before the axis mapping for `mesh_to_obj`).
|
|
179
|
+
Normals and texture coordinates are never scaled. An OBJ written with
|
|
180
|
+
scale `k` reads back with scale `1 / k`.
|
|
112
181
|
|
|
113
182
|
**Animation frames:** primitives with vertex animation extract as
|
|
114
183
|
sibling files `Primitive.MyMesh_00000.obj`, `Primitive.MyMesh_00001.obj`,
|
package/package.json
CHANGED
package/vpin.d.ts
CHANGED
|
@@ -1,6 +1,182 @@
|
|
|
1
1
|
/* tslint:disable */
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* An extracted table as a file map: absolute path under `/vpx` to file
|
|
6
|
+
* contents, e.g. `{ "/vpx/images/ball.png": Uint8Array, ... }`.
|
|
7
|
+
* Produced by `extract`, consumed by `assemble` and `export_glb`.
|
|
8
|
+
*/
|
|
9
|
+
export type VpxFileMap = Record<string, Uint8Array>;
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Options for `export_glb`. Pass a plain object literal; every field
|
|
15
|
+
* is optional.
|
|
16
|
+
*/
|
|
17
|
+
export interface GlbExportOptions {
|
|
18
|
+
/**
|
|
19
|
+
* When `true`, items marked invisible in the table are exported
|
|
20
|
+
* with the `KHR_node_visibility` extension set to `visible: false`
|
|
21
|
+
* instead of being skipped. Preserves the full table structure but
|
|
22
|
+
* requires viewer support for the extension (e.g. some game
|
|
23
|
+
* engines); leave off for Blender. Default: `false`.
|
|
24
|
+
*/
|
|
25
|
+
exportInvisibleItems?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Options for `export_obj`. Pass a plain object literal; every field
|
|
32
|
+
* is optional.
|
|
33
|
+
*/
|
|
34
|
+
export interface ObjExportOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Axis convention of the written OBJ. Default:
|
|
37
|
+
* `AxisConvention.ZDownRightHanded`, vpinball's own OBJ export
|
|
38
|
+
* layout. Use `AxisConvention.YUpRightHanded` for Blender and most
|
|
39
|
+
* other tools with default import settings.
|
|
40
|
+
*/
|
|
41
|
+
axes?: AxisConvention;
|
|
42
|
+
/**
|
|
43
|
+
* Unit of the written positions. Default: `ExportUnits.M`.
|
|
44
|
+
*/
|
|
45
|
+
units?: ExportUnits;
|
|
46
|
+
/**
|
|
47
|
+
* Emit one `newmtl` block per distinct (material, texture) pair
|
|
48
|
+
* instead of one per `usemtl`. Default: `true`.
|
|
49
|
+
*/
|
|
50
|
+
dedupMtlBlocks?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Write the referenced textures to `images/` and reference them
|
|
53
|
+
* from the MTL. Default: `true`.
|
|
54
|
+
*/
|
|
55
|
+
extractTextures?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Include the plunger mesh. Default: `true`.
|
|
58
|
+
*/
|
|
59
|
+
includePlunger?: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Result of `export_obj`: path relative to the export directory to file
|
|
64
|
+
* contents, e.g. `{ "table.obj": Uint8Array, "table.mtl": Uint8Array,
|
|
65
|
+
* "images/playfield.png": Uint8Array }`.
|
|
66
|
+
*/
|
|
67
|
+
export type ObjExportFileMap = Record<string, Uint8Array>;
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Options for `mesh_to_glb`. Pass a plain object literal; every field
|
|
73
|
+
* is optional.
|
|
74
|
+
*/
|
|
75
|
+
export interface MeshGlbOptions {
|
|
76
|
+
/**
|
|
77
|
+
* Multiplier applied to positions before the axis mapping. Normals
|
|
78
|
+
* and texture coordinates are never scaled. Default: `1.0`.
|
|
79
|
+
*/
|
|
80
|
+
unitScale?: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Options for `obj_to_mesh` / `mesh_to_obj`. Pass a plain object
|
|
87
|
+
* literal; every field is optional.
|
|
88
|
+
*/
|
|
89
|
+
export interface MeshIoOptions {
|
|
90
|
+
/**
|
|
91
|
+
* Axis convention of the OBJ side of the conversion (the mesh side
|
|
92
|
+
* is always vpx-internal). Default: `AxisConvention.ZDownRightHanded`,
|
|
93
|
+
* matching what `extract` writes and `assemble` reads.
|
|
94
|
+
*/
|
|
95
|
+
axes?: AxisConvention;
|
|
96
|
+
/**
|
|
97
|
+
* Multiplier applied to positions (on the vpx side for
|
|
98
|
+
* `obj_to_mesh`, before the axis mapping for `mesh_to_obj`).
|
|
99
|
+
* Normals and texture coordinates are never scaled. An OBJ written
|
|
100
|
+
* with scale `k` reads back with `1 / k`. Default: `1.0`.
|
|
101
|
+
*/
|
|
102
|
+
unitScale?: number;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Axis convention for 3D mesh interchange (OBJ, glTF/GLB), in either
|
|
109
|
+
* direction: exporting VPX geometry or importing meshes back in.
|
|
110
|
+
*
|
|
111
|
+
* VPX space is left-handed with Z up: X right (across the playfield),
|
|
112
|
+
* Y towards the player (down the playfield), Z up (towards the glass).
|
|
113
|
+
* [`Self::ZUpLeftHanded`] is that internal frame verbatim; the other
|
|
114
|
+
* variants negate or swap exactly one axis pair, so each produces a
|
|
115
|
+
* right-handed frame from the left-handed one. A conversion between two
|
|
116
|
+
* frames of different [`Self::handedness`] must pair with a reversed
|
|
117
|
+
* triangle winding (matching vpinball's `ObjLoader`); one between frames
|
|
118
|
+
* of equal handedness keeps the winding, since such frames differ only
|
|
119
|
+
* by a pure rotation (the two right-handed variants: 90 degrees about
|
|
120
|
+
* X).
|
|
121
|
+
*/
|
|
122
|
+
export enum AxisConvention {
|
|
123
|
+
/**
|
|
124
|
+
* VPX's internal coordinate system: left-handed with Z up, inherited
|
|
125
|
+
* from DirectX. X runs right across the playfield, Y down the
|
|
126
|
+
* playfield towards the player, Z up towards the glass.
|
|
127
|
+
*
|
|
128
|
+
* Converting to or from this convention leaves coordinates untouched
|
|
129
|
+
* (vertices keep their vpx-internal values). Only meaningful for
|
|
130
|
+
* tooling that works on the raw vpx data; not what any viewer or DCC
|
|
131
|
+
* tool expects.
|
|
132
|
+
*/
|
|
133
|
+
ZUpLeftHanded = 0,
|
|
134
|
+
/**
|
|
135
|
+
* VPinball's exported OBJ convention: `(x, y, -z)`.
|
|
136
|
+
*
|
|
137
|
+
* Right-handed like [`Self::YUpRightHanded`], but keeping VPX's axis
|
|
138
|
+
* roles: Y still runs down the playfield and Z, now negated, points
|
|
139
|
+
* down through the table instead of up. This is what vpinball itself
|
|
140
|
+
* writes when exporting an OBJ and expects when importing one, so a
|
|
141
|
+
* table shows up rotated 90 degrees about X in a Y-up viewer.
|
|
142
|
+
*/
|
|
143
|
+
ZDownRightHanded = 1,
|
|
144
|
+
/**
|
|
145
|
+
* Y up, right-handed: `(x, z, y)`. The glTF and Wavefront OBJ
|
|
146
|
+
* convention, and what Blender / Maya / 3ds Max assume with their
|
|
147
|
+
* default import settings (`Scale 1.0, Forward -Z, Up Y`).
|
|
148
|
+
*/
|
|
149
|
+
YUpRightHanded = 2,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Output unit for table exports (OBJ, glTF/GLB).
|
|
154
|
+
*
|
|
155
|
+
* VPinball internally uses "VP Units" (VPU): 50 VPU = 1.0625 inches
|
|
156
|
+
* (one pinball diameter), so a standard table around 20 inches wide
|
|
157
|
+
* is roughly 950 VPU. Loaded straight into a tool that treats
|
|
158
|
+
* numbers as metres, that becomes a ~950 m table. Pick a metric
|
|
159
|
+
* variant to scale positions on the way out.
|
|
160
|
+
*/
|
|
161
|
+
export enum ExportUnits {
|
|
162
|
+
/**
|
|
163
|
+
* Raw VPinball Units (no scaling).
|
|
164
|
+
*/
|
|
165
|
+
Vpu = 0,
|
|
166
|
+
/**
|
|
167
|
+
* Millimetres.
|
|
168
|
+
*/
|
|
169
|
+
Mm = 1,
|
|
170
|
+
/**
|
|
171
|
+
* Centimetres.
|
|
172
|
+
*/
|
|
173
|
+
Cm = 2,
|
|
174
|
+
/**
|
|
175
|
+
* Metres.
|
|
176
|
+
*/
|
|
177
|
+
M = 3,
|
|
178
|
+
}
|
|
179
|
+
|
|
4
180
|
/**
|
|
5
181
|
* Mesh data for a single primitive: positions, texture coordinates,
|
|
6
182
|
* normals and triangle indices, packed as flat typed arrays for direct
|
|
@@ -45,9 +221,40 @@ export class PrimitiveMesh {
|
|
|
45
221
|
readonly texCoords: Float32Array;
|
|
46
222
|
}
|
|
47
223
|
|
|
48
|
-
export function assemble(files:
|
|
224
|
+
export function assemble(files: VpxFileMap, callback?: Function | null): Uint8Array;
|
|
49
225
|
|
|
50
|
-
|
|
226
|
+
/**
|
|
227
|
+
* Export a whole table to a GLB (binary glTF 2.0) file.
|
|
228
|
+
*
|
|
229
|
+
* Takes the same extracted-file map `assemble` takes
|
|
230
|
+
* (`{ "/vpx/...": Uint8Array }`), so consumers holding a table as an
|
|
231
|
+
* extracted tree skip a full assemble/parse round trip; consumers with
|
|
232
|
+
* only `.vpx` bytes can call `extract` first.
|
|
233
|
+
*
|
|
234
|
+
* The output follows the glTF conventions: Y-up right-handed axes and
|
|
235
|
+
* meters, so it opens correctly in Blender and other glTF viewers with
|
|
236
|
+
* default settings. It contains the generated meshes for every part
|
|
237
|
+
* type, PBR materials from the VPX material list, embedded textures,
|
|
238
|
+
* and the three VPX view cameras (desktop / fullscreen / FSS).
|
|
239
|
+
*
|
|
240
|
+
* Sound entries (`/vpx/sounds.json` and `/vpx/sounds/*`) are ignored -
|
|
241
|
+
* the exporter never reads them, and skipping them keeps peak wasm
|
|
242
|
+
* memory down on sound-heavy tables. Passing a map without them works
|
|
243
|
+
* too.
|
|
244
|
+
*/
|
|
245
|
+
export function export_glb(files: VpxFileMap, options?: GlbExportOptions | null, callback?: Function | null): Uint8Array;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Export a whole table as a Wavefront OBJ with its MTL and, by
|
|
249
|
+
* default, the referenced textures. Takes the file map produced by
|
|
250
|
+
* `extract` and returns a file map relative to the export directory:
|
|
251
|
+
* `table.obj`, `table.mtl` and `images/*`.
|
|
252
|
+
*
|
|
253
|
+
* Sound entries are ignored like in `export_glb`.
|
|
254
|
+
*/
|
|
255
|
+
export function export_obj(files: VpxFileMap, options?: ObjExportOptions | null, callback?: Function | null): ObjExportFileMap;
|
|
256
|
+
|
|
257
|
+
export function extract(data: Uint8Array, callback?: Function | null): VpxFileMap;
|
|
51
258
|
|
|
52
259
|
/**
|
|
53
260
|
* Generate the procedural mesh used by vpinball primitives that
|
|
@@ -72,6 +279,26 @@ export function generate_builtin_primitive(sides: number, draw_textures_inside:
|
|
|
72
279
|
|
|
73
280
|
export function init(): void;
|
|
74
281
|
|
|
282
|
+
/**
|
|
283
|
+
* Serialize a single mesh as a GLB (binary glTF 2.0) file.
|
|
284
|
+
*
|
|
285
|
+
* The GLB sibling of [`mesh_to_obj`], for exporting one primitive's
|
|
286
|
+
* mesh to DCC tools. There is no axis option: glTF mandates Y-up
|
|
287
|
+
* right-handed, so the vpx-internal input is always converted the same
|
|
288
|
+
* way the whole-table exporter converts it (Y-Z swap, winding
|
|
289
|
+
* reversed; texture coordinates pass through - glTF's UV origin
|
|
290
|
+
* matches vpx's, unlike OBJ's).
|
|
291
|
+
*
|
|
292
|
+
* `name` becomes the mesh/node name; pass an empty string to use
|
|
293
|
+
* `"object"`. Array requirements are the same as [`mesh_to_obj`].
|
|
294
|
+
*
|
|
295
|
+
* `options.unitScale` (default `1.0`) multiplies positions. A
|
|
296
|
+
* primitive's local mesh coordinates are arbitrary units (the table
|
|
297
|
+
* scales them by the primitive's Size at render), so no unit
|
|
298
|
+
* conversion is applied by default.
|
|
299
|
+
*/
|
|
300
|
+
export function mesh_to_glb(name: string, positions: Float32Array, tex_coords: Float32Array, normals: Float32Array, indices: Uint32Array, options?: MeshGlbOptions | null): Uint8Array;
|
|
301
|
+
|
|
75
302
|
/**
|
|
76
303
|
* Serialize a mesh as a Wavefront OBJ.
|
|
77
304
|
*
|
|
@@ -81,18 +308,29 @@ export function init(): void;
|
|
|
81
308
|
* normals.len() / 3`); index values must be valid 0-based offsets into
|
|
82
309
|
* that vertex array.
|
|
83
310
|
*
|
|
84
|
-
* `
|
|
85
|
-
*
|
|
311
|
+
* `options.axes` is the symmetric inverse of the same option on
|
|
312
|
+
* [`obj_to_mesh`]: the input is always vpx-internal data, `axes` names
|
|
313
|
+
* the convention to write the OBJ in.
|
|
86
314
|
*
|
|
87
|
-
* - `
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* corner order is reversed. The result is a
|
|
91
|
-
* that `assemble` (or `obj_to_mesh
|
|
92
|
-
*
|
|
93
|
-
*
|
|
315
|
+
* - [`AxisConvention::ZDownRightHanded`] (the default; matches
|
|
316
|
+
* `extract`'s write path, the old `convert_to_left_handed = true`):
|
|
317
|
+
* vertex and normal Z are negated, V is flipped (`obj_v = 1 -
|
|
318
|
+
* vpx_tv`) and per-triangle corner order is reversed. The result is a
|
|
319
|
+
* vpinball-format OBJ that `assemble` (or `obj_to_mesh` with the same
|
|
320
|
+
* convention) reads back identically.
|
|
321
|
+
* - [`AxisConvention::YUpRightHanded`]: Y and Z are swapped, V is
|
|
322
|
+
* flipped and winding is reversed; the OBJ opens upright in Blender
|
|
323
|
+
* with default import settings.
|
|
324
|
+
* - [`AxisConvention::ZUpLeftHanded`] (the old `convert_to_left_handed
|
|
325
|
+
* = false`): the vpx-internal data is written out verbatim, no
|
|
326
|
+
* transforms applied.
|
|
327
|
+
*
|
|
328
|
+
* `options.unitScale` (default `1.0`) multiplies positions before the
|
|
329
|
+
* axis mapping. Normals and texture coordinates are never scaled.
|
|
330
|
+
* Round-trips through `obj_to_mesh` with the same convention and scale
|
|
331
|
+
* `1.0 / unitScale`.
|
|
94
332
|
*/
|
|
95
|
-
export function mesh_to_obj(name: string, positions: Float32Array, tex_coords: Float32Array, normals: Float32Array, indices: Uint32Array,
|
|
333
|
+
export function mesh_to_obj(name: string, positions: Float32Array, tex_coords: Float32Array, normals: Float32Array, indices: Uint32Array, options?: MeshIoOptions | null): Uint8Array;
|
|
96
334
|
|
|
97
335
|
/**
|
|
98
336
|
* Parse a Wavefront OBJ into a [`PrimitiveMesh`].
|
|
@@ -101,21 +339,31 @@ export function mesh_to_obj(name: string, positions: Float32Array, tex_coords: F
|
|
|
101
339
|
* anything in between): n-gons are fan-triangulated and `(position, uv,
|
|
102
340
|
* normal)` corners are deduplicated so the result is renderer-ready.
|
|
103
341
|
*
|
|
104
|
-
* `
|
|
105
|
-
*
|
|
106
|
-
*
|
|
342
|
+
* `options.axes` names the convention the OBJ data is in; the returned
|
|
343
|
+
* mesh is always in vpx-internal convention:
|
|
344
|
+
*
|
|
345
|
+
* - [`AxisConvention::ZDownRightHanded`] (the default; matches
|
|
346
|
+
* `assemble`'s read path and vpinball's mesh-import dialog with
|
|
347
|
+
* "Convert coordinate system" checked, the old `convert_to_left_handed
|
|
348
|
+
* = true`): vertex and normal Z are negated, V is flipped (`vpx_tv =
|
|
349
|
+
* 1 - obj_v`) and the per-triangle corner order is reversed. This path
|
|
350
|
+
* also honors the `# vpx <hex>` byte-preservation comments, so
|
|
351
|
+
* vpinball-format OBJs from `extract` reproduce the original vpx
|
|
352
|
+
* values bit-for-bit.
|
|
353
|
+
* - [`AxisConvention::YUpRightHanded`] (Blender / DCC default export
|
|
354
|
+
* settings): Y and Z are swapped, V is flipped and winding is
|
|
355
|
+
* reversed.
|
|
356
|
+
* - [`AxisConvention::ZUpLeftHanded`] (the old `convert_to_left_handed
|
|
357
|
+
* = false`): the input is assumed to already hold vpx-internal values
|
|
358
|
+
* (e.g. produced by a previous `mesh_to_obj` with the same
|
|
359
|
+
* convention). No transforms; values pass through verbatim.
|
|
107
360
|
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* reversed. The returned mesh data ends up in vpx-internal,
|
|
113
|
-
* left-handed convention.
|
|
114
|
-
* - `false`: the input is assumed to already be in vpx-internal
|
|
115
|
-
* convention (e.g. produced by a previous `mesh_to_obj` with the same
|
|
116
|
-
* flag). The transforms are skipped and values pass through verbatim.
|
|
361
|
+
* `options.unitScale` (default `1.0`) multiplies positions after the
|
|
362
|
+
* axis mapping. Normals and texture coordinates are never scaled. A
|
|
363
|
+
* mesh exported through `mesh_to_obj` with scale `k` reads back with
|
|
364
|
+
* scale `1.0 / k`.
|
|
117
365
|
*/
|
|
118
|
-
export function obj_to_mesh(data: Uint8Array,
|
|
366
|
+
export function obj_to_mesh(data: Uint8Array, options?: MeshIoOptions | null): PrimitiveMesh;
|
|
119
367
|
|
|
120
368
|
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
121
369
|
|
|
@@ -123,8 +371,11 @@ export interface InitOutput {
|
|
|
123
371
|
readonly memory: WebAssembly.Memory;
|
|
124
372
|
readonly __wbg_primitivemesh_free: (a: number, b: number) => void;
|
|
125
373
|
readonly assemble: (a: any, b: number) => [number, number, number, number];
|
|
374
|
+
readonly export_glb: (a: any, b: number, c: number) => [number, number, number, number];
|
|
375
|
+
readonly export_obj: (a: any, b: number, c: number) => [number, number, number];
|
|
126
376
|
readonly extract: (a: number, b: number, c: number) => [number, number, number];
|
|
127
377
|
readonly generate_builtin_primitive: (a: number, b: number) => [number, number, number];
|
|
378
|
+
readonly mesh_to_glb: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number) => [number, number, number, number];
|
|
128
379
|
readonly mesh_to_obj: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number) => [number, number, number, number];
|
|
129
380
|
readonly obj_to_mesh: (a: number, b: number, c: number) => [number, number, number];
|
|
130
381
|
readonly primitivemesh_indices: (a: number) => any;
|
package/vpin.js
CHANGED
|
@@ -1,5 +1,80 @@
|
|
|
1
1
|
/* @ts-self-types="./vpin.d.ts" */
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Axis convention for 3D mesh interchange (OBJ, glTF/GLB), in either
|
|
5
|
+
* direction: exporting VPX geometry or importing meshes back in.
|
|
6
|
+
*
|
|
7
|
+
* VPX space is left-handed with Z up: X right (across the playfield),
|
|
8
|
+
* Y towards the player (down the playfield), Z up (towards the glass).
|
|
9
|
+
* [`Self::ZUpLeftHanded`] is that internal frame verbatim; the other
|
|
10
|
+
* variants negate or swap exactly one axis pair, so each produces a
|
|
11
|
+
* right-handed frame from the left-handed one. A conversion between two
|
|
12
|
+
* frames of different [`Self::handedness`] must pair with a reversed
|
|
13
|
+
* triangle winding (matching vpinball's `ObjLoader`); one between frames
|
|
14
|
+
* of equal handedness keeps the winding, since such frames differ only
|
|
15
|
+
* by a pure rotation (the two right-handed variants: 90 degrees about
|
|
16
|
+
* X).
|
|
17
|
+
* @enum {0 | 1 | 2}
|
|
18
|
+
*/
|
|
19
|
+
export const AxisConvention = Object.freeze({
|
|
20
|
+
/**
|
|
21
|
+
* VPX's internal coordinate system: left-handed with Z up, inherited
|
|
22
|
+
* from DirectX. X runs right across the playfield, Y down the
|
|
23
|
+
* playfield towards the player, Z up towards the glass.
|
|
24
|
+
*
|
|
25
|
+
* Converting to or from this convention leaves coordinates untouched
|
|
26
|
+
* (vertices keep their vpx-internal values). Only meaningful for
|
|
27
|
+
* tooling that works on the raw vpx data; not what any viewer or DCC
|
|
28
|
+
* tool expects.
|
|
29
|
+
*/
|
|
30
|
+
ZUpLeftHanded: 0, "0": "ZUpLeftHanded",
|
|
31
|
+
/**
|
|
32
|
+
* VPinball's exported OBJ convention: `(x, y, -z)`.
|
|
33
|
+
*
|
|
34
|
+
* Right-handed like [`Self::YUpRightHanded`], but keeping VPX's axis
|
|
35
|
+
* roles: Y still runs down the playfield and Z, now negated, points
|
|
36
|
+
* down through the table instead of up. This is what vpinball itself
|
|
37
|
+
* writes when exporting an OBJ and expects when importing one, so a
|
|
38
|
+
* table shows up rotated 90 degrees about X in a Y-up viewer.
|
|
39
|
+
*/
|
|
40
|
+
ZDownRightHanded: 1, "1": "ZDownRightHanded",
|
|
41
|
+
/**
|
|
42
|
+
* Y up, right-handed: `(x, z, y)`. The glTF and Wavefront OBJ
|
|
43
|
+
* convention, and what Blender / Maya / 3ds Max assume with their
|
|
44
|
+
* default import settings (`Scale 1.0, Forward -Z, Up Y`).
|
|
45
|
+
*/
|
|
46
|
+
YUpRightHanded: 2, "2": "YUpRightHanded",
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Output unit for table exports (OBJ, glTF/GLB).
|
|
51
|
+
*
|
|
52
|
+
* VPinball internally uses "VP Units" (VPU): 50 VPU = 1.0625 inches
|
|
53
|
+
* (one pinball diameter), so a standard table around 20 inches wide
|
|
54
|
+
* is roughly 950 VPU. Loaded straight into a tool that treats
|
|
55
|
+
* numbers as metres, that becomes a ~950 m table. Pick a metric
|
|
56
|
+
* variant to scale positions on the way out.
|
|
57
|
+
* @enum {0 | 1 | 2 | 3}
|
|
58
|
+
*/
|
|
59
|
+
export const ExportUnits = Object.freeze({
|
|
60
|
+
/**
|
|
61
|
+
* Raw VPinball Units (no scaling).
|
|
62
|
+
*/
|
|
63
|
+
Vpu: 0, "0": "Vpu",
|
|
64
|
+
/**
|
|
65
|
+
* Millimetres.
|
|
66
|
+
*/
|
|
67
|
+
Mm: 1, "1": "Mm",
|
|
68
|
+
/**
|
|
69
|
+
* Centimetres.
|
|
70
|
+
*/
|
|
71
|
+
Cm: 2, "2": "Cm",
|
|
72
|
+
/**
|
|
73
|
+
* Metres.
|
|
74
|
+
*/
|
|
75
|
+
M: 3, "3": "M",
|
|
76
|
+
});
|
|
77
|
+
|
|
3
78
|
/**
|
|
4
79
|
* Mesh data for a single primitive: positions, texture coordinates,
|
|
5
80
|
* normals and triangle indices, packed as flat typed arrays for direct
|
|
@@ -101,7 +176,7 @@ export class PrimitiveMesh {
|
|
|
101
176
|
if (Symbol.dispose) PrimitiveMesh.prototype[Symbol.dispose] = PrimitiveMesh.prototype.free;
|
|
102
177
|
|
|
103
178
|
/**
|
|
104
|
-
* @param {
|
|
179
|
+
* @param {VpxFileMap} files
|
|
105
180
|
* @param {Function | null} [callback]
|
|
106
181
|
* @returns {Uint8Array}
|
|
107
182
|
*/
|
|
@@ -115,10 +190,63 @@ export function assemble(files, callback) {
|
|
|
115
190
|
return v1;
|
|
116
191
|
}
|
|
117
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Export a whole table to a GLB (binary glTF 2.0) file.
|
|
195
|
+
*
|
|
196
|
+
* Takes the same extracted-file map `assemble` takes
|
|
197
|
+
* (`{ "/vpx/...": Uint8Array }`), so consumers holding a table as an
|
|
198
|
+
* extracted tree skip a full assemble/parse round trip; consumers with
|
|
199
|
+
* only `.vpx` bytes can call `extract` first.
|
|
200
|
+
*
|
|
201
|
+
* The output follows the glTF conventions: Y-up right-handed axes and
|
|
202
|
+
* meters, so it opens correctly in Blender and other glTF viewers with
|
|
203
|
+
* default settings. It contains the generated meshes for every part
|
|
204
|
+
* type, PBR materials from the VPX material list, embedded textures,
|
|
205
|
+
* and the three VPX view cameras (desktop / fullscreen / FSS).
|
|
206
|
+
*
|
|
207
|
+
* Sound entries (`/vpx/sounds.json` and `/vpx/sounds/*`) are ignored -
|
|
208
|
+
* the exporter never reads them, and skipping them keeps peak wasm
|
|
209
|
+
* memory down on sound-heavy tables. Passing a map without them works
|
|
210
|
+
* too.
|
|
211
|
+
* @param {VpxFileMap} files
|
|
212
|
+
* @param {GlbExportOptions | null} [options]
|
|
213
|
+
* @param {Function | null} [callback]
|
|
214
|
+
* @returns {Uint8Array}
|
|
215
|
+
*/
|
|
216
|
+
export function export_glb(files, options, callback) {
|
|
217
|
+
const ret = wasm.export_glb(files, isLikeNone(options) ? 0 : addToExternrefTable0(options), isLikeNone(callback) ? 0 : addToExternrefTable0(callback));
|
|
218
|
+
if (ret[3]) {
|
|
219
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
220
|
+
}
|
|
221
|
+
var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
|
|
222
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
|
|
223
|
+
return v1;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Export a whole table as a Wavefront OBJ with its MTL and, by
|
|
228
|
+
* default, the referenced textures. Takes the file map produced by
|
|
229
|
+
* `extract` and returns a file map relative to the export directory:
|
|
230
|
+
* `table.obj`, `table.mtl` and `images/*`.
|
|
231
|
+
*
|
|
232
|
+
* Sound entries are ignored like in `export_glb`.
|
|
233
|
+
* @param {VpxFileMap} files
|
|
234
|
+
* @param {ObjExportOptions | null} [options]
|
|
235
|
+
* @param {Function | null} [callback]
|
|
236
|
+
* @returns {ObjExportFileMap}
|
|
237
|
+
*/
|
|
238
|
+
export function export_obj(files, options, callback) {
|
|
239
|
+
const ret = wasm.export_obj(files, isLikeNone(options) ? 0 : addToExternrefTable0(options), isLikeNone(callback) ? 0 : addToExternrefTable0(callback));
|
|
240
|
+
if (ret[2]) {
|
|
241
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
242
|
+
}
|
|
243
|
+
return takeFromExternrefTable0(ret[0]);
|
|
244
|
+
}
|
|
245
|
+
|
|
118
246
|
/**
|
|
119
247
|
* @param {Uint8Array} data
|
|
120
248
|
* @param {Function | null} [callback]
|
|
121
|
-
* @returns {
|
|
249
|
+
* @returns {VpxFileMap}
|
|
122
250
|
*/
|
|
123
251
|
export function extract(data, callback) {
|
|
124
252
|
const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
|
|
@@ -164,6 +292,51 @@ export function init() {
|
|
|
164
292
|
wasm.init();
|
|
165
293
|
}
|
|
166
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Serialize a single mesh as a GLB (binary glTF 2.0) file.
|
|
297
|
+
*
|
|
298
|
+
* The GLB sibling of [`mesh_to_obj`], for exporting one primitive's
|
|
299
|
+
* mesh to DCC tools. There is no axis option: glTF mandates Y-up
|
|
300
|
+
* right-handed, so the vpx-internal input is always converted the same
|
|
301
|
+
* way the whole-table exporter converts it (Y-Z swap, winding
|
|
302
|
+
* reversed; texture coordinates pass through - glTF's UV origin
|
|
303
|
+
* matches vpx's, unlike OBJ's).
|
|
304
|
+
*
|
|
305
|
+
* `name` becomes the mesh/node name; pass an empty string to use
|
|
306
|
+
* `"object"`. Array requirements are the same as [`mesh_to_obj`].
|
|
307
|
+
*
|
|
308
|
+
* `options.unitScale` (default `1.0`) multiplies positions. A
|
|
309
|
+
* primitive's local mesh coordinates are arbitrary units (the table
|
|
310
|
+
* scales them by the primitive's Size at render), so no unit
|
|
311
|
+
* conversion is applied by default.
|
|
312
|
+
* @param {string} name
|
|
313
|
+
* @param {Float32Array} positions
|
|
314
|
+
* @param {Float32Array} tex_coords
|
|
315
|
+
* @param {Float32Array} normals
|
|
316
|
+
* @param {Uint32Array} indices
|
|
317
|
+
* @param {MeshGlbOptions | null} [options]
|
|
318
|
+
* @returns {Uint8Array}
|
|
319
|
+
*/
|
|
320
|
+
export function mesh_to_glb(name, positions, tex_coords, normals, indices, options) {
|
|
321
|
+
const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
322
|
+
const len0 = WASM_VECTOR_LEN;
|
|
323
|
+
const ptr1 = passArrayF32ToWasm0(positions, wasm.__wbindgen_malloc);
|
|
324
|
+
const len1 = WASM_VECTOR_LEN;
|
|
325
|
+
const ptr2 = passArrayF32ToWasm0(tex_coords, wasm.__wbindgen_malloc);
|
|
326
|
+
const len2 = WASM_VECTOR_LEN;
|
|
327
|
+
const ptr3 = passArrayF32ToWasm0(normals, wasm.__wbindgen_malloc);
|
|
328
|
+
const len3 = WASM_VECTOR_LEN;
|
|
329
|
+
const ptr4 = passArray32ToWasm0(indices, wasm.__wbindgen_malloc);
|
|
330
|
+
const len4 = WASM_VECTOR_LEN;
|
|
331
|
+
const ret = wasm.mesh_to_glb(ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, isLikeNone(options) ? 0 : addToExternrefTable0(options));
|
|
332
|
+
if (ret[3]) {
|
|
333
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
334
|
+
}
|
|
335
|
+
var v6 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
|
|
336
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
|
|
337
|
+
return v6;
|
|
338
|
+
}
|
|
339
|
+
|
|
167
340
|
/**
|
|
168
341
|
* Serialize a mesh as a Wavefront OBJ.
|
|
169
342
|
*
|
|
@@ -173,25 +346,36 @@ export function init() {
|
|
|
173
346
|
* normals.len() / 3`); index values must be valid 0-based offsets into
|
|
174
347
|
* that vertex array.
|
|
175
348
|
*
|
|
176
|
-
* `
|
|
177
|
-
*
|
|
349
|
+
* `options.axes` is the symmetric inverse of the same option on
|
|
350
|
+
* [`obj_to_mesh`]: the input is always vpx-internal data, `axes` names
|
|
351
|
+
* the convention to write the OBJ in.
|
|
352
|
+
*
|
|
353
|
+
* - [`AxisConvention::ZDownRightHanded`] (the default; matches
|
|
354
|
+
* `extract`'s write path, the old `convert_to_left_handed = true`):
|
|
355
|
+
* vertex and normal Z are negated, V is flipped (`obj_v = 1 -
|
|
356
|
+
* vpx_tv`) and per-triangle corner order is reversed. The result is a
|
|
357
|
+
* vpinball-format OBJ that `assemble` (or `obj_to_mesh` with the same
|
|
358
|
+
* convention) reads back identically.
|
|
359
|
+
* - [`AxisConvention::YUpRightHanded`]: Y and Z are swapped, V is
|
|
360
|
+
* flipped and winding is reversed; the OBJ opens upright in Blender
|
|
361
|
+
* with default import settings.
|
|
362
|
+
* - [`AxisConvention::ZUpLeftHanded`] (the old `convert_to_left_handed
|
|
363
|
+
* = false`): the vpx-internal data is written out verbatim, no
|
|
364
|
+
* transforms applied.
|
|
178
365
|
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
* that `assemble` (or `obj_to_mesh(.., true)`) reads back identically.
|
|
184
|
-
* - `false`: the input vpx-internal data is written out verbatim, no
|
|
185
|
-
* transforms applied. Round-trips with `obj_to_mesh(.., false)`.
|
|
366
|
+
* `options.unitScale` (default `1.0`) multiplies positions before the
|
|
367
|
+
* axis mapping. Normals and texture coordinates are never scaled.
|
|
368
|
+
* Round-trips through `obj_to_mesh` with the same convention and scale
|
|
369
|
+
* `1.0 / unitScale`.
|
|
186
370
|
* @param {string} name
|
|
187
371
|
* @param {Float32Array} positions
|
|
188
372
|
* @param {Float32Array} tex_coords
|
|
189
373
|
* @param {Float32Array} normals
|
|
190
374
|
* @param {Uint32Array} indices
|
|
191
|
-
* @param {
|
|
375
|
+
* @param {MeshIoOptions | null} [options]
|
|
192
376
|
* @returns {Uint8Array}
|
|
193
377
|
*/
|
|
194
|
-
export function mesh_to_obj(name, positions, tex_coords, normals, indices,
|
|
378
|
+
export function mesh_to_obj(name, positions, tex_coords, normals, indices, options) {
|
|
195
379
|
const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
196
380
|
const len0 = WASM_VECTOR_LEN;
|
|
197
381
|
const ptr1 = passArrayF32ToWasm0(positions, wasm.__wbindgen_malloc);
|
|
@@ -202,7 +386,7 @@ export function mesh_to_obj(name, positions, tex_coords, normals, indices, conve
|
|
|
202
386
|
const len3 = WASM_VECTOR_LEN;
|
|
203
387
|
const ptr4 = passArray32ToWasm0(indices, wasm.__wbindgen_malloc);
|
|
204
388
|
const len4 = WASM_VECTOR_LEN;
|
|
205
|
-
const ret = wasm.mesh_to_obj(ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4,
|
|
389
|
+
const ret = wasm.mesh_to_obj(ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, isLikeNone(options) ? 0 : addToExternrefTable0(options));
|
|
206
390
|
if (ret[3]) {
|
|
207
391
|
throw takeFromExternrefTable0(ret[2]);
|
|
208
392
|
}
|
|
@@ -218,27 +402,37 @@ export function mesh_to_obj(name, positions, tex_coords, normals, indices, conve
|
|
|
218
402
|
* anything in between): n-gons are fan-triangulated and `(position, uv,
|
|
219
403
|
* normal)` corners are deduplicated so the result is renderer-ready.
|
|
220
404
|
*
|
|
221
|
-
* `
|
|
222
|
-
*
|
|
223
|
-
* vpinball mesh-import dialog):
|
|
405
|
+
* `options.axes` names the convention the OBJ data is in; the returned
|
|
406
|
+
* mesh is always in vpx-internal convention:
|
|
224
407
|
*
|
|
225
|
-
* - `
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
408
|
+
* - [`AxisConvention::ZDownRightHanded`] (the default; matches
|
|
409
|
+
* `assemble`'s read path and vpinball's mesh-import dialog with
|
|
410
|
+
* "Convert coordinate system" checked, the old `convert_to_left_handed
|
|
411
|
+
* = true`): vertex and normal Z are negated, V is flipped (`vpx_tv =
|
|
412
|
+
* 1 - obj_v`) and the per-triangle corner order is reversed. This path
|
|
413
|
+
* also honors the `# vpx <hex>` byte-preservation comments, so
|
|
414
|
+
* vpinball-format OBJs from `extract` reproduce the original vpx
|
|
415
|
+
* values bit-for-bit.
|
|
416
|
+
* - [`AxisConvention::YUpRightHanded`] (Blender / DCC default export
|
|
417
|
+
* settings): Y and Z are swapped, V is flipped and winding is
|
|
418
|
+
* reversed.
|
|
419
|
+
* - [`AxisConvention::ZUpLeftHanded`] (the old `convert_to_left_handed
|
|
420
|
+
* = false`): the input is assumed to already hold vpx-internal values
|
|
421
|
+
* (e.g. produced by a previous `mesh_to_obj` with the same
|
|
422
|
+
* convention). No transforms; values pass through verbatim.
|
|
423
|
+
*
|
|
424
|
+
* `options.unitScale` (default `1.0`) multiplies positions after the
|
|
425
|
+
* axis mapping. Normals and texture coordinates are never scaled. A
|
|
426
|
+
* mesh exported through `mesh_to_obj` with scale `k` reads back with
|
|
427
|
+
* scale `1.0 / k`.
|
|
234
428
|
* @param {Uint8Array} data
|
|
235
|
-
* @param {
|
|
429
|
+
* @param {MeshIoOptions | null} [options]
|
|
236
430
|
* @returns {PrimitiveMesh}
|
|
237
431
|
*/
|
|
238
|
-
export function obj_to_mesh(data,
|
|
432
|
+
export function obj_to_mesh(data, options) {
|
|
239
433
|
const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
|
|
240
434
|
const len0 = WASM_VECTOR_LEN;
|
|
241
|
-
const ret = wasm.obj_to_mesh(ptr0, len0,
|
|
435
|
+
const ret = wasm.obj_to_mesh(ptr0, len0, isLikeNone(options) ? 0 : addToExternrefTable0(options));
|
|
242
436
|
if (ret[2]) {
|
|
243
437
|
throw takeFromExternrefTable0(ret[1]);
|
|
244
438
|
}
|
|
@@ -251,6 +445,22 @@ function __wbg_get_imports() {
|
|
|
251
445
|
const ret = Error(getStringFromWasm0(arg0, arg1));
|
|
252
446
|
return ret;
|
|
253
447
|
},
|
|
448
|
+
__wbg_Number_3890faa6d3ff057d: function(arg0) {
|
|
449
|
+
const ret = Number(arg0);
|
|
450
|
+
return ret;
|
|
451
|
+
},
|
|
452
|
+
__wbg_String_8564e559799eccda: function(arg0, arg1) {
|
|
453
|
+
const ret = String(arg1);
|
|
454
|
+
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
455
|
+
const len1 = WASM_VECTOR_LEN;
|
|
456
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
457
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
458
|
+
},
|
|
459
|
+
__wbg___wbindgen_boolean_get_c9c83ebd41b34df3: function(arg0) {
|
|
460
|
+
const v = arg0;
|
|
461
|
+
const ret = typeof(v) === 'boolean' ? v : undefined;
|
|
462
|
+
return isLikeNone(ret) ? 0xFFFFFF : ret ? 1 : 0;
|
|
463
|
+
},
|
|
254
464
|
__wbg___wbindgen_debug_string_a57024b9c6e4a48b: function(arg0, arg1) {
|
|
255
465
|
const ret = debugString(arg1);
|
|
256
466
|
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
@@ -258,6 +468,33 @@ function __wbg_get_imports() {
|
|
|
258
468
|
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
259
469
|
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
260
470
|
},
|
|
471
|
+
__wbg___wbindgen_in_ac983077f137f2e6: function(arg0, arg1) {
|
|
472
|
+
const ret = arg0 in arg1;
|
|
473
|
+
return ret;
|
|
474
|
+
},
|
|
475
|
+
__wbg___wbindgen_is_null_7d13f41e1a2d5140: function(arg0) {
|
|
476
|
+
const ret = arg0 === null;
|
|
477
|
+
return ret;
|
|
478
|
+
},
|
|
479
|
+
__wbg___wbindgen_is_object_a2790eb24c211ea0: function(arg0) {
|
|
480
|
+
const val = arg0;
|
|
481
|
+
const ret = typeof(val) === 'object' && val !== null;
|
|
482
|
+
return ret;
|
|
483
|
+
},
|
|
484
|
+
__wbg___wbindgen_is_undefined_6cff064c44e0d823: function(arg0) {
|
|
485
|
+
const ret = arg0 === undefined;
|
|
486
|
+
return ret;
|
|
487
|
+
},
|
|
488
|
+
__wbg___wbindgen_jsval_loose_eq_acf2776254a8d832: function(arg0, arg1) {
|
|
489
|
+
const ret = arg0 == arg1;
|
|
490
|
+
return ret;
|
|
491
|
+
},
|
|
492
|
+
__wbg___wbindgen_number_get_136b9679cab35cfb: function(arg0, arg1) {
|
|
493
|
+
const obj = arg1;
|
|
494
|
+
const ret = typeof(obj) === 'number' ? obj : undefined;
|
|
495
|
+
getDataViewMemory0().setFloat64(arg0 + 8 * 1, isLikeNone(ret) ? 0 : ret, true);
|
|
496
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
|
|
497
|
+
},
|
|
261
498
|
__wbg___wbindgen_string_get_d154f1e671052120: function(arg0, arg1) {
|
|
262
499
|
const obj = arg1;
|
|
263
500
|
const ret = typeof(obj) === 'string' ? obj : undefined;
|
|
@@ -292,6 +529,34 @@ function __wbg_get_imports() {
|
|
|
292
529
|
const ret = arg0[arg1 >>> 0];
|
|
293
530
|
return ret;
|
|
294
531
|
},
|
|
532
|
+
__wbg_get_with_ref_key_6412cf3094599694: function(arg0, arg1) {
|
|
533
|
+
const ret = arg0[arg1];
|
|
534
|
+
return ret;
|
|
535
|
+
},
|
|
536
|
+
__wbg_instanceof_ArrayBuffer_993d02d2d254cad1: function(arg0) {
|
|
537
|
+
let result;
|
|
538
|
+
try {
|
|
539
|
+
result = arg0 instanceof ArrayBuffer;
|
|
540
|
+
} catch (_) {
|
|
541
|
+
result = false;
|
|
542
|
+
}
|
|
543
|
+
const ret = result;
|
|
544
|
+
return ret;
|
|
545
|
+
},
|
|
546
|
+
__wbg_instanceof_Uint8Array_f935dbb0aa7cdeed: function(arg0) {
|
|
547
|
+
let result;
|
|
548
|
+
try {
|
|
549
|
+
result = arg0 instanceof Uint8Array;
|
|
550
|
+
} catch (_) {
|
|
551
|
+
result = false;
|
|
552
|
+
}
|
|
553
|
+
const ret = result;
|
|
554
|
+
return ret;
|
|
555
|
+
},
|
|
556
|
+
__wbg_isSafeInteger_f3d6cd19ccfe4512: function(arg0) {
|
|
557
|
+
const ret = Number.isSafeInteger(arg0);
|
|
558
|
+
return ret;
|
|
559
|
+
},
|
|
295
560
|
__wbg_keys_ec7f8c0c2370d91d: function(arg0) {
|
|
296
561
|
const ret = Object.keys(arg0);
|
|
297
562
|
return ret;
|
|
@@ -308,6 +573,10 @@ function __wbg_get_imports() {
|
|
|
308
573
|
const ret = new Error();
|
|
309
574
|
return ret;
|
|
310
575
|
},
|
|
576
|
+
__wbg_new_77cc4f4f472aeb81: function(arg0) {
|
|
577
|
+
const ret = new Uint8Array(arg0);
|
|
578
|
+
return ret;
|
|
579
|
+
},
|
|
311
580
|
__wbg_new_ebe3e0f6837f0879: function() {
|
|
312
581
|
const ret = new Object();
|
|
313
582
|
return ret;
|
package/vpin_bg.wasm
CHANGED
|
Binary file
|
package/vpin_bg.wasm.d.ts
CHANGED
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
export const memory: WebAssembly.Memory;
|
|
4
4
|
export const __wbg_primitivemesh_free: (a: number, b: number) => void;
|
|
5
5
|
export const assemble: (a: any, b: number) => [number, number, number, number];
|
|
6
|
+
export const export_glb: (a: any, b: number, c: number) => [number, number, number, number];
|
|
7
|
+
export const export_obj: (a: any, b: number, c: number) => [number, number, number];
|
|
6
8
|
export const extract: (a: number, b: number, c: number) => [number, number, number];
|
|
7
9
|
export const generate_builtin_primitive: (a: number, b: number) => [number, number, number];
|
|
10
|
+
export const mesh_to_glb: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number) => [number, number, number, number];
|
|
8
11
|
export const mesh_to_obj: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number) => [number, number, number, number];
|
|
9
12
|
export const obj_to_mesh: (a: number, b: number, c: number) => [number, number, number];
|
|
10
13
|
export const primitivemesh_indices: (a: number) => any;
|