@forgeax/engine-gltf 0.1.27 → 0.1.29

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.
@@ -1 +1 @@
1
- {"version":3,"file":"gltf-importer.d.ts","sourceRoot":"","sources":["../src/gltf-importer.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAEV,QAAQ,EAIR,QAAQ,EAMT,MAAM,uBAAuB,CAAC;AAkB/B,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAqB,MAAM,iBAAiB,CAAC;AAwTlF,iFAAiF;AACjF,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,OAAO,EACZ,kBAAkB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/C,kBAAkB,GAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAa,GAC1D,SAAS,QAAQ,EAAE,CA2CrB;AA4oBD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,8BAA8B,GAAG,QAAQ,CAMrF;AAED,8EAA8E;AAC9E,eAAO,MAAM,YAAY,EAAE,QAA+B,CAAC"}
1
+ {"version":3,"file":"gltf-importer.d.ts","sourceRoot":"","sources":["../src/gltf-importer.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAEV,QAAQ,EAIR,QAAQ,EAMT,MAAM,uBAAuB,CAAC;AAmB/B,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAqB,MAAM,iBAAiB,CAAC;AAwUlF,iFAAiF;AACjF,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,OAAO,EACZ,kBAAkB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/C,kBAAkB,GAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAa,GAC1D,SAAS,QAAQ,EAAE,CA2CrB;AA6oBD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,8BAA8B,GAAG,QAAQ,CAMrF;AAED,8EAA8E;AAC9E,eAAO,MAAM,YAAY,EAAE,QAA+B,CAAC"}
@@ -2,7 +2,7 @@ import { MeshoptDecoder } from 'meshoptimizer';
2
2
  import { deriveDefaultLodScreenCoverages } from '@forgeax/engine-import';
3
3
  import { packMeshBinV4 } from '@forgeax/engine-import/mesh-bin';
4
4
  import { AssetGuid } from '@forgeax/engine-pack/guid';
5
- import { ImportError, toShared, err, ok, reconcileMeshMaterialSlotTopology, IMPORT_ERROR_HINTS, resolveMeshMaterialSlotDefaultGuid, createMaterialError, standardMaterialParameters, STANDARD_MATERIAL_PARAM_SCHEMA, STANDARD_PHYSICAL_PARAMETER_NAMES, STANDARD_TRANSMISSION_PARAMETER_NAMES, STANDARD_LAYER_PARAMETER_GROUPS } from '@forgeax/engine-types';
5
+ import { ImportError, readConservativeAnimatedBounds, toShared, err, ok, reconcileMeshMaterialSlotTopology, IMPORT_ERROR_HINTS, resolveMeshMaterialSlotDefaultGuid, createMaterialError, standardMaterialParameters, STANDARD_MATERIAL_PARAM_SCHEMA, STANDARD_PHYSICAL_PARAMETER_NAMES, STANDARD_TRANSMISSION_PARAMETER_NAMES, STANDARD_LAYER_PARAMETER_GROUPS, parseConservativeAnimatedBounds } from '@forgeax/engine-types';
6
6
  import { computeTangentVec4, packInterleavedVertexAttributes } from '@forgeax/engine-geometry';
7
7
  import { box3, mat4, vec3, quat } from '@forgeax/engine-math';
8
8
  import { deriveAnimationTargetId } from '@forgeax/engine-animation/target-id';
@@ -13,7 +13,7 @@ var GLTF_MESHOPT_FILTERS = ["NONE", "OCTAHEDRAL", "QUATERNION", "EXPONENTIAL"];
13
13
  var gltfErrorPolicy = {
14
14
  "gltf-malformed-header": {
15
15
  expected: "GLB 12-byte header (magic 0x46546C67 + version=2 + length) plus mandatory JSON chunk",
16
- hint: "verify .glb is not truncated; rerun: forgeax-engine-remote-gltf import <path>"
16
+ hint: "verify .glb is not truncated; rerun: forgeax asset import <path> --root <project> --json"
17
17
  },
18
18
  "gltf-version-unsupported": {
19
19
  expected: 'asset.version === "2.0"',
@@ -49,7 +49,7 @@ var gltfErrorPolicy = {
49
49
  },
50
50
  "gltf-meta-missing": {
51
51
  expected: "sidecar <source>.meta.json (importer: 'gltf') present in same directory",
52
- hint: "run: forgeax-engine-remote-gltf import <path>"
52
+ hint: "run: forgeax asset import <path> --root <project> --json"
53
53
  },
54
54
  "gltf-instancing-count-mismatch": {
55
55
  expected: "all instance attribute accessors share the same count",
@@ -77,7 +77,7 @@ var gltfErrorPolicy = {
77
77
  },
78
78
  "gltf-image-extract-failed": {
79
79
  expected: "image bytes extractable from bufferView / data-URI / external URI without corruption",
80
- hint: "verify the bufferView byte range / data: URI base64 / external URI sibling file is intact next to the .gltf source; rerun: forgeax-engine-remote-gltf import <path>"
80
+ hint: "verify the bufferView byte range / data: URI base64 / external URI sibling file is intact next to the .gltf source; rerun: forgeax asset import <path> --root <project> --json"
81
81
  },
82
82
  "gltf-skin-attr-asymmetric": {
83
83
  expected: "mesh primitive declares JOINTS_0 and WEIGHTS_0 symmetrically (both present or both absent)",
@@ -443,7 +443,7 @@ function composeMat4(out, tx, ty, tz, qx, qy, qz, qw, sx, sy, sz) {
443
443
  function gltfDocToSceneAsset(doc, ctx) {
444
444
  const sceneIr = doc.scenes[doc.defaultSceneIndex];
445
445
  const resultNodes = [];
446
- if (sceneIr === void 0) return { kind: "scene", entities: [] };
446
+ if (sceneIr === void 0) return { kind: "scene", entities: {} };
447
447
  const importedLights = doc.lights ?? doc.extensions?.KHR_lights_punctual?.lights ?? [];
448
448
  const animationTargetIds = /* @__PURE__ */ new Map();
449
449
  for (const clip of doc.animationClips) {
@@ -536,7 +536,10 @@ function gltfDocToSceneAsset(doc, ctx) {
536
536
  components.MeshRenderer = { materials: [] };
537
537
  }
538
538
  if (ir.instancing !== void 0) {
539
- components.Instances = { transforms: ir.instancing.transforms };
539
+ const collectionId = ctx.instanceCollectionIdsByNodeIndex?.get(gltfNodeIdx);
540
+ if (collectionId !== void 0) {
541
+ components.Instances = { collectionId };
542
+ }
540
543
  }
541
544
  if (isCamera) {
542
545
  components.Camera = {
@@ -564,10 +567,20 @@ function gltfDocToSceneAsset(doc, ctx) {
564
567
  for (let i = 0; i < 16; i++) parentWorld[i] = savedParent[i] ?? 0;
565
568
  };
566
569
  for (const rootIdx of sceneIr.nodes) visit(rootIdx, null);
567
- const frozen = resultNodes.map((n) => ({
568
- localId: n.localId,
569
- components: n.components
570
- }));
570
+ const keyByLocalId = /* @__PURE__ */ new Map();
571
+ for (const node of resultNodes) keyByLocalId.set(node.localIdx, `node-${node.localIdx}`);
572
+ const entities = {};
573
+ for (const node of resultNodes) {
574
+ const components = { ...node.components };
575
+ const childOf = components.ChildOf;
576
+ if (childOf !== void 0 && typeof childOf.parent === "number") {
577
+ const parentKey = keyByLocalId.get(childOf.parent);
578
+ if (parentKey === void 0)
579
+ throw new Error(`gltfDocToSceneAsset: missing parent node ${childOf.parent}`);
580
+ components.ChildOf = { ...childOf, parent: parentKey };
581
+ }
582
+ entities[`node-${node.localIdx}`] = { components };
583
+ }
571
584
  const lightFacts = importedLights.map((light) => ({
572
585
  kind: light.type,
573
586
  intensity: light.intensity,
@@ -576,7 +589,7 @@ function gltfDocToSceneAsset(doc, ctx) {
576
589
  }));
577
590
  return {
578
591
  kind: "scene",
579
- entities: frozen,
592
+ entities,
580
593
  ...lightFacts.length === 0 ? {} : { lights: lightFacts }
581
594
  };
582
595
  }
@@ -2283,8 +2296,6 @@ function parseAnimation(animationsJson, nodesJson, accessors, bufferViews, buffe
2283
2296
  }
2284
2297
  return ok(clips);
2285
2298
  }
2286
-
2287
- // src/parse-skin.ts
2288
2299
  var MAX_JOINTS = 256;
2289
2300
  var SKIN_ACCESSOR_TYPES = ["MAT4"];
2290
2301
  function identityMat4() {
@@ -2365,10 +2376,14 @@ function parseSkin(skinsJson, nodesJson, accessors, bufferViews, buffers) {
2365
2376
  if (!pathResult.ok) return err(pathResult.error);
2366
2377
  jointPaths.push(pathResult.value.join("/"));
2367
2378
  }
2379
+ const bounds = parseConservativeAnimatedBounds(
2380
+ skin.extras?.forgeax?.conservativeAnimatedBounds
2381
+ );
2368
2382
  records.push({
2369
2383
  jointCount: joints.length,
2370
2384
  inverseBindMatrices: ibm,
2371
- jointPaths
2385
+ jointPaths,
2386
+ ...bounds === void 0 ? {} : { bounds }
2372
2387
  });
2373
2388
  }
2374
2389
  return ok(records);
@@ -3220,6 +3235,16 @@ function isGlbBytes(source) {
3220
3235
  function publishesCatalogProduct(input) {
3221
3236
  return input.importSettings.geometry !== "procedural";
3222
3237
  }
3238
+ function applyImportSettingsBounds(doc, importSettings) {
3239
+ let changed = false;
3240
+ const skeletons = doc.skeletons.map((record, sourceIndex) => {
3241
+ const bounds = readConservativeAnimatedBounds(importSettings, sourceIndex);
3242
+ if (bounds === void 0 || record.bounds !== void 0) return record;
3243
+ changed = true;
3244
+ return { ...record, bounds };
3245
+ });
3246
+ return changed ? { ...doc, skeletons } : doc;
3247
+ }
3223
3248
  function previousMaterialSlotTopology(ctx, meshSourceKey) {
3224
3249
  if (meshSourceKey === void 0) return void 0;
3225
3250
  const value = ctx.sourceOverrides?.[meshSourceKey]?.materialSlots;
@@ -3539,7 +3564,7 @@ async function importGltf(ctx, meshopt) {
3539
3564
  }
3540
3565
  const parsed = await parseDoc(ctx.source, read.value, ctx, meshopt);
3541
3566
  if (!parsed.ok) return parsed;
3542
- const doc = parsed.value;
3567
+ const doc = applyImportSettingsBounds(parsed.value, ctx.importSettings);
3543
3568
  const maps = buildHandleMaps(ctx.subAssets, doc);
3544
3569
  const imageColorSpaces = deriveTextureColorSpace({
3545
3570
  imageCount: (doc.images ?? []).length,
@@ -3838,7 +3863,7 @@ async function importGltf(ctx, meshopt) {
3838
3863
  fieldName: prov.fieldName,
3839
3864
  ...prov.arrayIndex !== void 0 ? { arrayIndex: prov.arrayIndex } : {}
3840
3865
  },
3841
- sceneEntityId: prov.sceneEntityId
3866
+ sceneEntityKey: prov.sceneEntityKey
3842
3867
  };
3843
3868
  }
3844
3869
  return { guid };
@@ -3849,19 +3874,19 @@ async function importGltf(ctx, meshopt) {
3849
3874
  });
3850
3875
  const handleValueProvenance = /* @__PURE__ */ new Map();
3851
3876
  const skeletonGuidProvenance = /* @__PURE__ */ new Map();
3852
- for (const entity of scene.entities) {
3877
+ for (const [sceneEntityKey, entity] of Object.entries(scene.entities)) {
3853
3878
  const comps = entity.components;
3854
3879
  const mf = comps.MeshFilter;
3855
3880
  if (mf !== void 0 && typeof mf.assetHandle === "number") {
3856
3881
  handleValueProvenance.set(mf.assetHandle, {
3857
- sceneEntityId: entity.localId,
3882
+ sceneEntityKey,
3858
3883
  componentName: "MeshFilter",
3859
3884
  fieldName: "assetHandle"
3860
3885
  });
3861
3886
  }
3862
3887
  const skin = comps.Skin;
3863
3888
  if (skin !== void 0 && typeof skin.skeleton === "string") {
3864
- skeletonGuidProvenance.set(skin.skeleton, { sceneEntityId: entity.localId });
3889
+ skeletonGuidProvenance.set(skin.skeleton, { sceneEntityKey });
3865
3890
  }
3866
3891
  }
3867
3892
  const meshGuidList = [...maps.meshGuidByIndex.values()];
@@ -3879,7 +3904,7 @@ async function importGltf(ctx, meshopt) {
3879
3904
  skProv !== void 0 ? {
3880
3905
  guid,
3881
3906
  sourceField: { componentName: "Skin", fieldName: "skeleton" },
3882
- sceneEntityId: skProv.sceneEntityId
3907
+ sceneEntityKey: skProv.sceneEntityKey
3883
3908
  } : { guid }
3884
3909
  );
3885
3910
  cursor++;
@@ -3909,7 +3934,8 @@ async function importGltf(ctx, meshopt) {
3909
3934
  const payload = {
3910
3935
  kind: "skeleton",
3911
3936
  inverseBindMatrices: rec.inverseBindMatrices,
3912
- jointCount: rec.jointCount
3937
+ jointCount: rec.jointCount,
3938
+ ...rec.bounds === void 0 ? {} : { bounds: rec.bounds }
3913
3939
  };
3914
3940
  out.push({ guid: sub.guid, kind: "skeleton", payload, refs: [], artifacts: {} });
3915
3941
  } else if (sub.kind === "skin") {