@carbonenginejs/runtime-resource 0.8.0 → 0.9.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/LICENSE +21 -21
- package/NOTICE +29 -29
- package/README.md +67 -548
- package/dist/CjsMotherLode.js +1271 -1271
- package/dist/CjsResMan.js +3005 -3005
- package/dist/CjsResManQueue.js +214 -214
- package/dist/CjsResource.js +566 -566
- package/dist/CjsResourceSource.js +59 -59
- package/dist/_virtual/_rollupPluginBabelHelpers.js +153 -153
- package/dist/format/CjsBlueReader.js +269 -269
- package/dist/format/CjsFormat.js +192 -192
- package/dist/format/CjsReader.js +18 -18
- package/dist/format/CjsResourceProbe.js +277 -277
- package/dist/format/payloadContract.js +173 -173
- package/dist/formats/black/CjsBlackFormat.js +278 -278
- package/dist/formats/black/core/CjsBlackBinaryReader.js +153 -153
- package/dist/formats/black/core/CjsBlackPropertyReaders.js +382 -382
- package/dist/formats/black/core/CjsBlackReader.js +639 -639
- package/dist/formats/black/core/CjsBlackSchemaRegistry.js +433 -433
- package/dist/formats/black/core/black-schema-v1-2026-07-11.json.js +4 -4
- package/dist/formats/black/core/blackConstants.js +7 -7
- package/dist/formats/black/core/blackDefinitions.js +10 -10
- package/dist/formats/black/core/blackEnums.js +6 -6
- package/dist/formats/black/core/blackSchema.js +3 -3
- package/dist/formats/black/core/blackVersion.js +22 -22
- package/dist/formats/black/core/helpers.js +182 -182
- package/dist/formats/black/core/schema.js +4 -4
- package/dist/formats/black/index.js +2 -2
- package/dist/formats/bnk/CjsBnkFormat.js +125 -125
- package/dist/formats/bnk/core/graph.js +140 -140
- package/dist/formats/bnk/core/helpers.js +409 -409
- package/dist/formats/bnk/core/musicNodes.js +489 -489
- package/dist/formats/bnk/core/soundbanksInfo.js +246 -246
- package/dist/formats/bnk/index.js +2 -2
- package/dist/formats/cmf/CjsCmfFormat.js +497 -497
- package/dist/formats/cmf/core/binary.js +118 -118
- package/dist/formats/cmf/core/buffers.js +233 -233
- package/dist/formats/cmf/core/constants.js +47 -47
- package/dist/formats/cmf/core/gr2Anim.js +453 -453
- package/dist/formats/cmf/core/helpers.js +287 -287
- package/dist/formats/cmf/core/pack.js +276 -276
- package/dist/formats/cmf/core/schema.js +364 -364
- package/dist/formats/cmf/core/shared.js +268 -268
- package/dist/formats/cmf/core/writer.js +517 -517
- package/dist/formats/cmf/index.js +2 -2
- package/dist/formats/dds/CjsDdsFormat.js +193 -193
- package/dist/formats/dds/core/bc6h.js +288 -288
- package/dist/formats/dds/core/bc7.js +251 -251
- package/dist/formats/dds/core/helpers.js +815 -815
- package/dist/formats/dds/index.js +2 -2
- package/dist/formats/fbx/CjsFbxFormat.js +266 -266
- package/dist/formats/fbx/core/helpers.js +3901 -3901
- package/dist/formats/fbx/index.js +2 -2
- package/dist/formats/flac/CjsFlacFormat.js +87 -87
- package/dist/formats/flac/core/helpers.js +295 -295
- package/dist/formats/flac/index.js +2 -2
- package/dist/formats/gif/CjsGifFormat.js +87 -87
- package/dist/formats/gif/core/helpers.js +360 -360
- package/dist/formats/gif/index.js +2 -2
- package/dist/formats/gltf/CjsGltfFormat.js +290 -290
- package/dist/formats/gltf/core/helpers.js +292 -292
- package/dist/formats/gltf/core/json.js +79 -79
- package/dist/formats/gltf/core/parser.js +666 -666
- package/dist/formats/gltf/core/targets.js +163 -163
- package/dist/formats/gltf/index.js +2 -2
- package/dist/formats/gr2/CjsGr2Format.js +46 -0
- package/dist/formats/gr2/CjsGr2Format.js.map +1 -0
- package/dist/formats/gr2/core/CjsFormatGr2.js +273 -0
- package/dist/formats/gr2/core/CjsFormatGr2.js.map +1 -0
- package/dist/formats/gr2/core/bitknit2.js +280 -0
- package/dist/formats/gr2/core/bitknit2.js.map +1 -0
- package/dist/formats/gr2/core/curves.js +1047 -0
- package/dist/formats/gr2/core/curves.js.map +1 -0
- package/dist/formats/gr2/core/gsf.js +72 -0
- package/dist/formats/gr2/core/gsf.js.map +1 -0
- package/dist/formats/gr2/core/helpers.js +332 -0
- package/dist/formats/gr2/core/helpers.js.map +1 -0
- package/dist/formats/gr2/core/json.js +622 -0
- package/dist/formats/gr2/core/json.js.map +1 -0
- package/dist/formats/gr2/core/oodle1.js +388 -0
- package/dist/formats/gr2/core/oodle1.js.map +1 -0
- package/dist/formats/gr2/core/reader.js +617 -0
- package/dist/formats/gr2/core/reader.js.map +1 -0
- package/dist/formats/gr2/core/tangents.js +48 -0
- package/dist/formats/gr2/core/tangents.js.map +1 -0
- package/dist/formats/gr2/core/targets.js +351 -0
- package/dist/formats/gr2/core/targets.js.map +1 -0
- package/dist/formats/gr2/index.js +3 -0
- package/dist/formats/gr2/index.js.map +1 -0
- package/dist/formats/index.js +30 -23
- package/dist/formats/index.js.map +1 -1
- package/dist/formats/jpeg/CjsJpegFormat.js +206 -206
- package/dist/formats/jpeg/core/helpers.js +350 -350
- package/dist/formats/jpeg/core/jpeg.js +377 -377
- package/dist/formats/jpeg/index.js +2 -2
- package/dist/formats/mp3/CjsMp3Format.js +192 -192
- package/dist/formats/mp3/core/helpers.js +338 -338
- package/dist/formats/mp3/index.js +2 -2
- package/dist/formats/mp4/CjsMp4Format.js +191 -191
- package/dist/formats/mp4/core/helpers.js +449 -449
- package/dist/formats/mp4/index.js +2 -2
- package/dist/formats/obj/CjsObjFormat.js +253 -253
- package/dist/formats/obj/core/helpers.js +573 -573
- package/dist/formats/obj/core/json.js +64 -64
- package/dist/formats/obj/core/parser.js +321 -321
- package/dist/formats/obj/index.js +2 -2
- package/dist/formats/ogg/CjsOggFormat.js +88 -88
- package/dist/formats/ogg/core/helpers.js +387 -387
- package/dist/formats/ogg/core/imdct.js +178 -178
- package/dist/formats/ogg/core/vorbis.js +999 -999
- package/dist/formats/ogg/index.js +2 -2
- package/dist/formats/png/CjsPngFormat.js +195 -195
- package/dist/formats/png/core/helpers.js +583 -583
- package/dist/formats/png/index.js +2 -2
- package/dist/formats/red/CjsRedFormat.js +261 -261
- package/dist/formats/red/core/CjsRedReader.js +194 -194
- package/dist/formats/red/core/blackDefinitions.js +3 -3
- package/dist/formats/red/core/helpers.js +139 -139
- package/dist/formats/red/core/redGraph.js +68 -68
- package/dist/formats/red/core/schema.js +4 -4
- package/dist/formats/red/index.js +2 -2
- package/dist/formats/stl/CjsStlFormat.js +365 -365
- package/dist/formats/stl/core/helpers.js +261 -261
- package/dist/formats/stl/core/json.js +51 -51
- package/dist/formats/stl/core/stl.js +629 -629
- package/dist/formats/stl/core/targets.js +163 -163
- package/dist/formats/stl/index.js +2 -2
- package/dist/formats/tga/CjsTgaFormat.js +192 -192
- package/dist/formats/tga/core/helpers.js +446 -446
- package/dist/formats/tga/index.js +2 -2
- package/dist/formats/wav/CjsWavFormat.js +192 -192
- package/dist/formats/wav/core/helpers.js +328 -328
- package/dist/formats/wav/index.js +2 -2
- package/dist/formats/webm/CjsWebmFormat.js +191 -191
- package/dist/formats/webm/core/helpers.js +537 -537
- package/dist/formats/webm/index.js +2 -2
- package/dist/formats/webp/CjsWebpFormat.js +86 -86
- package/dist/formats/webp/core/helpers.js +214 -214
- package/dist/formats/webp/index.js +2 -2
- package/dist/formats/wem/CjsWemFormat.js +241 -241
- package/dist/formats/wem/core/bitStream.js +259 -259
- package/dist/formats/wem/core/codebookLibrary.js +164 -164
- package/dist/formats/wem/core/helpers.js +417 -417
- package/dist/formats/wem/core/packedCodebooksAotuv603.js +30 -30
- package/dist/formats/wem/core/ptadpcm.js +77 -77
- package/dist/formats/wem/core/resolve.js +121 -121
- package/dist/formats/wem/core/wemToOgg.js +485 -485
- package/dist/formats/wem/index.js +2 -2
- package/dist/formats/yaml/CjsYamlFormat.js +83 -83
- package/dist/formats/yaml/core/CjsYamlReader.js +305 -305
- package/dist/formats/yaml/core/helpers.js +160 -160
- package/dist/formats/yaml/index.js +2 -2
- package/dist/index.js +49 -48
- package/dist/index.js.map +1 -1
- package/dist/resourcePath.js +18 -18
- package/dist/resourceStates.js +9 -9
- package/dist/resources/AudioGeometryResData.js +47 -47
- package/dist/resources/GStateBindingCallbackData.js +31 -31
- package/dist/resources/MeshDecalData.js +37 -37
- package/dist/resources/MeshDecalLodData.js +34 -34
- package/dist/resources/Tr2EffectRes.js +71 -71
- package/dist/resources/Tr2GrannyIntersectionResult.js +60 -60
- package/dist/resources/Tr2GrannyStateRes.js +44 -44
- package/dist/resources/Tr2ImageRes.js +114 -114
- package/dist/resources/Tr2LightProfileRes.js +40 -40
- package/dist/resources/Tr2MaterialArea.js +34 -34
- package/dist/resources/Tr2MaterialMesh.js +31 -31
- package/dist/resources/Tr2MaterialRes.js +34 -34
- package/dist/resources/Tr2ShaderPermutation.js +43 -43
- package/dist/resources/Tr2TextureLodManager.js +80 -80
- package/dist/resources/Tr2TextureLodUpdateRequest.js +37 -37
- package/dist/resources/Tr2TexturePackChannel.js +37 -37
- package/dist/resources/Tr2TexturePipeline.js +52 -52
- package/dist/resources/Tr2TexturePipelineParams.js +34 -34
- package/dist/resources/Tr2TexturePipelineStepCompress.js +40 -40
- package/dist/resources/Tr2TexturePipelineStepGenerateMips.js +22 -0
- package/dist/resources/Tr2TexturePipelineStepGenerateMips.js.map +1 -0
- package/dist/resources/Tr2TexturePipelineStepLimitSize.js +34 -34
- package/dist/resources/Tr2TexturePipelineStepLoad.js +31 -31
- package/dist/resources/Tr2TexturePipelineStepPack.js +43 -43
- package/dist/resources/TriGeometryRes.js +239 -239
- package/dist/resources/TriGeometryResAreaData.js +59 -59
- package/dist/resources/TriGeometryResJointData.js +38 -38
- package/dist/resources/TriGeometryResLodData.js +88 -88
- package/dist/resources/TriGeometryResMeshData.js +63 -63
- package/dist/resources/TriGeometryResSkeletonData.js +34 -34
- package/dist/resources/TriGrannyRes.js +43 -43
- package/dist/resources/TriJointBinding.js +38 -38
- package/dist/resources/TriMorphTargetGeometryConstants.js +46 -46
- package/dist/resources/TriRtGeometryConstants.js +88 -88
- package/dist/resources/TriTextureRes.js +304 -304
- package/dist/resources/enums.js +18 -18
- package/dist/resources/resourceBoundary.js +47 -47
- package/dist/resources/texturePipelineBehavior.js +308 -308
- package/dist/texture/CjsTextureArrayRes.js +406 -406
- package/dist/texture/CjsTextureParameterProxy.js +133 -133
- package/docs/README.md +69 -0
- package/docs/architecture.md +86 -0
- package/docs/concepts/resource-lifecycle.md +217 -0
- package/docs/formats/README.md +104 -0
- package/{FORMAT-PROVENANCE.md → docs/formats/provenance.md} +173 -155
- package/docs/formats/stl.md +37 -0
- package/docs/formats/wwise.md +44 -0
- package/docs/reference/events.md +92 -0
- package/docs/reference/motherlode-cache.md +244 -0
- package/docs/reference/queues.md +102 -0
- package/docs/reference/reload.md +107 -0
- package/docs/reference/texture-arrays.md +113 -0
- package/docs/reference/texture-pipeline.md +53 -0
- package/docs/roadmap.md +104 -0
- package/format-notices/black/LICENSE +21 -21
- package/format-notices/black/NOTICE +47 -47
- package/format-notices/bnk/LICENSE +21 -21
- package/format-notices/bnk/NOTICE +20 -20
- package/format-notices/cmf/LICENSE +21 -21
- package/format-notices/cmf/NOTICE +36 -36
- package/format-notices/dds/LICENSE +21 -21
- package/format-notices/dds/NOTICE +14 -14
- package/format-notices/fbx/LICENSE +21 -21
- package/format-notices/fbx/NOTICE +14 -14
- package/format-notices/flac/LICENSE +21 -21
- package/format-notices/flac/NOTICE +14 -14
- package/format-notices/gif/LICENSE +21 -21
- package/format-notices/gif/NOTICE +14 -14
- package/format-notices/gltf/LICENSE +21 -21
- package/format-notices/gltf/NOTICE +27 -27
- package/format-notices/gr2/LICENSE +21 -0
- package/format-notices/gr2/NOTICE +60 -0
- package/format-notices/gr2/THIRD-PARTY-NOTICES.md +93 -0
- package/format-notices/jpeg/LICENSE +21 -21
- package/format-notices/jpeg/NOTICE +14 -14
- package/format-notices/mp3/LICENSE +21 -21
- package/format-notices/mp3/NOTICE +14 -14
- package/format-notices/mp4/LICENSE +21 -21
- package/format-notices/mp4/NOTICE +14 -14
- package/format-notices/obj/LICENSE +21 -21
- package/format-notices/obj/NOTICE +26 -26
- package/format-notices/ogg/LICENSE +21 -21
- package/format-notices/ogg/NOTICE +28 -28
- package/format-notices/png/LICENSE +21 -21
- package/format-notices/png/NOTICE +14 -14
- package/format-notices/red/LICENSE +21 -21
- package/format-notices/red/NOTICE +31 -31
- package/format-notices/stl/LICENSE +21 -21
- package/format-notices/stl/NOTICE +21 -21
- package/format-notices/tga/LICENSE +21 -21
- package/format-notices/tga/NOTICE +14 -14
- package/format-notices/wav/LICENSE +21 -21
- package/format-notices/wav/NOTICE +14 -14
- package/format-notices/webm/LICENSE +21 -21
- package/format-notices/webm/NOTICE +14 -14
- package/format-notices/webp/LICENSE +21 -21
- package/format-notices/webp/NOTICE +14 -14
- package/format-notices/wem/LICENSE +57 -57
- package/format-notices/wem/NOTICE +33 -33
- package/format-notices/yaml/LICENSE +21 -21
- package/format-notices/yaml/NOTICE +44 -44
- package/package.json +52 -51
- package/resource-lifecycle.md +0 -679
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sources":["../../../../../src/formats/gr2/core/helpers.js"],"sourcesContent":["import { readGr2Raw } from \"./reader.js\";\nimport { emitJson, CLASS_KEYS as GR2_CLASS_KEYS } from \"./json.js\";\nimport { tangents } from \"./tangents.js\";\nimport { decompressAnimationCurves } from \"./curves.js\";\nimport { buildCmfFromShared, CMF_CLASS_KEYS, hydrateCmf } from \"./targets.js\";\n\nexport const CLASS_KEYS = Object.freeze(Array.from(new Set([\n ...GR2_CLASS_KEYS,\n ...CMF_CLASS_KEYS\n])));\n\nexport const OUTPUT_JSON = \"json\";\nexport const OUTPUT_GR2 = \"gr2\";\nexport const OUTPUT_GR2_JSON = \"gr2Json\";\nexport const OUTPUT_CMF = \"cmf\";\nexport const OUTPUT_RAW = \"raw\";\n\nexport const DEFAULT_VALUES = Object.freeze({\n emit: OUTPUT_JSON,\n decompressCurves: false,\n unpackTangents: false,\n rebuildMissingNormals: false,\n rebuildMissingTangents: false,\n rebuildMissingBiNormals: false,\n classes: Object.freeze({})\n});\n\nconst OPTION_KEYS = new Set([\n \"emit\",\n \"decompressCurves\",\n \"unpackTangents\",\n \"rebuildMissingNormals\",\n \"rebuildMissingTangents\",\n \"rebuildMissingBiNormals\",\n \"classes\"\n]);\n\nfunction normalizeEmit(emit)\n{\n if (emit === undefined || emit === OUTPUT_JSON) return OUTPUT_JSON;\n if (emit === OUTPUT_GR2_JSON) return OUTPUT_GR2_JSON;\n if (emit === OUTPUT_GR2) return OUTPUT_GR2;\n if (emit === OUTPUT_CMF) return OUTPUT_CMF;\n if (emit === OUTPUT_RAW) return OUTPUT_RAW;\n throw new Error(`CjsFormatGr2 unknown emit value \"${emit}\"`);\n}\n\nfunction hasOwn(value, key)\n{\n return Object.prototype.hasOwnProperty.call(value, key);\n}\n\nfunction classMap(values)\n{\n return values && values.classes ? values.classes : {};\n}\n\nfunction cloneValues(values)\n{\n return {\n emit: values.emit,\n decompressCurves: values.decompressCurves,\n unpackTangents: values.unpackTangents,\n rebuildMissingNormals: values.rebuildMissingNormals,\n rebuildMissingTangents: values.rebuildMissingTangents,\n rebuildMissingBiNormals: values.rebuildMissingBiNormals,\n classes: { ...classMap(values) }\n };\n}\n\nfunction assertKnownOptions(options)\n{\n for (const key of Object.keys(options))\n {\n if (!OPTION_KEYS.has(key))\n {\n throw new TypeError(`CjsFormatGr2 unknown option \"${key}\"`);\n }\n }\n}\n\nfunction validateBoolean(name, value)\n{\n if (typeof value !== \"boolean\")\n {\n throw new TypeError(`CjsFormatGr2 ${name} option must be true or false`);\n }\n return value;\n}\n\nfunction validateRule(name, value)\n{\n if (typeof value === \"boolean\" || typeof value === \"function\") return value;\n throw new TypeError(`CjsFormatGr2 ${name} option must be true, false, or a function`);\n}\n\nexport function validateClassKey(key)\n{\n if (!CLASS_KEYS.includes(key))\n {\n throw new Error(`CjsFormatGr2 unknown class type \"${key}\"`);\n }\n}\n\nexport function validateClass(type, Class)\n{\n validateClassKey(type);\n if (typeof Class !== \"function\")\n {\n throw new TypeError(`CjsFormatGr2 class \"${type}\" must be a constructor`);\n }\n}\n\nfunction mergeClasses(values, classes)\n{\n if (!classes || typeof classes !== \"object\")\n {\n throw new TypeError(\"CjsFormatGr2 classes option must be an object\");\n }\n\n const next = { ...values.classes };\n for (const [ type, Class ] of Object.entries(classes))\n {\n validateClass(type, Class);\n next[type] = Class;\n }\n values.classes = next;\n}\n\nfunction optionValue(options, keys)\n{\n for (const key of keys)\n {\n if (hasOwn(options, key)) return options[key];\n }\n return undefined;\n}\n\nexport function normalizeValues(base = DEFAULT_VALUES, options = {})\n{\n if (!options || typeof options !== \"object\")\n {\n throw new TypeError(\"CjsFormatGr2 options must be an object\");\n }\n\n assertKnownOptions(options);\n\n const values = cloneValues(base);\n\n if (hasOwn(options, \"emit\")) values.emit = normalizeEmit(options.emit);\n if (hasOwn(options, \"decompressCurves\"))\n {\n values.decompressCurves = validateBoolean(\"decompressCurves\", options.decompressCurves);\n }\n\n const unpackTangents = optionValue(options, [ \"unpackTangents\" ]);\n if (unpackTangents !== undefined)\n {\n values.unpackTangents = validateRule(\"unpackTangents\", unpackTangents);\n }\n\n const rebuildMissingNormals = optionValue(options, [ \"rebuildMissingNormals\" ]);\n if (rebuildMissingNormals !== undefined)\n {\n values.rebuildMissingNormals = validateRule(\"rebuildMissingNormals\", rebuildMissingNormals);\n }\n\n const rebuildMissingTangents = optionValue(options, [ \"rebuildMissingTangents\" ]);\n if (rebuildMissingTangents !== undefined)\n {\n values.rebuildMissingTangents = validateRule(\"rebuildMissingTangents\", rebuildMissingTangents);\n }\n\n const rebuildMissingBiNormals = optionValue(options, [ \"rebuildMissingBiNormals\" ]);\n if (rebuildMissingBiNormals !== undefined)\n {\n values.rebuildMissingBiNormals = validateRule(\"rebuildMissingBiNormals\", rebuildMissingBiNormals);\n }\n\n if (hasOwn(options, \"classes\"))\n {\n mergeClasses(values, options.classes);\n }\n\n if ((values.emit === OUTPUT_GR2 || values.emit === OUTPUT_CMF) && !hasClasses(values.classes))\n {\n throw new TypeError(`CjsFormatGr2 emit \"${values.emit}\" requires explicit classes`);\n }\n\n return values;\n}\n\nfunction hasClasses(classes)\n{\n return !!classes && Object.values(classes).some((Class) => typeof Class === \"function\");\n}\n\nfunction isRawGr2Result(value)\n{\n return !!value && typeof value === \"object\" && \"fileInfo\" in value &&\n typeof value.version === \"number\";\n}\n\n/**\n * Normalizes GR2 input into a Uint8Array. readGr2Raw indexes `.buffer`,\n * `.byteOffset`, `.byteLength` and calls `.subarray()`, so a raw\n * ArrayBuffer (e.g. from `fetch(...).then(r => r.arrayBuffer())`, which\n * is how ccpwgl's resource loader supplies bytes) must be wrapped in a\n * view before it reaches readGr2Raw, not passed straight through.\n *\n * @param {Uint8Array|ArrayBuffer|Buffer|DataView} input GR2 bytes.\n * @returns {Uint8Array} A Uint8Array view over the same bytes.\n */\nfunction toBytes(input)\n{\n if (input instanceof Uint8Array) return input;\n if (typeof ArrayBuffer !== \"undefined\" && input instanceof ArrayBuffer) return new Uint8Array(input);\n if (ArrayBuffer.isView(input)) return new Uint8Array(input.buffer, input.byteOffset, input.byteLength);\n throw new TypeError(\"CjsFormatGr2: input must be GR2 bytes (Uint8Array, Buffer, DataView or ArrayBuffer)\");\n}\n\nexport function readRawInput(input)\n{\n return isRawGr2Result(input) ? input : readGr2Raw(toBytes(input));\n}\n\nfunction meshName(mesh, meshIndex)\n{\n return mesh && mesh.name ? `\"${mesh.name}\"` : `#${meshIndex}`;\n}\n\nfunction vertexChannel(mesh, channel)\n{\n return mesh && mesh.vertex && mesh.vertex[channel];\n}\n\nfunction hasVertexChannel(mesh, channel)\n{\n const value = vertexChannel(mesh, channel);\n return !!value && value.length > 0;\n}\n\nfunction requireVertexChannel(mesh, meshIndex, channel, feature)\n{\n const value = vertexChannel(mesh, channel);\n if (!value || value.length === 0)\n {\n throw new Error(`CjsFormatGr2 ${feature} requires mesh.vertex.${channel} for mesh ${meshName(mesh, meshIndex)}`);\n }\n return value;\n}\n\nfunction triangleFaces(mesh, meshIndex, feature)\n{\n const faces = [];\n for (const group of mesh.indices || [])\n {\n if (group && group.faces) faces.push(...group.faces);\n }\n\n if (faces.length === 0)\n {\n throw new Error(`CjsFormatGr2 ${feature} requires triangle indices for mesh ${meshName(mesh, meshIndex)}`);\n }\n\n return faces;\n}\n\nfunction shouldApplyMeshRule(reader, rule, context)\n{\n const fullContext = { reader, ...context };\n\n if (typeof rule === \"function\")\n {\n const result = rule(fullContext);\n if (typeof result !== \"boolean\")\n {\n throw new TypeError(`CjsFormatGr2 ${context.feature} rule must return true or false`);\n }\n return result;\n }\n\n return rule;\n}\n\nfunction unpackMeshTangents(reader, json, raw, values)\n{\n for (let meshIndex = 0; meshIndex < (json.meshes || []).length; meshIndex++)\n {\n const mesh = json.meshes[meshIndex];\n if (shouldApplyMeshRule(reader, values.unpackTangents, {\n options: values, raw, json, mesh, meshIndex,\n feature: \"unpackTangents\",\n channel: \"tangent\"\n }))\n {\n tangents.unpack(mesh);\n }\n }\n}\n\nfunction rebuildMeshNormals(mesh, meshIndex)\n{\n const\n positions = requireVertexChannel(mesh, meshIndex, \"position\", \"rebuildMissingNormals\"),\n faces = triangleFaces(mesh, meshIndex, \"rebuildMissingNormals\");\n\n mesh.vertex.normal = Array.from(tangents.generateNormals(positions, faces));\n}\n\nfunction rebuildMeshTangents(mesh, meshIndex)\n{\n const\n positions = requireVertexChannel(mesh, meshIndex, \"position\", \"rebuildMissingTangents\"),\n normals = requireVertexChannel(mesh, meshIndex, \"normal\", \"rebuildMissingTangents\"),\n uvs = requireVertexChannel(mesh, meshIndex, \"texcoord0\", \"rebuildMissingTangents\"),\n faces = triangleFaces(mesh, meshIndex, \"rebuildMissingTangents\");\n\n mesh.vertex.tangent = Array.from(tangents.generateTangents(positions, normals, uvs, faces));\n}\n\nfunction rebuildMeshBiNormals(mesh, meshIndex)\n{\n const\n normals = requireVertexChannel(mesh, meshIndex, \"normal\", \"rebuildMissingBiNormals\"),\n tangentValues = requireVertexChannel(mesh, meshIndex, \"tangent\", \"rebuildMissingBiNormals\");\n\n mesh.vertex.binormal = tangents.generateBiNormals(normals, tangentValues);\n}\n\nfunction rebuildMissingMeshData(reader, json, raw, values)\n{\n for (let meshIndex = 0; meshIndex < (json.meshes || []).length; meshIndex++)\n {\n const mesh = json.meshes[meshIndex];\n if (!hasVertexChannel(mesh, \"normal\") && shouldApplyMeshRule(\n reader,\n values.rebuildMissingNormals,\n { options: values, raw, json, mesh, meshIndex, feature: \"rebuildMissingNormals\", channel: \"normal\" }))\n {\n rebuildMeshNormals(mesh, meshIndex);\n }\n\n if (!hasVertexChannel(mesh, \"tangent\") && shouldApplyMeshRule(\n reader,\n values.rebuildMissingTangents,\n { options: values, raw, json, mesh, meshIndex, feature: \"rebuildMissingTangents\", channel: \"tangent\" }))\n {\n rebuildMeshTangents(mesh, meshIndex);\n }\n\n if (!hasVertexChannel(mesh, \"binormal\") && shouldApplyMeshRule(\n reader,\n values.rebuildMissingBiNormals,\n { options: values, raw, json, mesh, meshIndex, feature: \"rebuildMissingBiNormals\", channel: \"binormal\" }))\n {\n rebuildMeshBiNormals(mesh, meshIndex);\n }\n }\n}\n\nfunction processMeshData(reader, json, raw, values)\n{\n unpackMeshTangents(reader, json, raw, values);\n rebuildMissingMeshData(reader, json, raw, values);\n}\n\nfunction buildJson(reader, raw, values)\n{\n const json = emitJson(raw.fileInfo, raw.version, {\n classes: values.emit === OUTPUT_GR2 || ((values.emit === OUTPUT_JSON || values.emit === OUTPUT_GR2_JSON) && hasClasses(values.classes))\n ? values.classes\n : {}\n });\n\n if (values.decompressCurves)\n {\n decompressAnimationCurves(json);\n }\n\n processMeshData(reader, json, raw, values);\n\n return json;\n}\n\nexport function readWithValues(reader, input, values)\n{\n const parsed = readRawInput(input);\n if (values.emit === OUTPUT_RAW) return parsed;\n const json = buildJson(reader, parsed, values);\n return values.emit === OUTPUT_CMF\n ? hydrateCmf(buildCmfFromShared(json), values.classes, { source: values.source })\n : json;\n}\n\nexport function toJsonValue(value, seen = new WeakSet())\n{\n if (value === null || typeof value !== \"object\") return value;\n if (ArrayBuffer.isView(value)) return Array.from(value, item => toJsonValue(item, seen));\n if (Array.isArray(value)) return value.map(item => toJsonValue(item, seen));\n\n if (seen.has(value))\n {\n throw new TypeError(\"CjsFormatGr2.toJSON cannot convert circular data\");\n }\n\n if (typeof value.toJSON === \"function\")\n {\n seen.add(value);\n const json = toJsonValue(value.toJSON(), seen);\n seen.delete(value);\n return json;\n }\n\n seen.add(value);\n const out = {};\n for (const key of Object.keys(value))\n {\n out[key] = toJsonValue(value[key], seen);\n }\n seen.delete(value);\n return out;\n}\n\nexport function inspectRawGr2Result(parsed)\n{\n const\n fileInfo = parsed.fileInfo || {},\n count = value => Array.isArray(value) ? value.filter(Boolean).length : 0;\n\n return {\n reader: \"CjsFormatGr2\",\n format: \"gr2\",\n version: parsed.version | 0,\n sectionCount: parsed.secCount | 0,\n source: fileInfo.FromFileName ?? \"\",\n counts: {\n meshes: count(fileInfo.Meshes),\n models: count(fileInfo.Models),\n animations: count(fileInfo.Animations),\n materials: count(fileInfo.Materials),\n textures: count(fileInfo.Textures)\n }\n };\n}\n"],"names":["CLASS_KEYS","Object","freeze","Array","from","Set","GR2_CLASS_KEYS","CMF_CLASS_KEYS","OUTPUT_JSON","OUTPUT_GR2","OUTPUT_GR2_JSON","OUTPUT_CMF","OUTPUT_RAW","DEFAULT_VALUES","emit","decompressCurves","unpackTangents","rebuildMissingNormals","rebuildMissingTangents","rebuildMissingBiNormals","classes","OPTION_KEYS","normalizeEmit","undefined","Error","hasOwn","value","key","prototype","hasOwnProperty","call","classMap","values","cloneValues","assertKnownOptions","options","keys","has","TypeError","validateBoolean","name","validateRule","validateClassKey","includes","validateClass","type","Class","mergeClasses","next","entries","optionValue","normalizeValues","base","hasClasses","some","isRawGr2Result","version","toBytes","input","Uint8Array","ArrayBuffer","isView","buffer","byteOffset","byteLength","readRawInput","readGr2Raw","meshName","mesh","meshIndex","vertexChannel","channel","vertex","hasVertexChannel","length","requireVertexChannel","feature","triangleFaces","faces","group","indices","push","shouldApplyMeshRule","reader","rule","context","fullContext","result","unpackMeshTangents","json","raw","meshes","tangents","unpack","rebuildMeshNormals","positions","normal","generateNormals","rebuildMeshTangents","normals","uvs","tangent","generateTangents","rebuildMeshBiNormals","tangentValues","binormal","generateBiNormals","rebuildMissingMeshData","processMeshData","buildJson","emitJson","fileInfo","decompressAnimationCurves","readWithValues","parsed","hydrateCmf","buildCmfFromShared","source","toJsonValue","seen","WeakSet","item","isArray","map","toJSON","add","delete","out","inspectRawGr2Result","count","filter","Boolean","format","sectionCount","secCount","FromFileName","counts","Meshes","models","Models","animations","Animations","materials","Materials","textures","Textures"],"mappings":"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"}
|
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GR2 JSON emitter.
|
|
3
|
+
* @author cppctamber
|
|
4
|
+
* `emitJson(fileInfo, version)` returns a plain object whose key order
|
|
5
|
+
* mirrors the reader schema. Normalized integer values are dequantized with
|
|
6
|
+
* float32 reciprocals, Real16 values are already converted by reader.js, and
|
|
7
|
+
* non-finite floats are serialized as 0.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fr = Math.fround;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Member type ids whose numeric values need conversion for GR2 JSON output.
|
|
14
|
+
*/
|
|
15
|
+
const MEMBER_TYPES = Object.freeze({
|
|
16
|
+
Real32: 10,
|
|
17
|
+
Int8: 11,
|
|
18
|
+
UInt8: 12,
|
|
19
|
+
BinormalInt8: 13,
|
|
20
|
+
NormalUInt8: 14,
|
|
21
|
+
Int16: 15,
|
|
22
|
+
UInt16: 16,
|
|
23
|
+
BinormalInt16: 17,
|
|
24
|
+
NormalUInt16: 18,
|
|
25
|
+
Int32: 19,
|
|
26
|
+
UInt32: 20,
|
|
27
|
+
Real16: 21
|
|
28
|
+
});
|
|
29
|
+
const T = MEMBER_TYPES;
|
|
30
|
+
|
|
31
|
+
/** Float32 reciprocal used to dequantize NormalUInt8 values. */
|
|
32
|
+
const INV255_VALUE = fr(1 / 255);
|
|
33
|
+
|
|
34
|
+
/** Float32 reciprocal used to dequantize NormalUInt16 values. */
|
|
35
|
+
const INV65535_VALUE = fr(1 / 65535);
|
|
36
|
+
|
|
37
|
+
/** Float32 reciprocal used to dequantize BinormalInt8 values. */
|
|
38
|
+
const INV127_VALUE = fr(1 / 127);
|
|
39
|
+
|
|
40
|
+
/** Float32 reciprocal used to dequantize BinormalInt16 values. */
|
|
41
|
+
const INV32767_VALUE = fr(1 / 32767);
|
|
42
|
+
const INV255 = INV255_VALUE,
|
|
43
|
+
INV65535 = INV65535_VALUE,
|
|
44
|
+
INV127 = INV127_VALUE,
|
|
45
|
+
INV32767 = INV32767_VALUE;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Node keys accepted by {@link emitJson}'s `options.classes` map.
|
|
49
|
+
*
|
|
50
|
+
* Each key names one GR2 JSON node shape; the mapped constructor is
|
|
51
|
+
* instantiated with `new` and populated with that node's usual fields instead
|
|
52
|
+
* of a plain object literal.
|
|
53
|
+
*/
|
|
54
|
+
const CLASS_KEYS = Object.freeze(["Root", "Mesh", "BoneBinding", "IndexGroup", "MorphTarget", "Model", "Skeleton", "Bone", "Animation", "TrackGroup", "TransformTrack", "Curve"]);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Constructors used to hydrate GR2 JSON nodes as class instances.
|
|
58
|
+
*
|
|
59
|
+
* Every key is optional; node types with no matching constructor keep the
|
|
60
|
+
* default plain-object shape. See {@link CLASS_KEYS} for valid keys.
|
|
61
|
+
*
|
|
62
|
+
* @typedef {{[key: string]: new () => object}} Gr2NodeClasses
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Instantiate and populate a node class, or return the plain props unchanged.
|
|
67
|
+
*
|
|
68
|
+
* @param {Gr2NodeClasses} classes Opt-in node class map.
|
|
69
|
+
* @param {string} key Node key to look up in `classes`.
|
|
70
|
+
* @param {object} props Fields to populate onto the instance.
|
|
71
|
+
* @returns {object} A populated class instance, or `props` when no
|
|
72
|
+
* constructor is registered for `key`.
|
|
73
|
+
*/
|
|
74
|
+
function build(classes, key, props, hydrationOptions = {}) {
|
|
75
|
+
const Ctor = classes[key];
|
|
76
|
+
return Ctor ? populate(new Ctor(), props, hydrationOptions) : props;
|
|
77
|
+
}
|
|
78
|
+
function populate(instance, props, hydrationOptions = {}) {
|
|
79
|
+
if (!instance || typeof instance.SetValues !== "function") {
|
|
80
|
+
throw new TypeError("CjsFormatGr2 class population requires classes to implement SetValues(values)");
|
|
81
|
+
}
|
|
82
|
+
instance.SetValues(props, {
|
|
83
|
+
...hydrationOptions,
|
|
84
|
+
skipUpdate: true,
|
|
85
|
+
skipEvents: true
|
|
86
|
+
});
|
|
87
|
+
return instance;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Root object emitted in the GR2 JSON shape.
|
|
92
|
+
*
|
|
93
|
+
* @typedef {object} Gr2JsonRoot
|
|
94
|
+
* @property {number} grannyFileFormatRevision Granny file format revision.
|
|
95
|
+
* @property {string} grannyFileSource Original source filename, or an empty string.
|
|
96
|
+
* @property {object[]} meshes Mesh records with deinterleaved vertex channels.
|
|
97
|
+
* @property {object[]} models Model records with skeleton and mesh bindings.
|
|
98
|
+
* @property {object[]} animations Animation records and transform tracks.
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Convert a reflected numeric value to the float convention used by GR2 JSON.
|
|
103
|
+
*
|
|
104
|
+
* @param {number} v Raw reflected numeric value.
|
|
105
|
+
* @param {number} memberType Granny member type id.
|
|
106
|
+
* @returns {number} Converted and float32-rounded value.
|
|
107
|
+
*/
|
|
108
|
+
function convert(v, memberType) {
|
|
109
|
+
switch (memberType) {
|
|
110
|
+
case T.NormalUInt8:
|
|
111
|
+
return fr(v * INV255);
|
|
112
|
+
case T.NormalUInt16:
|
|
113
|
+
return fr(v * INV65535);
|
|
114
|
+
case T.BinormalInt8:
|
|
115
|
+
return fr(v * INV127);
|
|
116
|
+
case T.BinormalInt16:
|
|
117
|
+
return fr(v * INV32767);
|
|
118
|
+
default:
|
|
119
|
+
return fr(v);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Replace non-finite JSON numbers with zero.
|
|
125
|
+
*
|
|
126
|
+
* @param {number} v Candidate numeric value.
|
|
127
|
+
* @returns {number} The original finite value, or zero.
|
|
128
|
+
*/
|
|
129
|
+
function sf(v) {
|
|
130
|
+
return Number.isFinite(v) ? v : 0;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Copy and dequantize one vertex channel from reflected vertex objects.
|
|
135
|
+
*
|
|
136
|
+
* Missing Granny members return an empty channel.
|
|
137
|
+
*
|
|
138
|
+
* @param {object[]} vertices Reflected vertex array with non-enumerable type metadata.
|
|
139
|
+
* @param {string} memberName Granny vertex member name to copy.
|
|
140
|
+
* @param {number} destWidth Number of components in the emitted channel.
|
|
141
|
+
* @returns {number[]} Flat deinterleaved channel values.
|
|
142
|
+
*/
|
|
143
|
+
function copyChannel(vertices, memberName, destWidth) {
|
|
144
|
+
const type = vertices.__type || [],
|
|
145
|
+
m = type.find(x => x.name === memberName);
|
|
146
|
+
if (!m) return [];
|
|
147
|
+
const srcWidth = m.arrayWidth > 1 ? m.arrayWidth : 1,
|
|
148
|
+
n = Math.min(srcWidth, destWidth),
|
|
149
|
+
out = new Array(vertices.length * destWidth).fill(0);
|
|
150
|
+
for (let i = 0; i < vertices.length; i++) {
|
|
151
|
+
const raw = vertices[i][memberName],
|
|
152
|
+
arr = Array.isArray(raw) ? raw : [raw],
|
|
153
|
+
base = i * destWidth;
|
|
154
|
+
for (let k = 0; k < n; k++) {
|
|
155
|
+
out[base + k] = sf(convert(arr[k], m.type));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
const VERTEX_CHANNELS = Object.freeze([["position", "Position", 3], ["blendIndice", "BoneIndices", 4], ["tangent", "Tangent", 4], ["normal", "Normal", 3], ["texcoord0", "TextureCoordinates0", 2], ["texcoord1", "TextureCoordinates1", 2], ["binormal", "Binormal", 4], ["blendWeight", "BoneWeights", 4]]);
|
|
161
|
+
function emitVertexChannels(vertices) {
|
|
162
|
+
const channels = {};
|
|
163
|
+
for (const [name, memberName, width] of VERTEX_CHANNELS) {
|
|
164
|
+
channels[name] = copyChannel(vertices, memberName, width);
|
|
165
|
+
}
|
|
166
|
+
return channels;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Flatten reflected scalar-array wrappers into plain JavaScript values.
|
|
171
|
+
*
|
|
172
|
+
* @param {ArrayLike<any>} a Reflected scalar array or already-flat array.
|
|
173
|
+
* @returns {any[]} Plain scalar values.
|
|
174
|
+
*/
|
|
175
|
+
function scalarArray(a) {
|
|
176
|
+
if (!a || !a.length) return [];
|
|
177
|
+
if (typeof a[0] === "object" && a[0] !== null) {
|
|
178
|
+
const k = Object.keys(a[0])[0];
|
|
179
|
+
return a.map(x => x[k]);
|
|
180
|
+
}
|
|
181
|
+
return a;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Granny curve format ids emitted by the GR2 JSON curve serializer.
|
|
186
|
+
*/
|
|
187
|
+
const CURVE_FORMATS = Object.freeze({
|
|
188
|
+
DaKeyframes32f: 0,
|
|
189
|
+
DaK32fC32f: 1,
|
|
190
|
+
DaIdentity: 2,
|
|
191
|
+
DaConstant32f: 3,
|
|
192
|
+
D3Constant32f: 4,
|
|
193
|
+
D4Constant32f: 5,
|
|
194
|
+
DaK16uC16u: 6,
|
|
195
|
+
DaK8uC8u: 7,
|
|
196
|
+
D4nK16uC15u: 8,
|
|
197
|
+
D4nK8uC7u: 9,
|
|
198
|
+
D3K16uC16u: 10,
|
|
199
|
+
D3K8uC8u: 11,
|
|
200
|
+
D9I1K16uC16u: 12,
|
|
201
|
+
D9I3K16uC16u: 13,
|
|
202
|
+
D9I1K8uC8u: 14,
|
|
203
|
+
D9I3K8uC8u: 15,
|
|
204
|
+
D3I1K32fC32f: 16,
|
|
205
|
+
D3I1K16uC16u: 17,
|
|
206
|
+
D3I1K8uC8u: 18
|
|
207
|
+
});
|
|
208
|
+
const F = CURVE_FORMATS;
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Locate the inline curve-data header inside a reflected curve-data object.
|
|
212
|
+
*
|
|
213
|
+
* @param {object} cd Reflected Granny curve-data object.
|
|
214
|
+
* @returns {{Format: number, Degree: number}|null} Header object when present.
|
|
215
|
+
*/
|
|
216
|
+
function curveHeader(cd) {
|
|
217
|
+
for (const k of Object.keys(cd)) {
|
|
218
|
+
if (k.startsWith("CurveDataHeader")) return cd[k];
|
|
219
|
+
}
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Convert a reflected scalar array to float32-rounded finite numbers.
|
|
225
|
+
*
|
|
226
|
+
* @param {ArrayLike<any>} a Reflected scalar array.
|
|
227
|
+
* @returns {number[]} Float array.
|
|
228
|
+
*/
|
|
229
|
+
function farr(a) {
|
|
230
|
+
return scalarArray(a).map(x => sf(fr(x)));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Convert a reflected scalar array to unsigned 32-bit integer values.
|
|
235
|
+
*
|
|
236
|
+
* @param {ArrayLike<any>} a Reflected scalar array.
|
|
237
|
+
* @returns {number[]} Unsigned integer array.
|
|
238
|
+
*/
|
|
239
|
+
function uarr(a) {
|
|
240
|
+
return scalarArray(a).map(x => x >>> 0);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Emit one Granny Curve2 object in GR2 JSON form.
|
|
245
|
+
*
|
|
246
|
+
* @param {object} curve2 Reflected Granny curve object.
|
|
247
|
+
* @param {Gr2NodeClasses} [classes] Opt-in node class map.
|
|
248
|
+
* @returns {object} Compact curve record with format-specific fields.
|
|
249
|
+
*/
|
|
250
|
+
function emitCurve(curve2, classes = {}) {
|
|
251
|
+
const cd = curve2 && curve2.CurveData;
|
|
252
|
+
if (!cd) return build(classes, "Curve", {
|
|
253
|
+
format: 0,
|
|
254
|
+
degree: 0,
|
|
255
|
+
error: "no curve data"
|
|
256
|
+
});
|
|
257
|
+
const h = curveHeader(cd) || {
|
|
258
|
+
Format: 0,
|
|
259
|
+
Degree: 0
|
|
260
|
+
},
|
|
261
|
+
format = h.Format,
|
|
262
|
+
degree = h.Degree,
|
|
263
|
+
o = {
|
|
264
|
+
format,
|
|
265
|
+
degree
|
|
266
|
+
};
|
|
267
|
+
switch (format) {
|
|
268
|
+
case F.DaIdentity:
|
|
269
|
+
break;
|
|
270
|
+
case F.DaKeyframes32f:
|
|
271
|
+
o.dimension = cd.Dimension;
|
|
272
|
+
o.controls = farr(cd.Controls);
|
|
273
|
+
break;
|
|
274
|
+
case F.DaConstant32f:
|
|
275
|
+
o.controls = farr(cd.Controls);
|
|
276
|
+
break;
|
|
277
|
+
case F.D3Constant32f:
|
|
278
|
+
o.controls = (cd.Controls || [0, 0, 0]).slice(0, 3).map(x => sf(fr(x)));
|
|
279
|
+
break;
|
|
280
|
+
case F.D4Constant32f:
|
|
281
|
+
o.controls = (cd.Controls || [0, 0, 0, 0]).slice(0, 4).map(x => sf(fr(x)));
|
|
282
|
+
break;
|
|
283
|
+
case F.DaK32fC32f:
|
|
284
|
+
o.knots = farr(cd.Knots);
|
|
285
|
+
o.controls = farr(cd.Controls);
|
|
286
|
+
break;
|
|
287
|
+
case F.DaK16uC16u:
|
|
288
|
+
case F.DaK8uC8u:
|
|
289
|
+
o.oneOverKnotScaleTrunc = cd.OneOverKnotScaleTrunc;
|
|
290
|
+
o.controlScaleOffsets = farr(cd.ControlScaleOffsets);
|
|
291
|
+
o.knotsControls = uarr(cd.KnotsControls);
|
|
292
|
+
break;
|
|
293
|
+
case F.D4nK16uC15u:
|
|
294
|
+
case F.D4nK8uC7u:
|
|
295
|
+
o.scaleOffsetTableEntries = cd.ScaleOffsetTableEntries;
|
|
296
|
+
o.oneOverKnotScale = sf(fr(cd.OneOverKnotScale));
|
|
297
|
+
o.knotsControls = uarr(cd.KnotsControls);
|
|
298
|
+
break;
|
|
299
|
+
case F.D3K16uC16u:
|
|
300
|
+
case F.D3K8uC8u:
|
|
301
|
+
case F.D3I1K16uC16u:
|
|
302
|
+
case F.D3I1K8uC8u:
|
|
303
|
+
case F.D9I3K16uC16u:
|
|
304
|
+
case F.D9I3K8uC8u:
|
|
305
|
+
o.oneOverKnotScaleTrunc = cd.OneOverKnotScaleTrunc;
|
|
306
|
+
o.controlScales = (cd.ControlScales || [0, 0, 0]).map(x => sf(fr(x)));
|
|
307
|
+
o.controlOffsets = (cd.ControlOffsets || [0, 0, 0]).map(x => sf(fr(x)));
|
|
308
|
+
o.knotsControls = uarr(cd.KnotsControls);
|
|
309
|
+
break;
|
|
310
|
+
case F.D3I1K32fC32f:
|
|
311
|
+
o.controlScales = (cd.ControlScales || [0, 0, 0]).map(x => sf(fr(x)));
|
|
312
|
+
o.controlOffsets = (cd.ControlOffsets || [0, 0, 0]).map(x => sf(fr(x)));
|
|
313
|
+
o.knotsControls = farr(cd.KnotsControls);
|
|
314
|
+
break;
|
|
315
|
+
case F.D9I1K16uC16u:
|
|
316
|
+
case F.D9I1K8uC8u:
|
|
317
|
+
o.oneOverKnotScaleTrunc = cd.OneOverKnotScaleTrunc;
|
|
318
|
+
o.controlScales = [sf(fr(cd.ControlScale))];
|
|
319
|
+
o.controlOffsets = [sf(fr(cd.ControlOffset))];
|
|
320
|
+
o.knotsControls = uarr(cd.KnotsControls);
|
|
321
|
+
break;
|
|
322
|
+
default:
|
|
323
|
+
o.error = `Unknown format ${format}`;
|
|
324
|
+
}
|
|
325
|
+
return build(classes, "Curve", o);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Convert arbitrary reflected variant data to JSON-safe plain values.
|
|
330
|
+
*
|
|
331
|
+
* @param {any} v Reflected variant value.
|
|
332
|
+
* @returns {JsonValue} JSON-compatible value.
|
|
333
|
+
*/
|
|
334
|
+
function emitVariant(v) {
|
|
335
|
+
if (v === null || v === undefined) return null;
|
|
336
|
+
if (Array.isArray(v)) return v.map(emitVariant);
|
|
337
|
+
if (typeof v === "object") {
|
|
338
|
+
const o = {};
|
|
339
|
+
for (const k of Object.keys(v)) {
|
|
340
|
+
o[k] = emitVariant(v[k]);
|
|
341
|
+
}
|
|
342
|
+
return o;
|
|
343
|
+
}
|
|
344
|
+
if (typeof v === "number") return Number.isInteger(v) ? v : sf(fr(v));
|
|
345
|
+
return v;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Attach converted extended data when the reflected variant is present.
|
|
350
|
+
*
|
|
351
|
+
* @param {object} target Emitted GR2 JSON object to mutate.
|
|
352
|
+
* @param {object|null|undefined} ext Reflected extended-data variant.
|
|
353
|
+
* @returns {void}
|
|
354
|
+
*/
|
|
355
|
+
function addExtendedData(target, ext) {
|
|
356
|
+
if (ext !== null && ext !== undefined && typeof ext === "object") {
|
|
357
|
+
target.extendedData = emitVariant(ext);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Emit one reflected Granny morph target (blend shape) in GR2 JSON shape.
|
|
363
|
+
*
|
|
364
|
+
* Morph target vertex data uses the same deinterleaved channel layout as a
|
|
365
|
+
* mesh's primary vertex data.
|
|
366
|
+
*
|
|
367
|
+
* @param {object} mt Reflected Granny `granny_morph_target` object.
|
|
368
|
+
* @param {Gr2NodeClasses} [classes] Opt-in node class map.
|
|
369
|
+
* @returns {object} Emitted morph-target record.
|
|
370
|
+
*/
|
|
371
|
+
function emitMorphTarget(mt, classes = {}) {
|
|
372
|
+
const vd = mt.VertexData,
|
|
373
|
+
verts = vd && vd.Vertices || [];
|
|
374
|
+
return build(classes, "MorphTarget", {
|
|
375
|
+
name: mt.ScalarName ?? "",
|
|
376
|
+
dataIsDeltas: !!mt.DataIsDeltas,
|
|
377
|
+
vertex: emitVertexChannels(verts)
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
function mappedAnnotationRows(set, vertexCount) {
|
|
381
|
+
const annotations = set.VertexAnnotations || [],
|
|
382
|
+
map = scalarArray(set.VertexAnnotationIndices),
|
|
383
|
+
rows = [],
|
|
384
|
+
vertexIndices = [];
|
|
385
|
+
if (set.IndicesMapFromVertexToAnnotation) {
|
|
386
|
+
for (let vertexIndex = 0; vertexIndex < Math.min(map.length, vertexCount); vertexIndex++) {
|
|
387
|
+
const annotationIndex = map[vertexIndex];
|
|
388
|
+
if (!Number.isInteger(annotationIndex) || annotationIndex < 0 || annotationIndex >= annotations.length) continue;
|
|
389
|
+
rows.push(annotations[annotationIndex]);
|
|
390
|
+
vertexIndices.push(vertexIndex);
|
|
391
|
+
}
|
|
392
|
+
} else {
|
|
393
|
+
const count = map.length ? Math.min(map.length, annotations.length) : annotations.length;
|
|
394
|
+
for (let annotationIndex = 0; annotationIndex < count; annotationIndex++) {
|
|
395
|
+
const vertexIndex = map.length ? map[annotationIndex] : annotationIndex;
|
|
396
|
+
if (!Number.isInteger(vertexIndex) || vertexIndex < 0 || vertexIndex >= vertexCount) continue;
|
|
397
|
+
rows.push(annotations[annotationIndex]);
|
|
398
|
+
vertexIndices.push(vertexIndex);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
Object.defineProperty(rows, "__type", {
|
|
402
|
+
value: annotations.__type || [],
|
|
403
|
+
configurable: true
|
|
404
|
+
});
|
|
405
|
+
const identity = rows.length === vertexCount && vertexIndices.every((value, index) => value === index);
|
|
406
|
+
return {
|
|
407
|
+
rows,
|
|
408
|
+
vertexIndices: identity ? null : vertexIndices
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
function emitVertexAnnotationTarget(set, vertexCount, classes = {}) {
|
|
412
|
+
if (!set || !set.VertexAnnotations?.length) return null;
|
|
413
|
+
const mapped = mappedAnnotationRows(set, vertexCount);
|
|
414
|
+
if (!mapped.rows.length) return null;
|
|
415
|
+
const target = {
|
|
416
|
+
name: set.Name ?? "",
|
|
417
|
+
dataIsDeltas: true,
|
|
418
|
+
vertex: emitVertexChannels(mapped.rows)
|
|
419
|
+
};
|
|
420
|
+
if (mapped.vertexIndices) target.vertexIndices = mapped.vertexIndices;
|
|
421
|
+
return build(classes, "MorphTarget", target);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Emit a reflected Granny mesh in GR2 JSON shape.
|
|
426
|
+
*
|
|
427
|
+
* @param {object} mesh Reflected Granny mesh object.
|
|
428
|
+
* @param {Gr2NodeClasses} [classes] Opt-in node class map.
|
|
429
|
+
* @returns {object} Emitted mesh record.
|
|
430
|
+
*/
|
|
431
|
+
function emitMesh(mesh, classes = {}) {
|
|
432
|
+
const o = {};
|
|
433
|
+
o.name = mesh.Name ?? "";
|
|
434
|
+
o.minBounds = [0, 0, 0];
|
|
435
|
+
o.maxBounds = [0, 0, 0];
|
|
436
|
+
o.boneBindings = (mesh.BoneBindings || []).map(bb => build(classes, "BoneBinding", {
|
|
437
|
+
name: bb.BoneName ?? "",
|
|
438
|
+
minBounds: (bb.OBBMin || [0, 0, 0]).map(x => sf(fr(x))),
|
|
439
|
+
maxBounds: (bb.OBBMax || [0, 0, 0]).map(x => sf(fr(x)))
|
|
440
|
+
}));
|
|
441
|
+
const vd = mesh.PrimaryVertexData,
|
|
442
|
+
verts = vd && vd.Vertices || [];
|
|
443
|
+
o.vertex = emitVertexChannels(verts);
|
|
444
|
+
o.morphTargets = (mesh.MorphTargets || []).map(mt => emitMorphTarget(mt, classes));
|
|
445
|
+
o.morphTargets.push(...(vd?.VertexAnnotationSets || []).map(set => emitVertexAnnotationTarget(set, verts.length, classes)).filter(Boolean));
|
|
446
|
+
const topo = mesh.PrimaryTopology || {},
|
|
447
|
+
i32arr = scalarArray(topo.Indices),
|
|
448
|
+
i16arr = scalarArray(topo.Indices16),
|
|
449
|
+
groups = topo.Groups || [];
|
|
450
|
+
o.indices = [];
|
|
451
|
+
let indices = null,
|
|
452
|
+
bpi = 0;
|
|
453
|
+
if (i32arr.length) {
|
|
454
|
+
indices = i32arr;
|
|
455
|
+
bpi = 4;
|
|
456
|
+
} else if (i16arr.length) {
|
|
457
|
+
indices = i16arr.map(x => x & 0xffff);
|
|
458
|
+
bpi = 2;
|
|
459
|
+
}
|
|
460
|
+
if (indices) {
|
|
461
|
+
for (const g of groups) {
|
|
462
|
+
const faces = new Array(g.TriCount * 3),
|
|
463
|
+
start = g.TriFirst * 3;
|
|
464
|
+
for (let i = 0; i < g.TriCount * 3; i++) {
|
|
465
|
+
faces[i] = indices[start + i] >>> 0;
|
|
466
|
+
}
|
|
467
|
+
o.indices.push(build(classes, "IndexGroup", {
|
|
468
|
+
name: `area_${g.MaterialIndex}`,
|
|
469
|
+
bytesPerIndex: bpi,
|
|
470
|
+
faces
|
|
471
|
+
}));
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return build(classes, "Mesh", o);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Emit a reflected Granny skeleton bone in GR2 JSON shape.
|
|
479
|
+
*
|
|
480
|
+
* @param {object} bone Reflected Granny bone object.
|
|
481
|
+
* @param {Gr2NodeClasses} [classes] Opt-in node class map.
|
|
482
|
+
* @returns {object} Emitted bone record.
|
|
483
|
+
*/
|
|
484
|
+
function emitBone(bone, classes = {}) {
|
|
485
|
+
const t = bone.LocalTransform || bone.Transform || {
|
|
486
|
+
flags: 0,
|
|
487
|
+
position: [0, 0, 0],
|
|
488
|
+
orientation: [0, 0, 0, 1],
|
|
489
|
+
scaleShear: [1, 0, 0, 0, 1, 0, 0, 0, 1]
|
|
490
|
+
},
|
|
491
|
+
o = {};
|
|
492
|
+
o.name = bone.Name ?? "";
|
|
493
|
+
o.parentIndex = bone.ParentIndex | 0;
|
|
494
|
+
o.flag = t.flags;
|
|
495
|
+
if (t.flags & 1) o.position = t.position.map(x => sf(fr(x)));
|
|
496
|
+
if (t.flags & 2) o.orientation = t.orientation.map(x => sf(fr(x)));
|
|
497
|
+
if (t.flags & 4) o.scaleShear = t.scaleShear.map(x => sf(fr(x)));
|
|
498
|
+
addExtendedData(o, bone.ExtendedData);
|
|
499
|
+
return build(classes, "Bone", o);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Emit a reflected Granny skeleton in GR2 JSON shape.
|
|
504
|
+
*
|
|
505
|
+
* @param {object|null} skel Reflected Granny skeleton object.
|
|
506
|
+
* @param {Gr2NodeClasses} [classes] Opt-in node class map.
|
|
507
|
+
* @returns {object} Emitted skeleton record.
|
|
508
|
+
*/
|
|
509
|
+
function emitSkeleton(skel, classes = {}) {
|
|
510
|
+
const o = {};
|
|
511
|
+
o.name = skel ? skel.Name ?? "" : "";
|
|
512
|
+
o.bones = skel ? (skel.Bones || []).map(b => emitBone(b, classes)) : [];
|
|
513
|
+
if (skel) addExtendedData(o, skel.ExtendedData);
|
|
514
|
+
return build(classes, "Skeleton", o);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Emit a reflected Granny model in GR2 JSON shape.
|
|
519
|
+
*
|
|
520
|
+
* @param {object} model Reflected Granny model object.
|
|
521
|
+
* @param {object} fileInfo Root reflected Granny file-info object.
|
|
522
|
+
* @param {Gr2NodeClasses} [classes] Opt-in node class map.
|
|
523
|
+
* @returns {object} Emitted model record.
|
|
524
|
+
*/
|
|
525
|
+
function emitModel(model, fileInfo, classes = {}) {
|
|
526
|
+
const o = {};
|
|
527
|
+
o.name = model.Name ?? "";
|
|
528
|
+
o.skeleton = emitSkeleton(model.Skeleton, classes);
|
|
529
|
+
const meshes = fileInfo.Meshes || [];
|
|
530
|
+
o.meshBindings = (model.MeshBindings || []).map(mb => {
|
|
531
|
+
const idx = meshes.indexOf(mb && mb.Mesh);
|
|
532
|
+
return idx;
|
|
533
|
+
});
|
|
534
|
+
addExtendedData(o, model.ExtendedData);
|
|
535
|
+
return build(classes, "Model", o);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Emit a reflected Granny transform track in GR2 JSON shape.
|
|
540
|
+
*
|
|
541
|
+
* @param {object} tt Reflected Granny transform-track object.
|
|
542
|
+
* @param {Gr2NodeClasses} [classes] Opt-in node class map.
|
|
543
|
+
* @returns {object} Emitted transform-track record.
|
|
544
|
+
*/
|
|
545
|
+
function emitTransformTrack(tt, classes = {}) {
|
|
546
|
+
return build(classes, "TransformTrack", {
|
|
547
|
+
name: tt.Name ?? "",
|
|
548
|
+
flags: tt.Flags | 0,
|
|
549
|
+
orientation: emitCurve(tt.OrientationCurve, classes),
|
|
550
|
+
position: emitCurve(tt.PositionCurve, classes),
|
|
551
|
+
scaleShear: emitCurve(tt.ScaleShearCurve, classes)
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Emit a reflected Granny track group in GR2 JSON shape.
|
|
557
|
+
*
|
|
558
|
+
* @param {object} tg Reflected Granny track-group object.
|
|
559
|
+
* @param {Gr2NodeClasses} [classes] Opt-in node class map.
|
|
560
|
+
* @returns {object} Emitted track-group record.
|
|
561
|
+
*/
|
|
562
|
+
function emitTrackGroup(tg, classes = {}) {
|
|
563
|
+
return build(classes, "TrackGroup", {
|
|
564
|
+
name: tg.Name ?? "",
|
|
565
|
+
transformTracks: (tg.TransformTracks || []).map(tt => emitTransformTrack(tt, classes))
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Emit a reflected Granny animation in GR2 JSON shape.
|
|
571
|
+
*
|
|
572
|
+
* @param {object} anim Reflected Granny animation object.
|
|
573
|
+
* @param {Gr2NodeClasses} [classes] Opt-in node class map.
|
|
574
|
+
* @returns {object} Emitted animation record.
|
|
575
|
+
*/
|
|
576
|
+
function emitAnimation(anim, classes = {}) {
|
|
577
|
+
const o = {};
|
|
578
|
+
o.name = anim.Name ?? "";
|
|
579
|
+
o.duration = sf(fr(anim.Duration));
|
|
580
|
+
o.timeStep = sf(fr(anim.TimeStep));
|
|
581
|
+
o.oversampling = sf(fr(anim.Oversampling));
|
|
582
|
+
o.defaultLoopCount = anim.DefaultLoopCount | 0;
|
|
583
|
+
o.flags = anim.Flags | 0;
|
|
584
|
+
o.trackGroups = (anim.TrackGroups || []).filter(t => t).map(tg => emitTrackGroup(tg, classes));
|
|
585
|
+
addExtendedData(o, anim.ExtendedData);
|
|
586
|
+
return build(classes, "Animation", o);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Convert a reflected `granny_file_info` graph into a GR2 JSON object.
|
|
591
|
+
*
|
|
592
|
+
* The key order and numeric conversion rules are stable so downstream tools can
|
|
593
|
+
* compare emitted data.
|
|
594
|
+
*
|
|
595
|
+
* When `options.classes` is given, matching node types are instantiated and
|
|
596
|
+
* populated as class instances instead of plain object literals; an opt-in
|
|
597
|
+
* alternative to walking the returned JSON into application-specific classes
|
|
598
|
+
* by hand. See {@link CLASS_KEYS} for the recognized keys.
|
|
599
|
+
*
|
|
600
|
+
* @param {object} fileInfo Reflected `granny_file_info` object from `reader.js`.
|
|
601
|
+
* @param {number} version Granny file format revision.
|
|
602
|
+
* @param {object} [options] Emission options.
|
|
603
|
+
* @param {Gr2NodeClasses} [options.classes] Opt-in node class map.
|
|
604
|
+
* @returns {Gr2JsonRoot} Plain JSON-compatible `GR2 JSON` object, or a
|
|
605
|
+
* populated `classes.Root` instance when provided.
|
|
606
|
+
*/
|
|
607
|
+
function emitJson(fileInfo, version, options = {}) {
|
|
608
|
+
const {
|
|
609
|
+
classes = {},
|
|
610
|
+
...hydrationOptions
|
|
611
|
+
} = options;
|
|
612
|
+
return build(classes, "Root", {
|
|
613
|
+
grannyFileFormatRevision: version | 0,
|
|
614
|
+
grannyFileSource: fileInfo.FromFileName ?? "",
|
|
615
|
+
meshes: (fileInfo.Meshes || []).filter(m => m).map(m => emitMesh(m, classes)),
|
|
616
|
+
models: (fileInfo.Models || []).filter(m => m).map(m => emitModel(m, fileInfo, classes)),
|
|
617
|
+
animations: (fileInfo.Animations || []).filter(a => a).map(a => emitAnimation(a, classes))
|
|
618
|
+
}, hydrationOptions);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
export { CLASS_KEYS, emitJson };
|
|
622
|
+
//# sourceMappingURL=json.js.map
|