@carbonenginejs/runtime-resource 0.13.0 → 0.14.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 +32 -32
- package/README.md +129 -129
- package/dist/CjsMotherLode.js +1271 -1271
- package/dist/CjsResMan.js +3858 -3858
- package/dist/CjsResManFetchProvider.js +94 -94
- package/dist/CjsResManWorkQueue.js +301 -301
- package/dist/_virtual/_rollupPluginBabelHelpers.js +150 -150
- package/dist/format/CjsBlueReader.js +358 -358
- package/dist/format/CjsByteReader.js +310 -310
- package/dist/format/CjsByteWriter.js +242 -242
- package/dist/format/CjsFormat.js +223 -223
- package/dist/format/CjsFormatError.js +41 -41
- package/dist/format/CjsReader.js +22 -22
- package/dist/format/CjsResourceProbe.js +279 -279
- package/dist/format/CjsStringTable.js +268 -268
- package/dist/format/carbonEffect/CjsCarbonEffectReader.js +265 -265
- package/dist/format/carbonEffect/CjsCarbonEffectWriter.js +373 -373
- package/dist/format/carbonEffect/buildCarbonEffectContainer.js +182 -182
- package/dist/format/carbonEffect/carbonEffectBackendBlock.js +321 -321
- package/dist/format/carbonEffect/carbonEffectRecords.js +1147 -1147
- package/dist/format/carbonEffect/carbonEffectResourceTransform.js +197 -197
- package/dist/format/compareUtf8.js +36 -36
- package/dist/format/effect/effectBodyInventory.js +146 -146
- package/dist/format/effect/effectPermutationGraph.js +257 -257
- package/dist/format/effect/sha256.js +114 -114
- package/dist/format/index.js +11 -11
- package/dist/format/payloadContract.js +193 -193
- package/dist/formats/black/CjsBlackFormat.js +310 -310
- package/dist/formats/black/core/CjsBlackBinaryReader.js +260 -260
- package/dist/formats/black/core/CjsBlackPropertyReaders.js +448 -448
- package/dist/formats/black/core/CjsBlackReader.js +764 -764
- package/dist/formats/black/core/CjsBlackSchemaRegistry.js +540 -540
- package/dist/formats/black/core/black-schema-v1-2026-07-23.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 +199 -199
- package/dist/formats/black/core/schema.js +4 -4
- package/dist/formats/black/index.js +2 -2
- package/dist/formats/bnk/CjsBnkFormat.js +175 -175
- package/dist/formats/bnk/core/busNodes.js +252 -252
- package/dist/formats/bnk/core/effectNodes.js +147 -147
- package/dist/formats/bnk/core/eventAction.js +416 -416
- package/dist/formats/bnk/core/globalSettings.js +215 -215
- package/dist/formats/bnk/core/graph.js +137 -137
- package/dist/formats/bnk/core/helpers.js +512 -512
- package/dist/formats/bnk/core/musicNodes.js +540 -540
- package/dist/formats/bnk/core/nodeBase.js +553 -553
- package/dist/formats/bnk/core/sfxNodes.js +632 -632
- package/dist/formats/bnk/core/soundbanksInfo.js +209 -209
- package/dist/formats/bnk/index.js +2 -2
- package/dist/formats/cmf/CjsCmfFormat.js +497 -497
- package/dist/formats/cmf/core/binary.js +194 -194
- package/dist/formats/cmf/core/buffers.js +237 -237
- 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 +318 -318
- package/dist/formats/cmf/core/pack.js +276 -276
- package/dist/formats/cmf/core/schema.js +374 -374
- package/dist/formats/cmf/core/shared.js +277 -277
- package/dist/formats/cmf/core/writer.js +571 -571
- package/dist/formats/cmf/index.js +2 -2
- package/dist/formats/dds/CjsDdsFormat.js +200 -200
- package/dist/formats/dds/core/bc6h.js +298 -298
- package/dist/formats/dds/core/bc7.js +272 -272
- package/dist/formats/dds/core/helpers.js +901 -862
- package/dist/formats/dds/core/helpers.js.map +1 -1
- package/dist/formats/dds/index.js +2 -2
- package/dist/formats/dxbc/CjsDxbcFormat.js +187 -142
- package/dist/formats/dxbc/CjsDxbcFormat.js.map +1 -1
- package/dist/formats/dxbc/core/DxbcReader.js +266 -266
- package/dist/formats/dxbc/core/container.js +169 -169
- package/dist/formats/dxbc/core/decoder.js +789 -789
- package/dist/formats/dxbc/core/disassemble.js +240 -0
- package/dist/formats/dxbc/core/disassemble.js.map +1 -0
- package/dist/formats/dxbc/core/errors.js +19 -19
- package/dist/formats/dxbc/core/helpers.js +220 -220
- package/dist/formats/dxbc/core/opcodes.js +45 -45
- package/dist/formats/dxbc/core/program.js +91 -91
- package/dist/formats/dxbc/core/signature.js +172 -172
- package/dist/formats/dxbc/index.js +2 -2
- package/dist/formats/fbx/CjsFbxFormat.js +266 -266
- package/dist/formats/fbx/core/helpers.js +3932 -3932
- package/dist/formats/fbx/index.js +2 -2
- package/dist/formats/flac/CjsFlacFormat.js +142 -142
- package/dist/formats/flac/core/helpers.js +315 -315
- package/dist/formats/flac/index.js +2 -2
- package/dist/formats/gif/CjsGifFormat.js +141 -141
- package/dist/formats/gif/core/helpers.js +380 -380
- package/dist/formats/gif/index.js +2 -2
- package/dist/formats/gltf/CjsGltfFormat.js +252 -290
- package/dist/formats/gltf/CjsGltfFormat.js.map +1 -1
- package/dist/formats/gltf/core/helpers.js +287 -307
- package/dist/formats/gltf/core/helpers.js.map +1 -1
- package/dist/formats/gltf/core/json.js +79 -79
- package/dist/formats/gltf/core/parser.js +679 -679
- package/dist/formats/gltf/core/targets.js +173 -173
- package/dist/formats/gltf/index.js +2 -2
- package/dist/formats/gr2/CjsGr2Format.js +289 -289
- package/dist/formats/gr2/core/bitknit2.js +282 -282
- package/dist/formats/gr2/core/curves.js +1047 -1047
- package/dist/formats/gr2/core/gsf.js +72 -72
- package/dist/formats/gr2/core/helpers.js +352 -352
- package/dist/formats/gr2/core/json.js +622 -622
- package/dist/formats/gr2/core/oodle1.js +388 -388
- package/dist/formats/gr2/core/tangents.js +48 -48
- package/dist/formats/gr2/core/targets.js +361 -361
- package/dist/formats/gr2/index.js +2 -2
- package/dist/formats/hlsl/CjsHlslFormat.js +233 -254
- package/dist/formats/hlsl/CjsHlslFormat.js.map +1 -1
- package/dist/formats/hlsl/core/HlslBinaryUtils.js +15 -15
- package/dist/formats/hlsl/core/HlslEffectReadError.js +19 -19
- package/dist/formats/hlsl/core/HlslEffectStateManager.js +130 -130
- package/dist/formats/hlsl/core/HlslRenderStateSetup.js +37 -37
- package/dist/formats/hlsl/core/HlslResourceSetDescription.js +94 -94
- package/dist/formats/hlsl/core/HlslShaderBytecode.js +44 -44
- package/dist/formats/hlsl/core/analysis.js +51 -51
- package/dist/formats/hlsl/core/carbonDescriptionToRuntime.js +850 -850
- package/dist/formats/hlsl/core/detailMapFamily.js +128 -128
- package/dist/formats/hlsl/core/helpers.js +270 -270
- package/dist/formats/hlsl/core/json.js +284 -284
- package/dist/formats/hlsl/core/localLightFamily.js +133 -133
- package/dist/formats/hlsl/core/metadata.js +327 -327
- package/dist/formats/hlsl/core/render-states.js +280 -280
- package/dist/formats/hlsl/core/tr2/HlslRenderContextEnum.js +43 -43
- package/dist/formats/hlsl/core/tr2/resources/HlslEffectRes.js +320 -320
- package/dist/formats/hlsl/core/tr2/resources/HlslShaderPermutation.js +33 -33
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectBindingManifest.js +423 -416
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectBindingManifest.js.map +1 -1
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectConstant.js +40 -40
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectDescription.js +62 -62
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectLibrary.js +52 -52
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectParameterAnnotation.js +38 -38
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectResource.js +50 -50
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectStageInput.js +86 -86
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectTechnique.js +31 -31
- package/dist/formats/hlsl/core/tr2/shader/HlslPass.js +42 -42
- package/dist/formats/hlsl/core/tr2/shader/HlslSamplerDescription.js +55 -55
- package/dist/formats/hlsl/core/tr2/shader/HlslSamplerSetup.js +29 -29
- package/dist/formats/hlsl/core/tr2/shader/HlslShader.js +220 -220
- package/dist/formats/hlsl/core/tr2/shader/HlslShaderOption.js +30 -30
- package/dist/formats/hlsl/index.js +3 -3
- package/dist/formats/index.js +33 -33
- package/dist/formats/jpeg/CjsJpegFormat.js +212 -212
- package/dist/formats/jpeg/core/helpers.js +402 -402
- package/dist/formats/jpeg/core/jpeg.js +480 -480
- package/dist/formats/jpeg/index.js +2 -2
- package/dist/formats/mp3/CjsMp3Format.js +197 -197
- package/dist/formats/mp3/core/helpers.js +375 -375
- package/dist/formats/mp3/index.js +2 -2
- package/dist/formats/mp4/CjsMp4Format.js +197 -197
- package/dist/formats/mp4/core/helpers.js +484 -484
- package/dist/formats/mp4/index.js +2 -2
- package/dist/formats/obj/CjsObjFormat.js +232 -253
- package/dist/formats/obj/CjsObjFormat.js.map +1 -1
- package/dist/formats/obj/core/helpers.js +553 -573
- package/dist/formats/obj/core/helpers.js.map +1 -1
- 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 +143 -143
- package/dist/formats/ogg/core/helpers.js +410 -410
- package/dist/formats/ogg/core/imdct.js +178 -178
- package/dist/formats/ogg/core/vorbis.js +1017 -1017
- package/dist/formats/ogg/index.js +2 -2
- package/dist/formats/pickle/CjsPickleFormat.js +214 -214
- package/dist/formats/pickle/core/CjsPickleProtocol0Reader.js +551 -551
- package/dist/formats/pickle/index.js +2 -2
- package/dist/formats/png/CjsPngFormat.js +201 -201
- package/dist/formats/png/core/helpers.js +635 -635
- package/dist/formats/png/index.js +2 -2
- package/dist/formats/red/CjsRedFormat.js +263 -263
- package/dist/formats/red/core/CjsRedReader.js +246 -246
- package/dist/formats/red/core/blackDefinitions.js +3 -3
- package/dist/formats/red/core/helpers.js +158 -158
- package/dist/formats/red/core/redGraph.js +71 -71
- package/dist/formats/red/core/schema.js +4 -4
- package/dist/formats/red/index.js +2 -2
- package/dist/formats/stl/CjsStlFormat.js +320 -365
- package/dist/formats/stl/CjsStlFormat.js.map +1 -1
- package/dist/formats/stl/core/helpers.js +241 -261
- package/dist/formats/stl/core/helpers.js.map +1 -1
- package/dist/formats/stl/core/json.js +51 -51
- package/dist/formats/stl/core/stl.js +642 -642
- package/dist/formats/stl/core/targets.js +173 -173
- package/dist/formats/stl/index.js +2 -2
- package/dist/formats/tga/CjsTgaFormat.js +197 -197
- package/dist/formats/tga/core/helpers.js +493 -493
- package/dist/formats/tga/index.js +2 -2
- package/dist/formats/wav/CjsWavFormat.js +198 -198
- package/dist/formats/wav/core/helpers.js +365 -365
- package/dist/formats/wav/index.js +2 -2
- package/dist/formats/webgl/CjsWebglFormat.js +199 -199
- package/dist/formats/webgl/core/buildGlslEffectContainer.js +70 -70
- package/dist/formats/webgl/core/effectPackage.js +900 -900
- package/dist/formats/webgl/core/errors.js +27 -27
- package/dist/formats/webgl/core/glsl/DxbcGlslEmitter.js +2820 -2820
- package/dist/formats/webgl/core/glsl/DxbcGlslHelpers.js +89 -89
- package/dist/formats/webgl/core/glsl/DxbcGlslOperandFormatter.js +486 -486
- package/dist/formats/webgl/core/glsl/packedLightFixups.js +98 -98
- package/dist/formats/webgl/core/glslBackendBlock.js +552 -552
- package/dist/formats/webgl/core/glslBackendBodySet.js +243 -243
- package/dist/formats/webgl/core/glslEffectCompleteness.js +85 -85
- package/dist/formats/webgl/core/glslEffectCompleteness.js.map +1 -1
- package/dist/formats/webgl/core/helpers.js +167 -167
- package/dist/formats/webgl/core/inspectGlslEffectContainer.js +122 -122
- package/dist/formats/webgl/core/readGlslEffectContainer.js +202 -256
- package/dist/formats/webgl/core/readGlslEffectContainer.js.map +1 -1
- package/dist/formats/webgl/index.js +2 -2
- package/dist/formats/webgpu/CjsWebgpuFormat.js +357 -357
- package/dist/formats/webgpu/core/buildCarbonEffectContainer.js +89 -89
- package/dist/formats/webgpu/core/carbonWebgpu/CarbonWebgpuContainer.js +354 -354
- package/dist/formats/webgpu/core/carbonWebgpu/containerViews.js +355 -355
- package/dist/formats/webgpu/core/carbonWebgpu/validateContainer.js +90 -90
- package/dist/formats/webgpu/core/effectAnalysis.js +82 -82
- package/dist/formats/webgpu/core/effectBackendBodySet.js +306 -306
- package/dist/formats/webgpu/core/errors.js +20 -20
- package/dist/formats/webgpu/core/helpers.js +443 -443
- package/dist/formats/webgpu/core/ir/analyzeRegisterValues.js +212 -212
- package/dist/formats/webgpu/core/ir/buildControlFlow.js +220 -220
- package/dist/formats/webgpu/core/ir/indexableTemps.js +137 -137
- package/dist/formats/webgpu/core/ir/inferValueTypes.js +449 -449
- package/dist/formats/webgpu/core/ir/lowerDxbcToIr.js +494 -494
- package/dist/formats/webgpu/core/ir/resolveRegisterFlow.js +177 -177
- package/dist/formats/webgpu/core/ir/sourceLanes.js +61 -61
- package/dist/formats/webgpu/core/packageEffect.js +381 -381
- package/dist/formats/webgpu/core/packageEffectSelection.js +164 -164
- package/dist/formats/webgpu/core/packageMetadata.js +17 -17
- package/dist/formats/webgpu/core/schema.js +4 -4
- package/dist/formats/webgpu/core/wgsl/buildResourceTransformPlan.js +263 -263
- package/dist/formats/webgpu/core/wgsl/buildWgslBindingPlan.js +172 -172
- package/dist/formats/webgpu/core/wgsl/buildWgslSet.js +325 -325
- package/dist/formats/webgpu/core/wgsl/emitWgsl.js +356 -356
- package/dist/formats/webgpu/core/wgsl/hoistEscapingValues.js +77 -77
- package/dist/formats/webgpu/core/wgsl/lowerBindingLayout.js +451 -451
- package/dist/formats/webgpu/core/wgsl/lowerComputeProgram.js +735 -735
- package/dist/formats/webgpu/core/wgsl/lowerCreateHistogramsComputeProgram.js +457 -457
- package/dist/formats/webgpu/core/wgsl/lowerFragmentProgram.js +1572 -1572
- package/dist/formats/webgpu/core/wgsl/lowerMergeHistogramsComputeProgram.js +659 -659
- package/dist/formats/webgpu/core/wgsl/lowerParticleClearComputePrograms.js +734 -734
- package/dist/formats/webgpu/core/wgsl/lowerParticleEmitComputeProgram.js +583 -583
- package/dist/formats/webgpu/core/wgsl/lowerSkinVerticesComputeProgram.js +621 -621
- package/dist/formats/webgpu/core/wgsl/lowerSortComputeProgram.js +824 -824
- package/dist/formats/webgpu/core/wgsl/lowerSortInnerComputeProgram.js +697 -697
- package/dist/formats/webgpu/core/wgsl/lowerSortStepComputeProgram.js +559 -559
- package/dist/formats/webgpu/core/wgsl/lowerVertexProgram.js +1328 -1328
- package/dist/formats/webgpu/core/wgsl/particleEmitSemanticDigest.js +110 -110
- package/dist/formats/webgpu/core/wgsl/precisionControls.js +55 -55
- package/dist/formats/webgpu/core/wgsl/selectionPlans.js +717 -717
- package/dist/formats/webgpu/core/wgsl/uniformity.js +78 -78
- package/dist/formats/webgpu/core/wgsl/validateExactComputeIr.js +196 -196
- package/dist/formats/webgpu/core/wgsl/validateHandleOperand.js +37 -37
- package/dist/formats/webgpu/index.js +2 -2
- package/dist/formats/webm/CjsWebmFormat.js +197 -197
- package/dist/formats/webm/core/helpers.js +572 -572
- package/dist/formats/webm/index.js +2 -2
- package/dist/formats/webp/CjsWebpFormat.js +140 -140
- package/dist/formats/webp/core/helpers.js +237 -237
- package/dist/formats/webp/index.js +2 -2
- package/dist/formats/wem/CjsWemFormat.js +250 -250
- package/dist/formats/wem/core/bitStream.js +261 -261
- package/dist/formats/wem/core/codebookLibrary.js +164 -164
- package/dist/formats/wem/core/helpers.js +437 -437
- 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 +134 -134
- package/dist/formats/yaml/core/CjsYamlReader.js +400 -400
- package/dist/formats/yaml/core/helpers.js +196 -196
- package/dist/formats/yaml/index.js +2 -2
- package/dist/index.js +64 -64
- package/dist/resource/CjsLoadingObject.js +19 -19
- package/dist/resource/CjsResource.js +801 -801
- package/dist/resource/ResourceHandlerMode.js +14 -14
- package/dist/resource/Tr2LightProfileRes.js +32 -32
- package/dist/resource/audio/AudioGeometryResData.js +47 -47
- package/dist/resource/audio/CjsAudioBufferRes.js +86 -86
- package/dist/resource/audio/CjsAudioRes.js +213 -213
- package/dist/resource/audio/index.js +4 -4
- package/dist/resource/geometry/MeshDecalData.js +37 -37
- package/dist/resource/geometry/MeshDecalLodData.js +34 -34
- package/dist/resource/geometry/TriGeometryRes.js +675 -675
- package/dist/resource/geometry/TriGeometryResAreaData.js +59 -59
- package/dist/resource/geometry/TriGeometryResJointData.js +38 -38
- package/dist/resource/geometry/TriGeometryResLodData.js +88 -88
- package/dist/resource/geometry/TriGeometryResMeshData.js +63 -63
- package/dist/resource/geometry/TriGeometryResSkeletonData.js +34 -34
- package/dist/resource/geometry/TriJointBinding.js +38 -38
- package/dist/resource/geometry/TriMorphTargetGeometryConstants.js +46 -46
- package/dist/resource/geometry/TriRtGeometryConstants.js +88 -88
- package/dist/resource/geometry/granny/GStateBindingCallbackData.js +31 -31
- package/dist/resource/geometry/granny/Tr2GrannyIntersectionResult.js +60 -60
- package/dist/resource/geometry/granny/Tr2GrannyStateRes.js +36 -36
- package/dist/resource/geometry/granny/TriGrannyRes.js +35 -35
- package/dist/resource/geometry/granny/enums.js +10 -10
- package/dist/resource/geometry/granny/index.js +6 -6
- package/dist/resource/geometry/index.js +17 -17
- package/dist/resource/index.js +54 -54
- package/dist/resource/resourceBoundary.js +64 -64
- package/dist/resource/shader/Tr2EffectRes.js +336 -336
- package/dist/resource/shader/Tr2MaterialArea.js +31 -31
- package/dist/resource/shader/Tr2MaterialMesh.js +27 -27
- package/dist/resource/shader/Tr2MaterialRes.js +31 -31
- package/dist/resource/shader/Tr2Shader.js +283 -283
- package/dist/resource/shader/Tr2ShaderPermutation.js +43 -43
- package/dist/resource/shader/index.js +17 -17
- package/dist/resource/shader/reflection/Tr2EffectConstant.js +143 -143
- package/dist/resource/shader/reflection/Tr2EffectDefine.js +30 -30
- package/dist/resource/shader/reflection/Tr2EffectDescription.js +114 -114
- package/dist/resource/shader/reflection/Tr2EffectLibrary.js +168 -168
- package/dist/resource/shader/reflection/Tr2EffectParameterAnnotation.js +125 -125
- package/dist/resource/shader/reflection/Tr2EffectResource.js +120 -120
- package/dist/resource/shader/reflection/Tr2EffectStageInput.js +372 -372
- package/dist/resource/shader/reflection/Tr2EffectTechnique.js +78 -78
- package/dist/resource/shader/reflection/Tr2Pass.js +168 -168
- package/dist/resource/shader/reflection/carbonRecordFields.js +159 -159
- package/dist/resource/shader/reflection/shaderStage.js +22 -22
- package/dist/resource/shader/sampler/Tr2SamplerSetup.js +135 -135
- package/dist/resource/texture/CjsTextureArrayRes.js +472 -472
- package/dist/resource/texture/CjsTextureArrayResParameterProxy.js +179 -179
- package/dist/resource/texture/Tr2ImageRes.js +120 -120
- package/dist/resource/texture/Tr2TextureLodManager.js +82 -82
- package/dist/resource/texture/Tr2TextureLodUpdateRequest.js +37 -37
- package/dist/resource/texture/Tr2TexturePackChannel.js +37 -37
- package/dist/resource/texture/Tr2TexturePipeline.js +54 -54
- package/dist/resource/texture/Tr2TexturePipelineParams.js +34 -34
- package/dist/resource/texture/Tr2TexturePipelineStepCompress.js +40 -40
- package/dist/resource/texture/Tr2TexturePipelineStepGenerateMips.js +22 -22
- package/dist/resource/texture/Tr2TexturePipelineStepLimitSize.js +34 -34
- package/dist/resource/texture/Tr2TexturePipelineStepLoad.js +31 -31
- package/dist/resource/texture/Tr2TexturePipelineStepPack.js +43 -43
- package/dist/resource/texture/TriTextureRes.js +359 -359
- package/dist/resource/texture/index.js +15 -15
- package/dist/resource/texture/texturePipelineBehavior.js +308 -308
- package/dist/worker/CjsResManMainThreadLoader.js +89 -89
- package/dist/worker/CjsResManWorker.js +218 -218
- package/dist/worker/CjsResManWorkerLoader.js +437 -437
- package/dist/worker/protocol.js +12 -12
- package/docs/README.md +98 -98
- package/docs/architecture.md +118 -118
- package/docs/concepts/resource-lifecycle.md +226 -226
- package/docs/concepts/shader-resource-model.md +111 -111
- package/docs/concepts/writing-an-engine-adapter.md +115 -115
- package/docs/formats/README.md +138 -138
- package/docs/formats/carbon-effect-container.md +553 -553
- package/docs/formats/dxbc/README.md +68 -68
- package/docs/formats/dxbc/architecture.md +80 -80
- package/docs/formats/dxbc/reference/api.md +105 -77
- package/docs/formats/dxbc/reference/classes/README.md +9 -9
- package/docs/formats/dxbc/reference/decoded-output.md +122 -122
- package/docs/formats/gr2.md +160 -160
- package/docs/formats/hlsl/README.md +54 -54
- package/docs/formats/hlsl/architecture.md +66 -65
- package/docs/formats/hlsl/guides/hydrating-json-output.md +60 -60
- package/docs/formats/hlsl/guides/reading-effects.md +68 -64
- package/docs/formats/hlsl/reference/advanced-analysis.md +61 -61
- package/docs/formats/hlsl/reference/api.md +91 -92
- package/docs/formats/hlsl/reference/classes/README.md +11 -11
- package/docs/formats/hlsl/reference/json-graph.md +97 -97
- package/docs/formats/pickle.md +82 -82
- package/docs/formats/provenance.md +196 -196
- package/docs/formats/stl.md +37 -37
- package/docs/formats/webgl/README.md +115 -115
- package/docs/formats/webgl/architecture.md +69 -69
- package/docs/formats/webgl/carbon-constant-layouts.md +326 -326
- package/docs/formats/webgl/decl-io.md +1234 -1234
- package/docs/formats/webgl/memory-structured.md +890 -890
- package/docs/formats/webgl/reference/classes/README.md +9 -9
- package/docs/formats/webgl/texture-sample.md +964 -964
- package/docs/formats/webgpu/README.md +84 -84
- package/docs/formats/webgpu/architecture.md +95 -95
- package/docs/formats/webgpu/formats/carbon-webgpu.md +215 -215
- package/docs/formats/webgpu/guides/effect-packaging.md +189 -189
- package/docs/formats/webgpu/reference/api.md +196 -196
- package/docs/formats/webgpu/reference/classes/README.md +9 -9
- package/docs/formats/webgpu/reference/wgsl-compatibility.md +1546 -1546
- package/docs/formats/wwise.md +146 -146
- package/docs/reference/classes/README.md +35 -35
- package/docs/reference/classes/audio.md +30 -30
- package/docs/reference/classes/core.md +216 -216
- package/docs/reference/classes/dropped.md +46 -46
- package/docs/reference/classes/formats.md +944 -944
- package/docs/reference/classes/resources.md +456 -456
- package/docs/reference/classes/texture.md +26 -26
- package/docs/reference/events.md +117 -117
- package/docs/reference/motherlode-cache.md +275 -275
- package/docs/reference/queues.md +194 -194
- package/docs/reference/reload.md +107 -107
- package/docs/reference/texture-arrays.md +113 -113
- package/docs/reference/texture-pipeline.md +53 -53
- package/docs/reference/workers.md +142 -142
- package/docs/roadmap.md +150 -150
- 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 +21 -21
- 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/dxbc/LICENSE +21 -21
- package/format-notices/dxbc/NOTICE +20 -20
- 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 -21
- package/format-notices/gr2/NOTICE +60 -60
- package/format-notices/gr2/THIRD-PARTY-NOTICES.md +93 -93
- package/format-notices/hlsl/LICENSE +21 -21
- package/format-notices/hlsl/NOTICE +25 -25
- 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/webgl/LICENSE +21 -21
- package/format-notices/webgl/NOTICE +35 -35
- package/format-notices/webgpu/LICENSE +21 -21
- package/format-notices/webgpu/NOTICE +31 -31
- 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 +63 -63
|
@@ -1,622 +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("CjsGr2Format 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
|
|
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("CjsGr2Format 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
|