@forgeax/engine-geometry 0.1.20 → 0.1.21
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 +12 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/mesh-builder.integration.test.d.ts +2 -0
- package/dist/__tests__/mesh-builder.integration.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-builder.unit.test.d.ts +2 -0
- package/dist/__tests__/mesh-builder.unit.test.d.ts.map +1 -0
- package/dist/assets/mesh-binary.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +366 -2
- package/dist/index.mjs.map +1 -1
- package/dist/mesh-builder.d.ts +28 -0
- package/dist/mesh-builder.d.ts.map +1 -0
- package/package.json +5 -5
- package/src/__tests__/mesh-builder.integration.test.ts +58 -0
- package/src/__tests__/mesh-builder.unit.test.ts +96 -0
- package/src/assets/mesh-binary.ts +12 -1
- package/src/index.ts +6 -1
- package/src/mesh-builder.ts +457 -0
package/dist/index.mjs
CHANGED
|
@@ -1114,6 +1114,9 @@ function normalizeMeshPayload(payload, refs) {
|
|
|
1114
1114
|
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) return void 0;
|
|
1115
1115
|
const source = payload;
|
|
1116
1116
|
if (source.kind !== "mesh") return void 0;
|
|
1117
|
+
const sourceAttributes = source.attributes !== null && typeof source.attributes === "object" ? source.attributes : void 0;
|
|
1118
|
+
const projection = sourceAttributes === void 0 ? void 0 : deriveVertexLayoutProjection(sourceAttributes);
|
|
1119
|
+
const floatsPerVertex = projection === void 0 || projection.attributes.length === 0 ? PROCEDURAL_FLOATS_PER_VERTEX : projection.arrayStride / Float32Array.BYTES_PER_ELEMENT;
|
|
1117
1120
|
return meshFromParts(
|
|
1118
1121
|
{
|
|
1119
1122
|
vertices: source.vertices,
|
|
@@ -1124,7 +1127,7 @@ function normalizeMeshPayload(payload, refs) {
|
|
|
1124
1127
|
...Array.isArray(source.materialSlots) ? { materialSlots: source.materialSlots } : {},
|
|
1125
1128
|
...source.morphTargets === void 0 ? {} : { morphTargets: source.morphTargets },
|
|
1126
1129
|
...source.morphWeights === void 0 ? {} : { morphWeights: source.morphWeights },
|
|
1127
|
-
floatsPerVertex
|
|
1130
|
+
floatsPerVertex
|
|
1128
1131
|
},
|
|
1129
1132
|
refs
|
|
1130
1133
|
);
|
|
@@ -2325,6 +2328,367 @@ function createEdgesGeometry(source, thresholdAngleDegrees = DEFAULT_THRESHOLD_D
|
|
|
2325
2328
|
);
|
|
2326
2329
|
return lineMesh(edges.map(({ a, b }) => ({ a, b })));
|
|
2327
2330
|
}
|
|
2331
|
+
var ATTRIBUTE_KEYS = [
|
|
2332
|
+
"position",
|
|
2333
|
+
"normal",
|
|
2334
|
+
"uv",
|
|
2335
|
+
"tangent",
|
|
2336
|
+
"skinIndex",
|
|
2337
|
+
"skinWeight",
|
|
2338
|
+
"uv1",
|
|
2339
|
+
"uv2",
|
|
2340
|
+
"uv3",
|
|
2341
|
+
"uv4",
|
|
2342
|
+
"uv5",
|
|
2343
|
+
"uv6",
|
|
2344
|
+
"uv7",
|
|
2345
|
+
"color"
|
|
2346
|
+
];
|
|
2347
|
+
var ATTRIBUTE_COMPONENTS = {
|
|
2348
|
+
position: 3,
|
|
2349
|
+
normal: 3,
|
|
2350
|
+
uv: 2,
|
|
2351
|
+
tangent: 4,
|
|
2352
|
+
skinIndex: 4,
|
|
2353
|
+
skinWeight: 4,
|
|
2354
|
+
uv1: 2,
|
|
2355
|
+
uv2: 2,
|
|
2356
|
+
uv3: 2,
|
|
2357
|
+
uv4: 2,
|
|
2358
|
+
uv5: 2,
|
|
2359
|
+
uv6: 2,
|
|
2360
|
+
uv7: 2,
|
|
2361
|
+
color: 4
|
|
2362
|
+
};
|
|
2363
|
+
var TOPOLOGIES = [
|
|
2364
|
+
"point-list",
|
|
2365
|
+
"line-list",
|
|
2366
|
+
"line-strip",
|
|
2367
|
+
"triangle-list",
|
|
2368
|
+
"triangle-strip"
|
|
2369
|
+
];
|
|
2370
|
+
function failure(field, value, reason) {
|
|
2371
|
+
return err(
|
|
2372
|
+
new AssetError({
|
|
2373
|
+
code: "asset-invalid-value",
|
|
2374
|
+
expected: `valid MeshBuilder ${field}: ${reason}`,
|
|
2375
|
+
hint: ASSET_ERROR_HINTS["asset-invalid-value"],
|
|
2376
|
+
detail: { field, value, reason }
|
|
2377
|
+
})
|
|
2378
|
+
);
|
|
2379
|
+
}
|
|
2380
|
+
function sourceView(key, value) {
|
|
2381
|
+
if (key === "skinIndex") {
|
|
2382
|
+
if (value instanceof Uint16Array) return value;
|
|
2383
|
+
if (value instanceof ArrayBuffer && value.byteLength % Uint16Array.BYTES_PER_ELEMENT === 0) {
|
|
2384
|
+
return new Uint16Array(value);
|
|
2385
|
+
}
|
|
2386
|
+
return void 0;
|
|
2387
|
+
}
|
|
2388
|
+
if (value instanceof Float32Array) return value;
|
|
2389
|
+
if (value instanceof ArrayBuffer && value.byteLength % Float32Array.BYTES_PER_ELEMENT === 0) {
|
|
2390
|
+
return new Float32Array(value);
|
|
2391
|
+
}
|
|
2392
|
+
return void 0;
|
|
2393
|
+
}
|
|
2394
|
+
function cloneAttribute(key, value) {
|
|
2395
|
+
const view = sourceView(key, value);
|
|
2396
|
+
if (view === void 0) return void 0;
|
|
2397
|
+
return view.slice();
|
|
2398
|
+
}
|
|
2399
|
+
function attributeKeys(attributes) {
|
|
2400
|
+
return ATTRIBUTE_KEYS.filter((key) => attributes[key] !== void 0);
|
|
2401
|
+
}
|
|
2402
|
+
function appendArray(target, source) {
|
|
2403
|
+
if (target instanceof Uint16Array && source instanceof Uint16Array) {
|
|
2404
|
+
const output = new Uint16Array(target.length + source.length);
|
|
2405
|
+
output.set(target, 0);
|
|
2406
|
+
output.set(source, target.length);
|
|
2407
|
+
return output;
|
|
2408
|
+
}
|
|
2409
|
+
if (target instanceof Float32Array && source instanceof Float32Array) {
|
|
2410
|
+
const output = new Float32Array(target.length + source.length);
|
|
2411
|
+
output.set(target, 0);
|
|
2412
|
+
output.set(source, target.length);
|
|
2413
|
+
return output;
|
|
2414
|
+
}
|
|
2415
|
+
return target;
|
|
2416
|
+
}
|
|
2417
|
+
function copySlots(slots) {
|
|
2418
|
+
return (slots ?? [{ slotName: "Default" }]).map((slot) => ({
|
|
2419
|
+
slotName: slot.slotName,
|
|
2420
|
+
...slot.sourceKey === void 0 ? {} : { sourceKey: slot.sourceKey },
|
|
2421
|
+
...slot.defaultMaterial === void 0 ? {} : { defaultMaterial: slot.defaultMaterial }
|
|
2422
|
+
}));
|
|
2423
|
+
}
|
|
2424
|
+
function validateAttributeBatch(attributes) {
|
|
2425
|
+
const keys = attributeKeys(attributes);
|
|
2426
|
+
if (keys.length === 0)
|
|
2427
|
+
return failure("attributes", [], "at least one canonical attribute is required");
|
|
2428
|
+
const position = attributes.position;
|
|
2429
|
+
if (position === void 0)
|
|
2430
|
+
return failure("attributes.position", void 0, "position is required");
|
|
2431
|
+
const positionView = sourceView("position", position);
|
|
2432
|
+
if (positionView === void 0) {
|
|
2433
|
+
return failure(
|
|
2434
|
+
"attributes.position",
|
|
2435
|
+
typeof position,
|
|
2436
|
+
"position must use Float32Array or ArrayBuffer"
|
|
2437
|
+
);
|
|
2438
|
+
}
|
|
2439
|
+
if (positionView.length === 0 || positionView.length % 3 !== 0) {
|
|
2440
|
+
return failure(
|
|
2441
|
+
"attributes.position",
|
|
2442
|
+
positionView.length,
|
|
2443
|
+
"position cardinality must be a non-zero multiple of 3"
|
|
2444
|
+
);
|
|
2445
|
+
}
|
|
2446
|
+
const vertexCount = positionView.length / 3;
|
|
2447
|
+
for (const key of keys) {
|
|
2448
|
+
const value = attributes[key];
|
|
2449
|
+
if (value === void 0) continue;
|
|
2450
|
+
const view = sourceView(key, value);
|
|
2451
|
+
if (view === void 0) {
|
|
2452
|
+
return failure(
|
|
2453
|
+
key,
|
|
2454
|
+
typeof value,
|
|
2455
|
+
key === "skinIndex" ? "storage must be Uint16Array" : "storage must be Float32Array"
|
|
2456
|
+
);
|
|
2457
|
+
}
|
|
2458
|
+
const expectedLength = vertexCount * ATTRIBUTE_COMPONENTS[key];
|
|
2459
|
+
if (view.length !== expectedLength) {
|
|
2460
|
+
return failure(key, view.length, `cardinality must be ${expectedLength}`);
|
|
2461
|
+
}
|
|
2462
|
+
for (let elementIndex = 0; elementIndex < view.length; elementIndex += 1) {
|
|
2463
|
+
const valueAt = view[elementIndex];
|
|
2464
|
+
if (valueAt === void 0 || !Number.isFinite(valueAt)) {
|
|
2465
|
+
return failure(key, valueAt, `${key}[${elementIndex}] must be finite`);
|
|
2466
|
+
}
|
|
2467
|
+
if (key === "skinIndex" && (!Number.isInteger(valueAt) || valueAt < 0 || valueAt > 65535)) {
|
|
2468
|
+
return failure(key, valueAt, `${key}[${elementIndex}] must be an integer in [0, 65535]`);
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
return ok({ keys, vertexCount });
|
|
2473
|
+
}
|
|
2474
|
+
function validateSlots(slots) {
|
|
2475
|
+
if (slots.length === 0)
|
|
2476
|
+
return failure("materialSlots", slots.length, "at least one material slot is required");
|
|
2477
|
+
const names = /* @__PURE__ */ new Set();
|
|
2478
|
+
for (let index = 0; index < slots.length; index += 1) {
|
|
2479
|
+
const slot = slots[index];
|
|
2480
|
+
const name = slot?.slotName.trim() ?? "";
|
|
2481
|
+
if (name.length === 0 || names.has(name)) {
|
|
2482
|
+
return failure(`materialSlots[${index}].slotName`, name, "must be non-empty and unique");
|
|
2483
|
+
}
|
|
2484
|
+
names.add(name);
|
|
2485
|
+
}
|
|
2486
|
+
return ok(void 0);
|
|
2487
|
+
}
|
|
2488
|
+
function completedSubmeshes(requested, vertexCount, indexCount, materialSlotCount) {
|
|
2489
|
+
const source = requested.length === 0 ? [
|
|
2490
|
+
{
|
|
2491
|
+
indexOffset: 0,
|
|
2492
|
+
indexCount,
|
|
2493
|
+
vertexCount,
|
|
2494
|
+
topology: "triangle-list",
|
|
2495
|
+
materialSlot: 0
|
|
2496
|
+
}
|
|
2497
|
+
] : requested;
|
|
2498
|
+
const output = [];
|
|
2499
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
2500
|
+
const candidate = source[index];
|
|
2501
|
+
if (candidate === void 0)
|
|
2502
|
+
return failure(`submeshes[${index}]`, void 0, "entry is required");
|
|
2503
|
+
const indexOffset = candidate.indexOffset ?? 0;
|
|
2504
|
+
const submeshIndexCount = candidate.indexCount ?? (indexCount > 0 ? indexCount : 0);
|
|
2505
|
+
const submeshVertexCount = candidate.vertexCount ?? vertexCount;
|
|
2506
|
+
const topology = candidate.topology ?? "triangle-list";
|
|
2507
|
+
const materialSlot = candidate.materialSlot ?? index;
|
|
2508
|
+
if (!TOPOLOGIES.includes(topology)) {
|
|
2509
|
+
return failure(
|
|
2510
|
+
`submeshes[${index}].topology`,
|
|
2511
|
+
topology,
|
|
2512
|
+
"must be a WebGPU primitive topology"
|
|
2513
|
+
);
|
|
2514
|
+
}
|
|
2515
|
+
if (!Number.isInteger(indexOffset) || indexOffset < 0 || !Number.isInteger(submeshIndexCount) || submeshIndexCount < 0 || !Number.isInteger(submeshVertexCount) || submeshVertexCount < 0 || submeshVertexCount > vertexCount || !Number.isInteger(materialSlot) || materialSlot < 0 || materialSlot >= materialSlotCount) {
|
|
2516
|
+
return failure(
|
|
2517
|
+
`submeshes[${index}]`,
|
|
2518
|
+
JSON.stringify(candidate),
|
|
2519
|
+
"range and material slot are invalid"
|
|
2520
|
+
);
|
|
2521
|
+
}
|
|
2522
|
+
if (indexCount === 0 && (indexOffset !== 0 || submeshIndexCount !== 0)) {
|
|
2523
|
+
return failure(
|
|
2524
|
+
`submeshes[${index}]`,
|
|
2525
|
+
JSON.stringify(candidate),
|
|
2526
|
+
"non-indexed meshes use indexOffset=0 and indexCount=0"
|
|
2527
|
+
);
|
|
2528
|
+
}
|
|
2529
|
+
if (indexCount > 0 && indexOffset + submeshIndexCount > indexCount) {
|
|
2530
|
+
return failure(
|
|
2531
|
+
`submeshes[${index}]`,
|
|
2532
|
+
JSON.stringify(candidate),
|
|
2533
|
+
"index range exceeds the accumulated index buffer"
|
|
2534
|
+
);
|
|
2535
|
+
}
|
|
2536
|
+
if (indexCount === 0 && (topology === "line-strip" || topology === "triangle-strip")) {
|
|
2537
|
+
return failure(
|
|
2538
|
+
`submeshes[${index}].topology`,
|
|
2539
|
+
topology,
|
|
2540
|
+
"strip topology requires an index buffer"
|
|
2541
|
+
);
|
|
2542
|
+
}
|
|
2543
|
+
output.push({
|
|
2544
|
+
indexOffset,
|
|
2545
|
+
indexCount: submeshIndexCount,
|
|
2546
|
+
vertexCount: submeshVertexCount,
|
|
2547
|
+
topology,
|
|
2548
|
+
materialSlot
|
|
2549
|
+
});
|
|
2550
|
+
}
|
|
2551
|
+
return ok(Object.freeze(output));
|
|
2552
|
+
}
|
|
2553
|
+
function createMeshBuilder(options = {}) {
|
|
2554
|
+
const attributes = {};
|
|
2555
|
+
const indices = [];
|
|
2556
|
+
const submeshes = [];
|
|
2557
|
+
const materialSlots = copySlots(options.materialSlots);
|
|
2558
|
+
const appendVertices = (batch) => {
|
|
2559
|
+
const checked = validateAttributeBatch(batch);
|
|
2560
|
+
if (!checked.ok) return checked;
|
|
2561
|
+
const incomingKeys = checked.value.keys;
|
|
2562
|
+
const existingKeys = ATTRIBUTE_KEYS.filter((key) => attributes[key] !== void 0);
|
|
2563
|
+
if (existingKeys.length > 0 && existingKeys.join("|") !== incomingKeys.join("|")) {
|
|
2564
|
+
return failure(
|
|
2565
|
+
"attributes",
|
|
2566
|
+
incomingKeys.join(","),
|
|
2567
|
+
"every appended batch must carry the same canonical keys"
|
|
2568
|
+
);
|
|
2569
|
+
}
|
|
2570
|
+
for (const key of incomingKeys) {
|
|
2571
|
+
const value = batch[key];
|
|
2572
|
+
if (value === void 0) continue;
|
|
2573
|
+
const cloned = cloneAttribute(key, value);
|
|
2574
|
+
if (cloned === void 0) return failure(key, typeof value, "storage could not be cloned");
|
|
2575
|
+
const previous = attributes[key];
|
|
2576
|
+
attributes[key] = previous === void 0 ? cloned : appendArray(previous, cloned);
|
|
2577
|
+
}
|
|
2578
|
+
return ok(void 0);
|
|
2579
|
+
};
|
|
2580
|
+
const appendIndices = (batch) => {
|
|
2581
|
+
for (let index = 0; index < batch.length; index += 1) {
|
|
2582
|
+
const value = Number(batch[index]);
|
|
2583
|
+
if (!Number.isInteger(value) || value < 0 || value > 4294967295) {
|
|
2584
|
+
return failure("indices", value, `indices[${index}] must be an integer in [0, 2^32-1]`);
|
|
2585
|
+
}
|
|
2586
|
+
indices.push(value);
|
|
2587
|
+
}
|
|
2588
|
+
return ok(void 0);
|
|
2589
|
+
};
|
|
2590
|
+
const addSubmesh = (submesh) => {
|
|
2591
|
+
if (submesh === null || typeof submesh !== "object") {
|
|
2592
|
+
return failure("submeshes", submesh, "entry must be an object");
|
|
2593
|
+
}
|
|
2594
|
+
submeshes.push({ ...submesh });
|
|
2595
|
+
return ok(void 0);
|
|
2596
|
+
};
|
|
2597
|
+
const build = () => {
|
|
2598
|
+
const source = attributes;
|
|
2599
|
+
const checked = validateAttributeBatch(source);
|
|
2600
|
+
if (!checked.ok) return checked;
|
|
2601
|
+
const slotCheck = validateSlots(materialSlots);
|
|
2602
|
+
if (!slotCheck.ok) return slotCheck;
|
|
2603
|
+
const vertexCount = checked.value.vertexCount;
|
|
2604
|
+
const position = source.position;
|
|
2605
|
+
if (position === void 0)
|
|
2606
|
+
return failure("attributes.position", void 0, "position is required");
|
|
2607
|
+
const positionView = sourceView("position", position);
|
|
2608
|
+
if (!(positionView instanceof Float32Array)) {
|
|
2609
|
+
return failure("attributes.position", typeof position, "position storage is invalid");
|
|
2610
|
+
}
|
|
2611
|
+
let maxIndex = 0;
|
|
2612
|
+
for (const value of indices) maxIndex = Math.max(maxIndex, value);
|
|
2613
|
+
const indexArray2 = indices.length === 0 ? void 0 : maxIndex <= 65535 ? new Uint16Array(indices) : new Uint32Array(indices);
|
|
2614
|
+
if (indexArray2 !== void 0) {
|
|
2615
|
+
for (let index = 0; index < indexArray2.length; index += 1) {
|
|
2616
|
+
const value = indexArray2[index];
|
|
2617
|
+
if (value === void 0 || value >= vertexCount) {
|
|
2618
|
+
return failure(
|
|
2619
|
+
"indices",
|
|
2620
|
+
value ?? -1,
|
|
2621
|
+
`indices[${index}] must be less than vertexCount (${vertexCount})`
|
|
2622
|
+
);
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
const packed = packInterleavedVertexAttributes(source, vertexCount);
|
|
2627
|
+
if (!packed.ok) return packed;
|
|
2628
|
+
const ranges = completedSubmeshes(
|
|
2629
|
+
submeshes,
|
|
2630
|
+
vertexCount,
|
|
2631
|
+
indexArray2?.length ?? 0,
|
|
2632
|
+
materialSlots.length
|
|
2633
|
+
);
|
|
2634
|
+
if (!ranges.ok) return ranges;
|
|
2635
|
+
const aabb = box3.fromPositions(box3.create(), positionView);
|
|
2636
|
+
const copiedAttributes = {};
|
|
2637
|
+
for (const key of checked.value.keys) {
|
|
2638
|
+
const value = source[key];
|
|
2639
|
+
if (value === void 0) continue;
|
|
2640
|
+
const cloned = cloneAttribute(key, value);
|
|
2641
|
+
if (cloned === void 0) return failure(key, typeof value, "storage could not be cloned");
|
|
2642
|
+
if (key === "skinIndex") {
|
|
2643
|
+
if (!(cloned instanceof Uint16Array)) {
|
|
2644
|
+
return failure(key, typeof value, "skinIndex storage must be Uint16Array");
|
|
2645
|
+
}
|
|
2646
|
+
copiedAttributes.skinIndex = cloned;
|
|
2647
|
+
} else {
|
|
2648
|
+
if (!(cloned instanceof Float32Array)) {
|
|
2649
|
+
return failure(key, typeof value, `${key} storage must be Float32Array`);
|
|
2650
|
+
}
|
|
2651
|
+
copiedAttributes[key] = cloned;
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
const mesh = {
|
|
2655
|
+
kind: "mesh",
|
|
2656
|
+
vertices: packed.value.vertices.slice(),
|
|
2657
|
+
...indexArray2 === void 0 ? {} : { indices: indexArray2.slice() },
|
|
2658
|
+
attributes: copiedAttributes,
|
|
2659
|
+
aabb: Float32Array.from(aabb),
|
|
2660
|
+
submeshes: ranges.value,
|
|
2661
|
+
materialSlots: Object.freeze(materialSlots.map((slot) => ({ ...slot })))
|
|
2662
|
+
};
|
|
2663
|
+
return ok(Object.freeze(mesh));
|
|
2664
|
+
};
|
|
2665
|
+
if (options.attributes !== void 0) {
|
|
2666
|
+
const result = appendVertices(options.attributes);
|
|
2667
|
+
if (!result.ok) {
|
|
2668
|
+
const constructionError = result.error;
|
|
2669
|
+
return {
|
|
2670
|
+
appendVertices,
|
|
2671
|
+
appendIndices,
|
|
2672
|
+
addSubmesh,
|
|
2673
|
+
build: () => err(constructionError)
|
|
2674
|
+
};
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
if (options.indices !== void 0) {
|
|
2678
|
+
const result = appendIndices(options.indices);
|
|
2679
|
+
if (!result.ok) {
|
|
2680
|
+
const constructionError = result.error;
|
|
2681
|
+
return {
|
|
2682
|
+
appendVertices,
|
|
2683
|
+
appendIndices,
|
|
2684
|
+
addSubmesh,
|
|
2685
|
+
build: () => err(constructionError)
|
|
2686
|
+
};
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
for (const submesh of options.submeshes ?? []) submeshes.push({ ...submesh });
|
|
2690
|
+
return { appendVertices, appendIndices, addSubmesh, build };
|
|
2691
|
+
}
|
|
2328
2692
|
var PATCHES = new Uint16Array([
|
|
2329
2693
|
0,
|
|
2330
2694
|
1,
|
|
@@ -3901,6 +4265,6 @@ function createTorusGeometry(radius, tube, radialSegments = 8, tubularSegments =
|
|
|
3901
4265
|
return meshFromInterleaved(vertices, indices);
|
|
3902
4266
|
}
|
|
3903
4267
|
|
|
3904
|
-
export { PROCEDURAL_FLOATS_PER_VERTEX, VertexAttributePackError, buildMeshAttributeMapForUvSets, compute2dBounds, computeTangentVec4, create2dGeometry, create2dRingGeometry, createBoxGeometry, createCapsuleGeometry, createConeGeometry, createCylinderGeometry, createEdgesGeometry, createPlaneGeometry, createPrimitiveMesh, createSphereGeometry, createTeapotGeometry, createTorusGeometry, createWireframeGeometry, deriveVertexBufferLayout, deriveVertexBufferLayoutFromProjection, deriveVertexLayoutProjection, deriveVertexLayoutProjectionFromMask, meshAssetContribution, meshAssetDecoder, meshAssetKind, meshFromInterleaved, packInterleavedVertexAttributes };
|
|
4268
|
+
export { PROCEDURAL_FLOATS_PER_VERTEX, VertexAttributePackError, buildMeshAttributeMapForUvSets, compute2dBounds, computeTangentVec4, create2dGeometry, create2dRingGeometry, createBoxGeometry, createCapsuleGeometry, createConeGeometry, createCylinderGeometry, createEdgesGeometry, createMeshBuilder, createPlaneGeometry, createPrimitiveMesh, createSphereGeometry, createTeapotGeometry, createTorusGeometry, createWireframeGeometry, deriveVertexBufferLayout, deriveVertexBufferLayoutFromProjection, deriveVertexLayoutProjection, deriveVertexLayoutProjectionFromMask, meshAssetContribution, meshAssetDecoder, meshAssetKind, meshFromInterleaved, packInterleavedVertexAttributes };
|
|
3905
4269
|
//# sourceMappingURL=index.mjs.map
|
|
3906
4270
|
//# sourceMappingURL=index.mjs.map
|