framefields 2.3.2 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -1
- package/dist/audio/index.d.mts +4 -4
- package/dist/audio/index.mjs +10 -10
- package/dist/{audio-C7Kn5xBm.mjs → audio-CPApYcWF.mjs} +4 -4
- package/dist/{audio-C7Kn5xBm.mjs.map → audio-CPApYcWF.mjs.map} +1 -1
- package/dist/{audio-BNnEclHU.d.mts → audio-DHuEMOtQ.d.mts} +3 -3
- package/dist/{audio-BNnEclHU.d.mts.map → audio-DHuEMOtQ.d.mts.map} +1 -1
- package/dist/{dist-fjKpBYkc.mjs → dist-ClyC_d66.mjs} +9 -2
- package/dist/dist-ClyC_d66.mjs.map +1 -0
- package/dist/{dist-CPUIfrtw.mjs → dist-CrK3rmyN.mjs} +180 -58
- package/dist/dist-CrK3rmyN.mjs.map +1 -0
- package/dist/{dist-CturBK2Z.mjs → dist-CspOG4V1.mjs} +1210 -748
- package/dist/dist-CspOG4V1.mjs.map +1 -0
- package/dist/{dist-BY0bIWgr.mjs → dist-SB9qfAko.mjs} +2 -2
- package/dist/{dist-BY0bIWgr.mjs.map → dist-SB9qfAko.mjs.map} +1 -1
- package/dist/effects/index.d.mts +4 -4
- package/dist/effects/index.mjs +35 -35
- package/dist/{effects-CW1VgdI5.mjs → effects-DxylPSuI.mjs} +3 -3
- package/dist/{effects-CW1VgdI5.mjs.map → effects-DxylPSuI.mjs.map} +1 -1
- package/dist/fonts/index.mjs +2 -2
- package/dist/{fonts-EgMNL8KE.mjs → fonts-CsMDfqv9.mjs} +2 -2
- package/dist/{fonts-EgMNL8KE.mjs.map → fonts-CsMDfqv9.mjs.map} +1 -1
- package/dist/{gpu-CN14e7Bi.mjs → gpu-DtT5I4ME.mjs} +2 -2
- package/dist/{gpu-CN14e7Bi.mjs.map → gpu-DtT5I4ME.mjs.map} +1 -1
- package/dist/{index-Cg2ptXcs.d.mts → index-B1XcyMm8.d.mts} +2 -2
- package/dist/{index-Cg2ptXcs.d.mts.map → index-B1XcyMm8.d.mts.map} +1 -1
- package/dist/{index-BU51pxZO.d.mts → index-B2Xesdug.d.mts} +4 -4
- package/dist/{index-BU51pxZO.d.mts.map → index-B2Xesdug.d.mts.map} +1 -1
- package/dist/{index-QmkcUL3W.d.mts → index-BxARm93R.d.mts} +2 -2
- package/dist/{index-QmkcUL3W.d.mts.map → index-BxARm93R.d.mts.map} +1 -1
- package/dist/{index-CeRv1KC0.d.mts → index-C0o3lLyA.d.mts} +3 -3
- package/dist/{index-CeRv1KC0.d.mts.map → index-C0o3lLyA.d.mts.map} +1 -1
- package/dist/{index-B3BwLHa6.d.mts → index-D-l-yCv6.d.mts} +3 -3
- package/dist/{index-B3BwLHa6.d.mts.map → index-D-l-yCv6.d.mts.map} +1 -1
- package/dist/{index-AdrZIWT0.d.mts → index-DujpgUUq.d.mts} +19 -2
- package/dist/index-DujpgUUq.d.mts.map +1 -0
- package/dist/index.d.mts +178 -10
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +488 -93
- package/dist/index.mjs.map +1 -1
- package/dist/preview/index.d.mts +2 -2
- package/dist/preview/index.mjs +10 -10
- package/dist/{preview-1sjnhHQL.mjs → preview-D2dMmokw.mjs} +2 -2
- package/dist/{preview-1sjnhHQL.mjs.map → preview-D2dMmokw.mjs.map} +1 -1
- package/dist/preview-engine/audio.mjs +1 -1
- package/dist/preview-engine/chunk-266DECPQ.mjs +1 -0
- package/dist/preview-engine/{chunk-SZW5J72T.mjs → chunk-2DDBSI75.mjs} +1 -1
- package/dist/preview-engine/{chunk-QXCY2ATH.mjs → chunk-2GIWWDE4.mjs} +1 -1
- package/dist/preview-engine/{chunk-U4JIFQRR.mjs → chunk-34ACEGNW.mjs} +1 -1
- package/dist/preview-engine/{chunk-AY7UX37L.mjs → chunk-3ACCCPBN.mjs} +1 -1
- package/dist/preview-engine/{chunk-VK2CVMWJ.mjs → chunk-5E5J4KT4.mjs} +1 -1
- package/dist/preview-engine/{chunk-T2FE5VOW.mjs → chunk-5RQHNB6Y.mjs} +1 -1
- package/dist/preview-engine/{chunk-TS3JI3BH.mjs → chunk-67SSYK7D.mjs} +1 -1
- package/dist/preview-engine/{chunk-PL4IH5V4.mjs → chunk-6K7US2WD.mjs} +1 -1
- package/dist/preview-engine/{chunk-PEWYB6WP.mjs → chunk-7LVOSEGN.mjs} +1 -1
- package/dist/preview-engine/chunk-7QJUC6YY.mjs +1525 -0
- package/dist/preview-engine/{chunk-PSRQA3QW.mjs → chunk-A5OVKZ52.mjs} +1 -1
- package/dist/preview-engine/{chunk-PXT52LEH.mjs → chunk-C6Z7H2RZ.mjs} +1 -1
- package/dist/preview-engine/chunk-CPFPY35C.mjs +1 -0
- package/dist/preview-engine/{chunk-7EPIRODI.mjs → chunk-DOCSX45C.mjs} +1 -1
- package/dist/preview-engine/{chunk-GSFN4WCH.mjs → chunk-FFGBUS76.mjs} +1 -1
- package/dist/preview-engine/{chunk-IR5DNNWR.mjs → chunk-FFMPC7QA.mjs} +1 -1
- package/dist/preview-engine/{chunk-IUPDOATX.mjs → chunk-FHKBALVI.mjs} +1 -1
- package/dist/preview-engine/{chunk-HE4R7EZM.mjs → chunk-G4J662EL.mjs} +1 -1
- package/dist/preview-engine/{chunk-5W4AFQP7.mjs → chunk-GNG4YH2W.mjs} +1 -1
- package/dist/preview-engine/{chunk-L6BH5J4P.mjs → chunk-GQLZXCW3.mjs} +1 -1
- package/dist/preview-engine/{chunk-EVXWDOCL.mjs → chunk-HDGFNBYK.mjs} +1 -1
- package/dist/preview-engine/{chunk-JXNG2ACR.mjs → chunk-HNNIVJ2K.mjs} +1 -1
- package/dist/preview-engine/{chunk-FU7AIAMM.mjs → chunk-HUKAC5MJ.mjs} +1 -1
- package/dist/preview-engine/{chunk-44CQSOYE.mjs → chunk-JX22B2FS.mjs} +1 -1
- package/dist/preview-engine/{chunk-DIGIQ5MJ.mjs → chunk-KAQUNOVB.mjs} +1 -1
- package/dist/preview-engine/{chunk-MLY5M7Y5.mjs → chunk-KT35IPCF.mjs} +1 -1
- package/dist/preview-engine/{chunk-VXS5SIEC.mjs → chunk-LIQA5OOU.mjs} +1 -1
- package/dist/preview-engine/{chunk-SGPRLTNF.mjs → chunk-LK3T65RB.mjs} +1 -1
- package/dist/preview-engine/{chunk-YQZOGEPZ.mjs → chunk-LLDIDE5Q.mjs} +1 -1
- package/dist/preview-engine/chunk-NNQUIVTE.mjs +5 -0
- package/dist/preview-engine/{chunk-5AUB4Y3L.mjs → chunk-NRAZV5OA.mjs} +1 -1
- package/dist/preview-engine/{chunk-VGZZSPDN.mjs → chunk-NTVDL3RS.mjs} +1 -1
- package/dist/preview-engine/{chunk-BSOJR4JU.mjs → chunk-O6NRIXS5.mjs} +1 -1
- package/dist/preview-engine/{chunk-OKH2VU2U.mjs → chunk-PZF6T7DM.mjs} +1 -1
- package/dist/preview-engine/{chunk-OJ2PKBXE.mjs → chunk-QJZKIY4H.mjs} +1 -1
- package/dist/preview-engine/{chunk-WFGJXCZT.mjs → chunk-R26SY5D4.mjs} +1 -1
- package/dist/preview-engine/{chunk-EYWPOCZW.mjs → chunk-RDP6QROU.mjs} +1 -1
- package/dist/preview-engine/{chunk-J2R5R7YY.mjs → chunk-RKVB47IA.mjs} +1 -1
- package/dist/preview-engine/{chunk-PAQNDZQB.mjs → chunk-SWXVITCQ.mjs} +1 -1
- package/dist/preview-engine/{chunk-KERW7QJ4.mjs → chunk-UZBVCYRY.mjs} +1 -1
- package/dist/preview-engine/{chunk-Q22PJXFJ.mjs → chunk-WACWOKEP.mjs} +1 -1
- package/dist/preview-engine/{chunk-AXHB4J37.mjs → chunk-WCZ5DKZ4.mjs} +1 -1
- package/dist/preview-engine/{chunk-WH5Q2NFN.mjs → chunk-WJJIISQJ.mjs} +1 -1
- package/dist/preview-engine/chunk-XDMZP3E2.mjs +1 -0
- package/dist/preview-engine/{chunk-7G3XIOP7.mjs → chunk-Z6UKUHPU.mjs} +1 -1
- package/dist/preview-engine/{chunk-WUKH7BD7.mjs → chunk-ZKPQGQE3.mjs} +1 -1
- package/dist/preview-engine/effects.mjs +1 -1
- package/dist/preview-engine/framefields.mjs +32 -25
- package/dist/preview-engine/player.mjs +1 -1
- package/dist/preview-engine/{renderers-2P6KXWEZ.mjs → renderers-3CXFGRE7.mjs} +1 -1
- package/dist/preview-engine/{renderers-KZWGSKRF.mjs → renderers-3FC3WCJN.mjs} +1 -1
- package/dist/preview-engine/renderers-3S2FM33K.mjs +1 -0
- package/dist/preview-engine/{renderers-5FQA2DP4.mjs → renderers-4AJWVIJG.mjs} +1 -1
- package/dist/preview-engine/renderers-53ZTBI3C.mjs +1 -0
- package/dist/preview-engine/renderers-5USBVCMQ.mjs +1 -0
- package/dist/preview-engine/renderers-65G6BLEA.mjs +1 -0
- package/dist/preview-engine/{renderers-PYWXELLG.mjs → renderers-6JZ4HYIU.mjs} +1 -1
- package/dist/preview-engine/{renderers-3GHEWWVX.mjs → renderers-75TL7RLS.mjs} +1 -1
- package/dist/preview-engine/{renderers-U6KY34TP.mjs → renderers-7CPYTCNW.mjs} +1 -1
- package/dist/preview-engine/renderers-7XU7BXE7.mjs +1 -0
- package/dist/preview-engine/{renderers-2VN3AH45.mjs → renderers-AZYJFJLO.mjs} +1 -1
- package/dist/preview-engine/{renderers-TR2V2HZ2.mjs → renderers-BDWVXYTW.mjs} +1 -1
- package/dist/preview-engine/renderers-BFXM32BC.mjs +1 -0
- package/dist/preview-engine/renderers-CDXHCWWK.mjs +1 -0
- package/dist/preview-engine/{renderers-N7FR54V2.mjs → renderers-CK3ZL3GM.mjs} +1 -1
- package/dist/preview-engine/renderers-CLUN7WU6.mjs +1 -0
- package/dist/preview-engine/renderers-DTB4HEXU.mjs +1 -0
- package/dist/preview-engine/renderers-EFKNRLYF.mjs +1 -0
- package/dist/preview-engine/{renderers-UPTJJE5F.mjs → renderers-FADYGSLK.mjs} +1 -1
- package/dist/preview-engine/{renderers-I5E2RSV4.mjs → renderers-FKH5S64C.mjs} +1 -1
- package/dist/preview-engine/{renderers-BSKZXITT.mjs → renderers-FM6A5YR4.mjs} +1 -1
- package/dist/preview-engine/renderers-G2K7ZA5O.mjs +1 -0
- package/dist/preview-engine/{renderers-D6T6IPER.mjs → renderers-GAIUTII6.mjs} +1 -1
- package/dist/preview-engine/renderers-GTUO5LIV.mjs +1 -0
- package/dist/preview-engine/{renderers-A6HM64UZ.mjs → renderers-GUPEJK3O.mjs} +1 -1
- package/dist/preview-engine/{renderers-IWQ3V6AJ.mjs → renderers-HSJIVP57.mjs} +1 -1
- package/dist/preview-engine/{renderers-4GRVAW2W.mjs → renderers-HZHEGONW.mjs} +1 -1
- package/dist/preview-engine/{renderers-NWHS7N2L.mjs → renderers-IHACBWXI.mjs} +1 -1
- package/dist/preview-engine/{renderers-3YCJOINH.mjs → renderers-IHRFEZNP.mjs} +1 -1
- package/dist/preview-engine/{renderers-A7VH3ON5.mjs → renderers-IJDQJEE5.mjs} +1 -1
- package/dist/preview-engine/{renderers-OT7D3BUA.mjs → renderers-IO3BVVJ7.mjs} +1 -1
- package/dist/preview-engine/renderers-IR772VSN.mjs +1 -0
- package/dist/preview-engine/{renderers-EJWPVVQR.mjs → renderers-K7B5PQBT.mjs} +1 -1
- package/dist/preview-engine/renderers-L6TRJOXA.mjs +1 -0
- package/dist/preview-engine/{renderers-N7TS5562.mjs → renderers-LVLVJHOL.mjs} +1 -1
- package/dist/preview-engine/{renderers-FK72LKQC.mjs → renderers-MBSOKWKB.mjs} +1 -1
- package/dist/preview-engine/{renderers-NC64EQDE.mjs → renderers-N6H6RSF2.mjs} +1 -1
- package/dist/preview-engine/{renderers-ZHZMGMLN.mjs → renderers-NJLGPPX7.mjs} +1 -1
- package/dist/preview-engine/renderers-O5NFQYRQ.mjs +1 -0
- package/dist/preview-engine/renderers-O6V3OEKX.mjs +1 -0
- package/dist/preview-engine/renderers-OODA27UH.mjs +1 -0
- package/dist/preview-engine/{renderers-6CG7DBTB.mjs → renderers-R4WMM6IX.mjs} +1 -1
- package/dist/preview-engine/renderers-RIGW33ZI.mjs +1 -0
- package/dist/preview-engine/{renderers-RLHTNLRE.mjs → renderers-RKZGYWDG.mjs} +1 -1
- package/dist/preview-engine/renderers-RUZRBQ4K.mjs +1 -0
- package/dist/preview-engine/renderers-SKB2GGKS.mjs +1 -0
- package/dist/preview-engine/{renderers-6OGFUSH6.mjs → renderers-SW7FIEKO.mjs} +1 -1
- package/dist/preview-engine/renderers-T4D2TASM.mjs +1 -0
- package/dist/preview-engine/renderers-T74XV36Q.mjs +1 -0
- package/dist/preview-engine/{renderers-F55XFVMP.mjs → renderers-TCNPEANL.mjs} +1 -1
- package/dist/preview-engine/renderers-TOPW2UM3.mjs +1 -0
- package/dist/preview-engine/{renderers-5YEIUTVN.mjs → renderers-TY7DVI7E.mjs} +1 -1
- package/dist/preview-engine/{renderers-WP2LBR5U.mjs → renderers-U55KRIOV.mjs} +3 -3
- package/dist/preview-engine/{renderers-YMPXGYRU.mjs → renderers-UDOBX433.mjs} +1 -1
- package/dist/preview-engine/{renderers-CRRLV7IO.mjs → renderers-UMPOVFRA.mjs} +1 -1
- package/dist/preview-engine/renderers-UO5G3Y2G.mjs +1 -0
- package/dist/preview-engine/renderers-UOV7VOJJ.mjs +1 -0
- package/dist/preview-engine/{renderers-MON4QFRF.mjs → renderers-UWKSTSTA.mjs} +1 -1
- package/dist/preview-engine/renderers-VHPAOUTA.mjs +1 -0
- package/dist/preview-engine/{renderers-E76OKK66.mjs → renderers-WR6MKT5S.mjs} +1 -1
- package/dist/preview-engine/{renderers-MCECHPCL.mjs → renderers-XKHNBARD.mjs} +1 -1
- package/dist/preview-engine/renderers-YEQRQJFC.mjs +1 -0
- package/dist/preview-engine/{renderers-RJO6H4FC.mjs → renderers-YRZ3WODX.mjs} +1 -1
- package/dist/preview-engine/renderers-YUTFGVRY.mjs +1 -0
- package/dist/preview-engine/{renderers-3SRG77SC.mjs → renderers-YXOTRKPA.mjs} +1 -1
- package/dist/preview-engine/renderers-ZOU5ARVD.mjs +1 -0
- package/dist/preview-engine/renderers-ZW75LQTR.mjs +1 -0
- package/dist/preview-engine/signals.mjs +1 -1
- package/dist/{program-DtiNMTxO.mjs → program-C2cJayA1.mjs} +4 -4
- package/dist/{program-DtiNMTxO.mjs.map → program-C2cJayA1.mjs.map} +1 -1
- package/dist/renderer/index.d.mts +2 -2
- package/dist/renderer/index.mjs +2 -2
- package/dist/{renderer-QMGrRiab.mjs → renderer--ruTGlPo.mjs} +3 -3
- package/dist/{renderer-QMGrRiab.mjs.map → renderer--ruTGlPo.mjs.map} +1 -1
- package/dist/{renderer-BAmGO6Hj.mjs → renderer-7y5Cj8rV.mjs} +3 -3
- package/dist/{renderer-BAmGO6Hj.mjs.map → renderer-7y5Cj8rV.mjs.map} +1 -1
- package/dist/{renderer-B48vtpou.mjs → renderer-92eLJg24.mjs} +4 -4
- package/dist/{renderer-B48vtpou.mjs.map → renderer-92eLJg24.mjs.map} +1 -1
- package/dist/{renderer-ButaUWLr.mjs → renderer-B0gPTXhe.mjs} +3 -3
- package/dist/{renderer-ButaUWLr.mjs.map → renderer-B0gPTXhe.mjs.map} +1 -1
- package/dist/{renderer-BaOC1Pd1.mjs → renderer-B1QREs7J.mjs} +3 -3
- package/dist/{renderer-BaOC1Pd1.mjs.map → renderer-B1QREs7J.mjs.map} +1 -1
- package/dist/{renderer-BI1nmIqA.mjs → renderer-B3e4LSE6.mjs} +3 -3
- package/dist/{renderer-BI1nmIqA.mjs.map → renderer-B3e4LSE6.mjs.map} +1 -1
- package/dist/{renderer-C4puWDLK.mjs → renderer-B4RpSd4A.mjs} +2 -2
- package/dist/{renderer-C4puWDLK.mjs.map → renderer-B4RpSd4A.mjs.map} +1 -1
- package/dist/renderer-BAhZeUUn.mjs +5 -0
- package/dist/{renderer-DmOewVsB.mjs → renderer-BBAbZfBl.mjs} +4 -4
- package/dist/{renderer-DmOewVsB.mjs.map → renderer-BBAbZfBl.mjs.map} +1 -1
- package/dist/{renderer-6QAlE1Mp.mjs → renderer-BDCy8NgT.mjs} +3 -3
- package/dist/{renderer-6QAlE1Mp.mjs.map → renderer-BDCy8NgT.mjs.map} +1 -1
- package/dist/renderer-BHAE_dKq.mjs +5 -0
- package/dist/{renderer-Rg1BFv8B.mjs → renderer-BMKFzfSQ.mjs} +3 -3
- package/dist/{renderer-Rg1BFv8B.mjs.map → renderer-BMKFzfSQ.mjs.map} +1 -1
- package/dist/renderer-BNYZY3FE.mjs +5 -0
- package/dist/{renderer-D8tdGi2P.mjs → renderer-BPixWnmY.mjs} +3 -3
- package/dist/{renderer-D8tdGi2P.mjs.map → renderer-BPixWnmY.mjs.map} +1 -1
- package/dist/renderer-BSvubMvI.mjs +5 -0
- package/dist/{renderer-C2Ff-9u_.mjs → renderer-BTd2sWDC.mjs} +3 -3
- package/dist/{renderer-C2Ff-9u_.mjs.map → renderer-BTd2sWDC.mjs.map} +1 -1
- package/dist/{renderer-YtRSM2cv.mjs → renderer-BTigwMQp.mjs} +3 -3
- package/dist/{renderer-YtRSM2cv.mjs.map → renderer-BTigwMQp.mjs.map} +1 -1
- package/dist/renderer-B_M_yhTc.mjs +5 -0
- package/dist/renderer-B_xSsTuy.mjs +5 -0
- package/dist/renderer-BePHurAU.mjs +5 -0
- package/dist/renderer-BfZquJrW.mjs +5 -0
- package/dist/{renderer-DNhOjz6C.mjs → renderer-Bi6W4RSn.mjs} +2 -2
- package/dist/{renderer-DNhOjz6C.mjs.map → renderer-Bi6W4RSn.mjs.map} +1 -1
- package/dist/{renderer--Da6pAJ4.mjs → renderer-BjCHW9Jp.mjs} +2 -2
- package/dist/{renderer-S6ez0leJ.mjs → renderer-BjvNEbML.mjs} +2 -2
- package/dist/{renderer-S6ez0leJ.mjs.map → renderer-BjvNEbML.mjs.map} +1 -1
- package/dist/{renderer-BFHgl-0f.mjs → renderer-BkWd4-YO.mjs} +2 -2
- package/dist/{renderer-BFHgl-0f.mjs.map → renderer-BkWd4-YO.mjs.map} +1 -1
- package/dist/{renderer-z3YOOR3k.mjs → renderer-Bkrk0M0r.mjs} +3 -3
- package/dist/{renderer-z3YOOR3k.mjs.map → renderer-Bkrk0M0r.mjs.map} +1 -1
- package/dist/{renderer-Kj9AhRCc.mjs → renderer-BljMOvry.mjs} +3 -3
- package/dist/{renderer-Kj9AhRCc.mjs.map → renderer-BljMOvry.mjs.map} +1 -1
- package/dist/renderer-BuY5ypB2.mjs +5 -0
- package/dist/renderer-BvOQgFHo.mjs +5 -0
- package/dist/{renderer-ITtBRR4o.mjs → renderer-BwpgDLYO.mjs} +3 -3
- package/dist/{renderer-ITtBRR4o.mjs.map → renderer-BwpgDLYO.mjs.map} +1 -1
- package/dist/{renderer-B3x-uogM.mjs → renderer-BwwZB2mt.mjs} +4 -4
- package/dist/{renderer-B3x-uogM.mjs.map → renderer-BwwZB2mt.mjs.map} +1 -1
- package/dist/{renderer-GlyeFl5R.mjs → renderer-ByCX4JYg.mjs} +3 -3
- package/dist/{renderer-GlyeFl5R.mjs.map → renderer-ByCX4JYg.mjs.map} +1 -1
- package/dist/{renderer-DDBmBmQN.mjs → renderer-C1E5Rt5q.mjs} +3 -3
- package/dist/{renderer-DDBmBmQN.mjs.map → renderer-C1E5Rt5q.mjs.map} +1 -1
- package/dist/renderer-C7NkSvUz.mjs +5 -0
- package/dist/{renderer-DvoPplvC.mjs → renderer-CCGzT6bX.mjs} +2 -2
- package/dist/{renderer-DJWQWN1E.mjs → renderer-CDOobs18.mjs} +3 -3
- package/dist/{renderer-DJWQWN1E.mjs.map → renderer-CDOobs18.mjs.map} +1 -1
- package/dist/{renderer-DacnnTjY.mjs → renderer-CDUxAtsk.mjs} +4 -4
- package/dist/{renderer-DacnnTjY.mjs.map → renderer-CDUxAtsk.mjs.map} +1 -1
- package/dist/renderer-CIuxV2q1.mjs +5 -0
- package/dist/{renderer-BlafvK-L.mjs → renderer-CJ4bxCld.mjs} +2 -2
- package/dist/renderer-CKp97tSQ.mjs +5 -0
- package/dist/{renderer-_-MCpvGq.mjs → renderer-CNb-DG00.mjs} +71 -71
- package/dist/{renderer-_-MCpvGq.mjs.map → renderer-CNb-DG00.mjs.map} +1 -1
- package/dist/{renderer-BYj8x8YM.mjs → renderer-CNuVJ4nG.mjs} +2 -2
- package/dist/{renderer-BYj8x8YM.mjs.map → renderer-CNuVJ4nG.mjs.map} +1 -1
- package/dist/renderer-CY89dTFR.mjs +5 -0
- package/dist/renderer-C_B_4Bl0.mjs +5 -0
- package/dist/{renderer-R0sJId_6.mjs → renderer-Cbsnj9vV.mjs} +3 -3
- package/dist/{renderer-R0sJId_6.mjs.map → renderer-Cbsnj9vV.mjs.map} +1 -1
- package/dist/{renderer-CBG6ewNf.mjs → renderer-CcoUNzlQ.mjs} +3 -3
- package/dist/{renderer-CBG6ewNf.mjs.map → renderer-CcoUNzlQ.mjs.map} +1 -1
- package/dist/renderer-Cd87JOjP.mjs +5 -0
- package/dist/{renderer-CbNW0KHh.mjs → renderer-CeiCJCg4.mjs} +3 -3
- package/dist/{renderer-CbNW0KHh.mjs.map → renderer-CeiCJCg4.mjs.map} +1 -1
- package/dist/renderer-Cev6orIK.mjs +6 -0
- package/dist/renderer-Cewf6UPh.mjs +5 -0
- package/dist/renderer-CnHsMLIv.mjs +5 -0
- package/dist/renderer-CoxuAr7b.mjs +5 -0
- package/dist/{renderer-BqSiWRoD.mjs → renderer-CqtIbe5n.mjs} +2 -2
- package/dist/{renderer-BqSiWRoD.mjs.map → renderer-CqtIbe5n.mjs.map} +1 -1
- package/dist/renderer-CrdG7trA.mjs +5 -0
- package/dist/{renderer-D-eTVnDS.mjs → renderer-Csss5GFQ.mjs} +2 -2
- package/dist/{renderer-D-eTVnDS.mjs.map → renderer-Csss5GFQ.mjs.map} +1 -1
- package/dist/renderer-Cu5MFgbk.mjs +5 -0
- package/dist/renderer-CuOjhtoo.mjs +5 -0
- package/dist/{renderer-Mdyv_W8K.mjs → renderer-Cv4lchUP.mjs} +3 -3
- package/dist/{renderer-Mdyv_W8K.mjs.map → renderer-Cv4lchUP.mjs.map} +1 -1
- package/dist/{renderer-CJwgsecF.mjs → renderer-Cw6Sagih.mjs} +3 -3
- package/dist/{renderer-CJwgsecF.mjs.map → renderer-Cw6Sagih.mjs.map} +1 -1
- package/dist/{renderer-DlESyfg7.d.mts → renderer-CxqPeATd.d.mts} +2 -2
- package/dist/{renderer-DlESyfg7.d.mts.map → renderer-CxqPeATd.d.mts.map} +1 -1
- package/dist/{renderer-DYo_a5-8.mjs → renderer-CzRqzp8P.mjs} +3 -3
- package/dist/{renderer-DYo_a5-8.mjs.map → renderer-CzRqzp8P.mjs.map} +1 -1
- package/dist/{renderer-BmWH4dK1.mjs → renderer-Czxgaygb.mjs} +8 -7
- package/dist/{renderer-BmWH4dK1.mjs.map → renderer-Czxgaygb.mjs.map} +1 -1
- package/dist/{renderer-CgEMtLOL.mjs → renderer-D0vom99O.mjs} +2 -2
- package/dist/{renderer-CgEMtLOL.mjs.map → renderer-D0vom99O.mjs.map} +1 -1
- package/dist/{renderer-BebePsG7.mjs → renderer-D2-V9nQq.mjs} +3 -3
- package/dist/{renderer-BebePsG7.mjs.map → renderer-D2-V9nQq.mjs.map} +1 -1
- package/dist/renderer-D2_0g6Oi.mjs +5 -0
- package/dist/renderer-D62FwolD.mjs +5 -0
- package/dist/{renderer-CMzd3BrW.mjs → renderer-D6BXR7P4.mjs} +2 -2
- package/dist/{renderer-CMzd3BrW.mjs.map → renderer-D6BXR7P4.mjs.map} +1 -1
- package/dist/renderer-DDNY9N7I.mjs +5 -0
- package/dist/{renderer-MS70wrQB.mjs → renderer-DFJQ6v0F.mjs} +2 -2
- package/dist/{renderer-MS70wrQB.mjs.map → renderer-DFJQ6v0F.mjs.map} +1 -1
- package/dist/renderer-DF_ONJ3v.mjs +5 -0
- package/dist/{renderer-DjPC9l3w.mjs → renderer-DILUmb-e.mjs} +3 -3
- package/dist/{renderer-DjPC9l3w.mjs.map → renderer-DILUmb-e.mjs.map} +1 -1
- package/dist/{renderer-Ch1rv1XP.mjs → renderer-DKfwlE4e.mjs} +3 -3
- package/dist/{renderer-Ch1rv1XP.mjs.map → renderer-DKfwlE4e.mjs.map} +1 -1
- package/dist/{renderer-B5Icb0XW.mjs → renderer-DScyMHpJ.mjs} +2 -2
- package/dist/{renderer-B5Icb0XW.mjs.map → renderer-DScyMHpJ.mjs.map} +1 -1
- package/dist/{renderer-Fm2brScz.mjs → renderer-DTw-W0Yz.mjs} +3 -3
- package/dist/{renderer-Fm2brScz.mjs.map → renderer-DTw-W0Yz.mjs.map} +1 -1
- package/dist/{renderer-dJcu7WqI.mjs → renderer-DZJJHCtm.mjs} +3 -3
- package/dist/{renderer-dJcu7WqI.mjs.map → renderer-DZJJHCtm.mjs.map} +1 -1
- package/dist/{renderer-B6c_Rk_2.mjs → renderer-DaSxr9fM.mjs} +3 -3
- package/dist/{renderer-B6c_Rk_2.mjs.map → renderer-DaSxr9fM.mjs.map} +1 -1
- package/dist/{renderer-BRWpn3dT.mjs → renderer-DaqWTx7s.mjs} +3 -3
- package/dist/{renderer-BRWpn3dT.mjs.map → renderer-DaqWTx7s.mjs.map} +1 -1
- package/dist/renderer-DbzrVHEE.mjs +5 -0
- package/dist/{renderer-CPNLkir4.mjs → renderer-DcBGYN3V.mjs} +3 -3
- package/dist/{renderer-CPNLkir4.mjs.map → renderer-DcBGYN3V.mjs.map} +1 -1
- package/dist/{renderer-BkXqFmNO.mjs → renderer-DjBCWxYy.mjs} +3 -3
- package/dist/{renderer-BkXqFmNO.mjs.map → renderer-DjBCWxYy.mjs.map} +1 -1
- package/dist/{renderer-D90PpIKG.mjs → renderer-DjwITRvg.mjs} +2 -2
- package/dist/renderer-DlYchp1v.mjs +5 -0
- package/dist/renderer-DqcUNP8J.mjs +5 -0
- package/dist/renderer-DqvFhEQj.mjs +5 -0
- package/dist/{renderer-ktpusVT2.mjs → renderer-DwVOxdzC.mjs} +3 -3
- package/dist/{renderer-ktpusVT2.mjs.map → renderer-DwVOxdzC.mjs.map} +1 -1
- package/dist/{renderer-_Fh9IBlE.mjs → renderer-Dwu_zfdL.mjs} +3 -3
- package/dist/{renderer-_Fh9IBlE.mjs.map → renderer-Dwu_zfdL.mjs.map} +1 -1
- package/dist/renderer-DxBav2bE.mjs +5 -0
- package/dist/{renderer-DS64UaYK.mjs → renderer-DyyIXLQK.mjs} +3 -3
- package/dist/{renderer-DS64UaYK.mjs.map → renderer-DyyIXLQK.mjs.map} +1 -1
- package/dist/{renderer-DqlvbOUt.mjs → renderer-DzSMeQBC.mjs} +3 -3
- package/dist/{renderer-DqlvbOUt.mjs.map → renderer-DzSMeQBC.mjs.map} +1 -1
- package/dist/{renderer-BXCZev4l.mjs → renderer-EZp_IIPK.mjs} +3 -3
- package/dist/{renderer-BXCZev4l.mjs.map → renderer-EZp_IIPK.mjs.map} +1 -1
- package/dist/{renderer-Bf4BdBtb.mjs → renderer-G1pMJH5C.mjs} +2 -2
- package/dist/{renderer-Bf4BdBtb.mjs.map → renderer-G1pMJH5C.mjs.map} +1 -1
- package/dist/renderer-GvSRoQje.mjs +5 -0
- package/dist/{renderer-DQtk282o.mjs → renderer-If8JOkBi.mjs} +2 -2
- package/dist/{renderer-DQtk282o.mjs.map → renderer-If8JOkBi.mjs.map} +1 -1
- package/dist/{renderer-CRYO5HQw.mjs → renderer-JvcR1vYI.mjs} +2 -2
- package/dist/{renderer-CRYO5HQw.mjs.map → renderer-JvcR1vYI.mjs.map} +1 -1
- package/dist/renderer-KP7Ita9g.mjs +5 -0
- package/dist/{renderer-Cz11KJmQ.mjs → renderer-NizuhHsH.mjs} +3 -3
- package/dist/{renderer-Cz11KJmQ.mjs.map → renderer-NizuhHsH.mjs.map} +1 -1
- package/dist/renderer-Pc8dyNXt.mjs +5 -0
- package/dist/{renderer-ClK7_Yzz.mjs → renderer-RDCax5CK.mjs} +3 -3
- package/dist/{renderer-ClK7_Yzz.mjs.map → renderer-RDCax5CK.mjs.map} +1 -1
- package/dist/{renderer-Bq9jXYJ5.mjs → renderer-UcdqCarR.mjs} +3 -3
- package/dist/{renderer-Bq9jXYJ5.mjs.map → renderer-UcdqCarR.mjs.map} +1 -1
- package/dist/{renderer-DL4oR40b.mjs → renderer-V5uEyDFz.mjs} +3 -3
- package/dist/{renderer-DL4oR40b.mjs.map → renderer-V5uEyDFz.mjs.map} +1 -1
- package/dist/{renderer-F410V727.mjs → renderer-X0eKSD7v.mjs} +3 -3
- package/dist/{renderer-F410V727.mjs.map → renderer-X0eKSD7v.mjs.map} +1 -1
- package/dist/{renderer-Dw1e5phO.mjs → renderer-Za4D9hej.mjs} +3 -3
- package/dist/{renderer-Dw1e5phO.mjs.map → renderer-Za4D9hej.mjs.map} +1 -1
- package/dist/{renderer-CczmOPAO.mjs → renderer-apeDrNXM.mjs} +3 -3
- package/dist/{renderer-CczmOPAO.mjs.map → renderer-apeDrNXM.mjs.map} +1 -1
- package/dist/renderer-ezRCmU09.mjs +3 -0
- package/dist/{renderer--S2cNYXS.mjs → renderer-gRMkQabv.mjs} +3 -3
- package/dist/{renderer--S2cNYXS.mjs.map → renderer-gRMkQabv.mjs.map} +1 -1
- package/dist/renderer-h6ev1ogx.mjs +5 -0
- package/dist/{renderer-8k-TR_Cy.mjs → renderer-rXgqgAjw.mjs} +3 -3
- package/dist/{renderer-8k-TR_Cy.mjs.map → renderer-rXgqgAjw.mjs.map} +1 -1
- package/dist/{renderer-DjwF10p2.mjs → renderer-ut1GqW89.mjs} +3 -3
- package/dist/{renderer-DjwF10p2.mjs.map → renderer-ut1GqW89.mjs.map} +1 -1
- package/dist/{renderer-w8LKBg_5.mjs → renderer-yyUpCeWb.mjs} +2 -2
- package/dist/{renderer-w8LKBg_5.mjs.map → renderer-yyUpCeWb.mjs.map} +1 -1
- package/dist/{renderers-CP8CFWDs-DXiR_PLR.mjs → renderers-CP8CFWDs-DzGXDs5p.mjs} +3 -3
- package/dist/{renderers-CP8CFWDs-DXiR_PLR.mjs.map → renderers-CP8CFWDs-DzGXDs5p.mjs.map} +1 -1
- package/dist/signals/index.d.mts +5 -5
- package/dist/signals/index.mjs +6 -6
- package/dist/{signals-DGRs6ddH.mjs → signals-C5nOrRmn.mjs} +3 -3
- package/dist/{signals-DGRs6ddH.mjs.map → signals-C5nOrRmn.mjs.map} +1 -1
- package/package.json +57 -56
- package/dist/dist-CPUIfrtw.mjs.map +0 -1
- package/dist/dist-CturBK2Z.mjs.map +0 -1
- package/dist/dist-fjKpBYkc.mjs.map +0 -1
- package/dist/index-AdrZIWT0.d.mts.map +0 -1
- package/dist/preview-engine/chunk-63SFBHEH.mjs +0 -1
- package/dist/preview-engine/chunk-7J2FWGVD.mjs +0 -1
- package/dist/preview-engine/chunk-M5HZPZHQ.mjs +0 -1
- package/dist/preview-engine/chunk-OG62XGCT.mjs +0 -5
- package/dist/preview-engine/chunk-U7NIY7UC.mjs +0 -1522
- package/dist/preview-engine/renderers-2H7YEUTD.mjs +0 -1
- package/dist/preview-engine/renderers-2ILG23ED.mjs +0 -1
- package/dist/preview-engine/renderers-3RC5FDWX.mjs +0 -1
- package/dist/preview-engine/renderers-6WH7NZCC.mjs +0 -1
- package/dist/preview-engine/renderers-7VJN5L3Z.mjs +0 -1
- package/dist/preview-engine/renderers-B7DSGUMI.mjs +0 -1
- package/dist/preview-engine/renderers-BFNJ7VCI.mjs +0 -1
- package/dist/preview-engine/renderers-CGYIDAVV.mjs +0 -1
- package/dist/preview-engine/renderers-DXHJAMZR.mjs +0 -1
- package/dist/preview-engine/renderers-ECA3P4ON.mjs +0 -1
- package/dist/preview-engine/renderers-FWGMNPYB.mjs +0 -1
- package/dist/preview-engine/renderers-HUW2ZMS3.mjs +0 -1
- package/dist/preview-engine/renderers-HXFRTIJD.mjs +0 -1
- package/dist/preview-engine/renderers-JHFT27YU.mjs +0 -1
- package/dist/preview-engine/renderers-NQXMYNSY.mjs +0 -1
- package/dist/preview-engine/renderers-ORAIXUL3.mjs +0 -1
- package/dist/preview-engine/renderers-Q4OFCMXI.mjs +0 -1
- package/dist/preview-engine/renderers-QVZVEYP5.mjs +0 -1
- package/dist/preview-engine/renderers-RKDPX5JU.mjs +0 -1
- package/dist/preview-engine/renderers-SBFF7JP5.mjs +0 -1
- package/dist/preview-engine/renderers-TAWT3ZSS.mjs +0 -1
- package/dist/preview-engine/renderers-UHTO6BQA.mjs +0 -1
- package/dist/preview-engine/renderers-UNK6I4JJ.mjs +0 -1
- package/dist/preview-engine/renderers-W773SBPV.mjs +0 -1
- package/dist/preview-engine/renderers-XHTMRXC5.mjs +0 -1
- package/dist/preview-engine/renderers-YECY2YFT.mjs +0 -1
- package/dist/preview-engine/renderers-YMN6QXK7.mjs +0 -1
- package/dist/preview-engine/renderers-ZANPE3OK.mjs +0 -1
- package/dist/preview-engine/renderers-ZHTX73PR.mjs +0 -1
- package/dist/preview-engine/renderers-ZJTRANIX.mjs +0 -1
- package/dist/renderer-1hypa-l7.mjs +0 -5
- package/dist/renderer-6D8M4DRu.mjs +0 -5
- package/dist/renderer-APrj6tdP.mjs +0 -5
- package/dist/renderer-BARst3ZD.mjs +0 -3
- package/dist/renderer-BF8wlbN1.mjs +0 -5
- package/dist/renderer-BOUcMCJB.mjs +0 -5
- package/dist/renderer-BSwn6KmG.mjs +0 -5
- package/dist/renderer-BUxvuC5A.mjs +0 -5
- package/dist/renderer-BYOsmJ8F.mjs +0 -5
- package/dist/renderer-Bp7LqSTt.mjs +0 -5
- package/dist/renderer-CD0amH_Q.mjs +0 -5
- package/dist/renderer-CIJGjrt7.mjs +0 -5
- package/dist/renderer-CNFTl94b.mjs +0 -5
- package/dist/renderer-CTJ0gHPS.mjs +0 -5
- package/dist/renderer-Cc3INn7w.mjs +0 -5
- package/dist/renderer-CeHh2lKY.mjs +0 -5
- package/dist/renderer-CfjwkQP4.mjs +0 -5
- package/dist/renderer-CiuOB-Md.mjs +0 -5
- package/dist/renderer-Cor66Y2X.mjs +0 -5
- package/dist/renderer-CtIM0LWe.mjs +0 -5
- package/dist/renderer-CyqgTsnx.mjs +0 -5
- package/dist/renderer-D2QG9yIW.mjs +0 -5
- package/dist/renderer-D2woU27o.mjs +0 -6
- package/dist/renderer-DAhDiQQY.mjs +0 -5
- package/dist/renderer-DIjxOQFi.mjs +0 -5
- package/dist/renderer-DRzalGhU.mjs +0 -5
- package/dist/renderer-DY6S1jWp.mjs +0 -5
- package/dist/renderer-DeW0KNQV.mjs +0 -5
- package/dist/renderer-DsVSVFkl.mjs +0 -5
- package/dist/renderer-DxvcIgEU.mjs +0 -5
- package/dist/renderer-F0MKqmol.mjs +0 -5
- package/dist/renderer-OkbovcAc.mjs +0 -5
- package/dist/renderer-QyBeWMEL.mjs +0 -5
- package/dist/renderer-hSh5IrDp.mjs +0 -5
- package/dist/renderer-puLncHft.mjs +0 -5
- package/dist/renderer-wnFCaw7j.mjs +0 -5
- package/dist/renderer-xjtlyGS1.mjs +0 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as __toESM, t as __commonJSMin } from "./chunk-GBe2k3y8.mjs";
|
|
2
|
-
import { At as gradientStopsToOklab,
|
|
2
|
+
import { At as gradientStopsToOklab, Ft as isValueSignal, Ht as parseCssGradient, Lt as limitGradientStops, Pt as isSignal, Vt as parseCssColor } from "./dist-ClyC_d66.mjs";
|
|
3
3
|
import { ALL_FORMATS, AudioBufferSink, CanvasSink, FilePathSource, Input, UrlSource, VideoSampleSink } from "mediabunny";
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
@@ -11836,7 +11836,8 @@ var WebGPUAudioProcessor = class WebGPUAudioProcessor$1 {
|
|
|
11836
11836
|
if (isSignal(directVal)) {
|
|
11837
11837
|
const signalData = new Float32Array(numSamples);
|
|
11838
11838
|
const durationSec = durationSeconds > 0 ? durationSeconds : numSamples / _sampleRate;
|
|
11839
|
-
|
|
11839
|
+
if (isValueSignal(directVal)) signalData.fill(Number(directVal.get()) || 0);
|
|
11840
|
+
else for (let s = 0; s < numSamples; s++) {
|
|
11840
11841
|
const t = elapsedSeconds + s / _sampleRate;
|
|
11841
11842
|
const f = t * fps;
|
|
11842
11843
|
const progress = durationSec > 0 ? t / durationSec : 0;
|
|
@@ -11910,6 +11911,19 @@ var WebGPUAudioProcessor = class WebGPUAudioProcessor$1 {
|
|
|
11910
11911
|
deviceCache.set(cacheKey, cached$1);
|
|
11911
11912
|
} else if (stateUpdate) device.queue.writeBuffer(cached$1.stateBuffer, 0, stateUpdate);
|
|
11912
11913
|
const CHUNK_SIZE = 65536;
|
|
11914
|
+
const MAX_CHUNKS_IN_FLIGHT = 8;
|
|
11915
|
+
const pending = [];
|
|
11916
|
+
const readBackOldest = async () => {
|
|
11917
|
+
const chunk = pending.shift();
|
|
11918
|
+
if (!chunk) return;
|
|
11919
|
+
const { stagingBuffer, offset, chunkSamples } = chunk;
|
|
11920
|
+
await stagingBuffer.mapAsync(GPUMapMode.READ);
|
|
11921
|
+
const mappedRange = new Float32Array(stagingBuffer.getMappedRange());
|
|
11922
|
+
for (let c = 0; c < numChannels; c++) channels[c].set(mappedRange.subarray(c * chunkSamples, (c + 1) * chunkSamples), offset);
|
|
11923
|
+
stagingBuffer.unmap();
|
|
11924
|
+
stagingBuffer.destroy();
|
|
11925
|
+
await yieldToMain();
|
|
11926
|
+
};
|
|
11913
11927
|
try {
|
|
11914
11928
|
for (let offset = 0; offset < numSamples; offset += CHUNK_SIZE) {
|
|
11915
11929
|
const chunkSamples = Math.min(CHUNK_SIZE, numSamples - offset);
|
|
@@ -12022,13 +12036,16 @@ var WebGPUAudioProcessor = class WebGPUAudioProcessor$1 {
|
|
|
12022
12036
|
passEncoder.end();
|
|
12023
12037
|
commandEncoder.copyBufferToBuffer(outputBuffer, 0, stagingBuffer, 0, numChannels * chunkSamples * 4);
|
|
12024
12038
|
device.queue.submit([commandEncoder.finish()]);
|
|
12025
|
-
|
|
12026
|
-
|
|
12027
|
-
|
|
12028
|
-
|
|
12029
|
-
|
|
12039
|
+
pending.push({
|
|
12040
|
+
stagingBuffer,
|
|
12041
|
+
offset,
|
|
12042
|
+
chunkSamples
|
|
12043
|
+
});
|
|
12044
|
+
if (pending.length >= MAX_CHUNKS_IN_FLIGHT) await readBackOldest();
|
|
12030
12045
|
}
|
|
12046
|
+
while (pending.length > 0) await readBackOldest();
|
|
12031
12047
|
} finally {
|
|
12048
|
+
for (const { stagingBuffer } of pending) stagingBuffer.destroy();
|
|
12032
12049
|
for (const b of createdBuffers) b.destroy();
|
|
12033
12050
|
}
|
|
12034
12051
|
}
|
|
@@ -12675,6 +12692,63 @@ var InputStore = class {
|
|
|
12675
12692
|
}
|
|
12676
12693
|
};
|
|
12677
12694
|
const inputStore = new InputStore();
|
|
12695
|
+
/** The texture formats the renderer decodes (sharp); others (TGA, BMP, PSD, DDS, …) are skipped. */
|
|
12696
|
+
const MIME_BY_EXT = {
|
|
12697
|
+
".png": "image/png",
|
|
12698
|
+
".jpg": "image/jpeg",
|
|
12699
|
+
".jpeg": "image/jpeg",
|
|
12700
|
+
".webp": "image/webp",
|
|
12701
|
+
".gif": "image/gif",
|
|
12702
|
+
".tif": "image/tiff",
|
|
12703
|
+
".tiff": "image/tiff",
|
|
12704
|
+
".avif": "image/avif"
|
|
12705
|
+
};
|
|
12706
|
+
/** MIME type of an image file name, by extension (PNG when unknown). */
|
|
12707
|
+
function textureMime(name) {
|
|
12708
|
+
return MIME_BY_EXT[path.extname(name).toLowerCase()] ?? "image/png";
|
|
12709
|
+
}
|
|
12710
|
+
/** Whether the renderer can decode a texture with this file name (no extension: assume yes). */
|
|
12711
|
+
function isSupportedTexture(name) {
|
|
12712
|
+
const ext = path.extname(name.replace(/\\/g, "/")).toLowerCase();
|
|
12713
|
+
return !ext || ext in MIME_BY_EXT;
|
|
12714
|
+
}
|
|
12715
|
+
/**
|
|
12716
|
+
* Reads a texture a model file refers to. Exporters often write absolute
|
|
12717
|
+
* paths from the author's machine (`C:\Users\…\wood.png`), so after the
|
|
12718
|
+
* path as written (relative to `basePath`), the file name is also tried in
|
|
12719
|
+
* `basePath`, its `textures/` folder and any `*.fbm` folder next to it.
|
|
12720
|
+
*/
|
|
12721
|
+
function readTextureFile(ref, basePath) {
|
|
12722
|
+
if (!ref || typeof fs === "undefined" || !fs.existsSync) return void 0;
|
|
12723
|
+
if (!isSupportedTexture(ref)) return void 0;
|
|
12724
|
+
let cleaned = ref.trim().replace(/^file:\/\//, "");
|
|
12725
|
+
try {
|
|
12726
|
+
cleaned = decodeURIComponent(cleaned);
|
|
12727
|
+
} catch (_) {}
|
|
12728
|
+
const normalized = cleaned.replace(/\\/g, "/");
|
|
12729
|
+
const fileName = normalized.split("/").pop() ?? normalized;
|
|
12730
|
+
const candidates = [];
|
|
12731
|
+
if (path.isAbsolute(normalized)) candidates.push(normalized);
|
|
12732
|
+
if (basePath) {
|
|
12733
|
+
candidates.push(path.resolve(basePath, normalized));
|
|
12734
|
+
candidates.push(path.join(basePath, fileName));
|
|
12735
|
+
candidates.push(path.join(basePath, "textures", fileName));
|
|
12736
|
+
try {
|
|
12737
|
+
for (const entry of fs.readdirSync(basePath)) if (entry.toLowerCase().endsWith(".fbm")) candidates.push(path.join(basePath, entry, fileName));
|
|
12738
|
+
} catch (_) {}
|
|
12739
|
+
}
|
|
12740
|
+
for (const file of candidates) try {
|
|
12741
|
+
if (fs.existsSync(file) && fs.statSync(file).isFile()) return {
|
|
12742
|
+
bytes: new Uint8Array(fs.readFileSync(file)),
|
|
12743
|
+
mime: textureMime(file)
|
|
12744
|
+
};
|
|
12745
|
+
} catch (_) {}
|
|
12746
|
+
}
|
|
12747
|
+
/** Warns that a model's texture is missing or in an unsupported format (the mesh renders untextured). */
|
|
12748
|
+
function warnMissingTexture(loader, material, ref) {
|
|
12749
|
+
const reason = isSupportedTexture(ref) ? "was not found" : `is in an unsupported format (use ${Object.keys(MIME_BY_EXT).join(", ")})`;
|
|
12750
|
+
console.warn(`[${loader}] Texture "${ref}" for material "${material}" ${reason}; the material renders without it.`);
|
|
12751
|
+
}
|
|
12678
12752
|
var ObjLoader = class ObjLoader$1 {
|
|
12679
12753
|
/**
|
|
12680
12754
|
* Parses Wavefront .obj text content (and optional .mtl text) into Model3DData.
|
|
@@ -12692,7 +12766,7 @@ var ObjLoader = class ObjLoader$1 {
|
|
|
12692
12766
|
};
|
|
12693
12767
|
meshBuilders.push(currentBuilder);
|
|
12694
12768
|
const materials = {};
|
|
12695
|
-
if (mtlText) Object.assign(materials, ObjLoader$1.parseMtl(mtlText));
|
|
12769
|
+
if (mtlText) Object.assign(materials, ObjLoader$1.loadTextures(ObjLoader$1.parseMtl(mtlText), options.basePath));
|
|
12696
12770
|
const lines = objText.split(/\r?\n/);
|
|
12697
12771
|
for (let i = 0; i < lines.length; i++) {
|
|
12698
12772
|
const line = lines[i]?.trim();
|
|
@@ -12705,7 +12779,7 @@ var ObjLoader = class ObjLoader$1 {
|
|
|
12705
12779
|
const resolvedMtlPath = path.resolve(options.basePath, mtlFileName);
|
|
12706
12780
|
if (fs.existsSync(resolvedMtlPath)) {
|
|
12707
12781
|
const content = fs.readFileSync(resolvedMtlPath, "utf-8");
|
|
12708
|
-
Object.assign(materials, ObjLoader$1.parseMtl(content));
|
|
12782
|
+
Object.assign(materials, ObjLoader$1.loadTextures(ObjLoader$1.parseMtl(content), path.dirname(resolvedMtlPath)));
|
|
12709
12783
|
}
|
|
12710
12784
|
} catch (_) {}
|
|
12711
12785
|
} else if (cmd === "v") {
|
|
@@ -12793,12 +12867,12 @@ var ObjLoader = class ObjLoader$1 {
|
|
|
12793
12867
|
maxY = 1;
|
|
12794
12868
|
maxZ = 1;
|
|
12795
12869
|
}
|
|
12796
|
-
|
|
12797
|
-
|
|
12798
|
-
|
|
12799
|
-
|
|
12800
|
-
|
|
12801
|
-
|
|
12870
|
+
const centerX = (minX + maxX) * .5;
|
|
12871
|
+
const centerY = (minY + maxY) * .5;
|
|
12872
|
+
const centerZ = (minZ + maxZ) * .5;
|
|
12873
|
+
const sizeX = Math.max(1e-4, maxX - minX);
|
|
12874
|
+
const sizeY = Math.max(1e-4, maxY - minY);
|
|
12875
|
+
const sizeZ = Math.max(1e-4, maxZ - minZ);
|
|
12802
12876
|
const maxDim = Math.max(sizeX, sizeY, sizeZ);
|
|
12803
12877
|
let scaleMultiplier = 1;
|
|
12804
12878
|
if (options.normalizeSize && options.normalizeSize > 0) scaleMultiplier = options.normalizeSize / maxDim;
|
|
@@ -13012,8 +13086,57 @@ var ObjLoader = class ObjLoader$1 {
|
|
|
13012
13086
|
const val = Number.parseFloat(parts[1] ?? "1");
|
|
13013
13087
|
currentMat.opacity = cmd === "d" ? val : 1 - val;
|
|
13014
13088
|
if (currentMat.diffuseColor) currentMat.diffuseColor[3] = currentMat.opacity;
|
|
13015
|
-
} else if (cmd === "map_kd")
|
|
13016
|
-
|
|
13089
|
+
} else if (cmd === "map_kd") {
|
|
13090
|
+
currentMat.diffuseTexture = ObjLoader$1.mapFileName(parts);
|
|
13091
|
+
const clamp = parts.findIndex((p) => p.toLowerCase() === "-clamp");
|
|
13092
|
+
currentMat.textureWrap = clamp > 0 && parts[clamp + 1]?.toLowerCase() === "on" ? "clamp" : "repeat";
|
|
13093
|
+
} else if (cmd === "norm" || cmd === "map_kn") currentMat.normalTexture = ObjLoader$1.mapFileName(parts);
|
|
13094
|
+
}
|
|
13095
|
+
}
|
|
13096
|
+
return materials;
|
|
13097
|
+
}
|
|
13098
|
+
/** Option arities of MTL map statements (`-o`, `-s`, `-t` take 1–3 numbers). */
|
|
13099
|
+
static MAP_OPTION_ARGS = {
|
|
13100
|
+
"-blendu": 1,
|
|
13101
|
+
"-blendv": 1,
|
|
13102
|
+
"-cc": 1,
|
|
13103
|
+
"-clamp": 1,
|
|
13104
|
+
"-texres": 1,
|
|
13105
|
+
"-bm": 1,
|
|
13106
|
+
"-boost": 1,
|
|
13107
|
+
"-imfchan": 1,
|
|
13108
|
+
"-type": 1,
|
|
13109
|
+
"-mm": 2
|
|
13110
|
+
};
|
|
13111
|
+
/** The file name of a map statement (`map_Kd -s 1 1 1 wood grain.png`), past its options. */
|
|
13112
|
+
static mapFileName(parts) {
|
|
13113
|
+
let i = 1;
|
|
13114
|
+
while (i < parts.length && parts[i]?.startsWith("-")) {
|
|
13115
|
+
const option = parts[i].toLowerCase();
|
|
13116
|
+
i++;
|
|
13117
|
+
if (option === "-o" || option === "-s" || option === "-t") for (let n = 0; n < 3 && i < parts.length; n++) {
|
|
13118
|
+
if (Number.isNaN(Number(parts[i]))) break;
|
|
13119
|
+
i++;
|
|
13120
|
+
}
|
|
13121
|
+
else i += ObjLoader$1.MAP_OPTION_ARGS[option] ?? 0;
|
|
13122
|
+
}
|
|
13123
|
+
return parts.slice(i).join(" ");
|
|
13124
|
+
}
|
|
13125
|
+
/** Reads the diffuse and normal maps the materials name, relative to `dir`. */
|
|
13126
|
+
static loadTextures(materials, dir) {
|
|
13127
|
+
if (!dir) return materials;
|
|
13128
|
+
for (const mat of Object.values(materials)) {
|
|
13129
|
+
if (mat.diffuseTexture && !mat.diffuseTextureBuffer) {
|
|
13130
|
+
const file = readTextureFile(mat.diffuseTexture, dir);
|
|
13131
|
+
if (file) {
|
|
13132
|
+
mat.diffuseTextureBuffer = file.bytes;
|
|
13133
|
+
mat.diffuseTextureMime = file.mime;
|
|
13134
|
+
} else warnMissingTexture("ObjLoader", mat.name, mat.diffuseTexture);
|
|
13135
|
+
}
|
|
13136
|
+
if (mat.normalTexture && !mat.normalTextureBuffer) {
|
|
13137
|
+
const file = readTextureFile(mat.normalTexture, dir);
|
|
13138
|
+
if (file) mat.normalTextureBuffer = file.bytes;
|
|
13139
|
+
else warnMissingTexture("ObjLoader", mat.name, mat.normalTexture);
|
|
13017
13140
|
}
|
|
13018
13141
|
}
|
|
13019
13142
|
return materials;
|
|
@@ -13049,190 +13172,499 @@ function loadOBJ(srcOrData, mtlText, options = {}) {
|
|
|
13049
13172
|
}
|
|
13050
13173
|
return ObjLoader.parse(text, mtlText, options);
|
|
13051
13174
|
}
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13058
|
-
|
|
13059
|
-
|
|
13175
|
+
/**
|
|
13176
|
+
* Adds each triangle's (area-weighted) face normal to its three vertices, then
|
|
13177
|
+
* normalizes every vertex normal in place.
|
|
13178
|
+
*/
|
|
13179
|
+
function accumulateVertexNormals(positions, indices, normals) {
|
|
13180
|
+
const vertex = (i) => [
|
|
13181
|
+
positions[i * 3],
|
|
13182
|
+
positions[i * 3 + 1],
|
|
13183
|
+
positions[i * 3 + 2]
|
|
13184
|
+
];
|
|
13185
|
+
for (let i = 0; i < indices.length; i += 3) {
|
|
13186
|
+
const i0 = indices[i];
|
|
13187
|
+
const i1 = indices[i + 1];
|
|
13188
|
+
const i2 = indices[i + 2];
|
|
13189
|
+
const p0 = vertex(i0);
|
|
13190
|
+
const fn = Vector3Math.cross(Vector3Math.subtract(vertex(i1), p0), Vector3Math.subtract(vertex(i2), p0));
|
|
13191
|
+
for (const v of [
|
|
13192
|
+
i0,
|
|
13193
|
+
i1,
|
|
13194
|
+
i2
|
|
13195
|
+
]) {
|
|
13196
|
+
normals[v * 3] += fn[0];
|
|
13197
|
+
normals[v * 3 + 1] += fn[1];
|
|
13198
|
+
normals[v * 3 + 2] += fn[2];
|
|
13199
|
+
}
|
|
13060
13200
|
}
|
|
13061
|
-
|
|
13062
|
-
const
|
|
13063
|
-
|
|
13064
|
-
const
|
|
13065
|
-
|
|
13066
|
-
|
|
13201
|
+
for (let i = 0; i < normals.length; i += 3) {
|
|
13202
|
+
const nx = normals[i];
|
|
13203
|
+
const ny = normals[i + 1];
|
|
13204
|
+
const nz = normals[i + 2];
|
|
13205
|
+
const len = Math.hypot(nx, ny, nz) || 1;
|
|
13206
|
+
normals[i] = nx / len;
|
|
13207
|
+
normals[i + 1] = ny / len;
|
|
13208
|
+
normals[i + 2] = nz / len;
|
|
13067
13209
|
}
|
|
13068
|
-
|
|
13069
|
-
|
|
13070
|
-
|
|
13071
|
-
|
|
13072
|
-
|
|
13073
|
-
|
|
13074
|
-
const
|
|
13075
|
-
|
|
13076
|
-
const
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
|
|
13080
|
-
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
let endOffset;
|
|
13084
|
-
let numProperties;
|
|
13085
|
-
let nameLen;
|
|
13086
|
-
if (is64Bit) {
|
|
13087
|
-
if (offset + 25 > u8.byteLength) return null;
|
|
13088
|
-
endOffset = Number(view.getBigUint64(offset, true));
|
|
13089
|
-
numProperties = Number(view.getBigUint64(offset + 8, true));
|
|
13090
|
-
nameLen = view.getUint8(offset + 24);
|
|
13091
|
-
offset += 25;
|
|
13092
|
-
} else {
|
|
13093
|
-
if (offset + 13 > u8.byteLength) return null;
|
|
13094
|
-
endOffset = view.getUint32(offset, true);
|
|
13095
|
-
numProperties = view.getUint32(offset + 4, true);
|
|
13096
|
-
nameLen = view.getUint8(offset + 12);
|
|
13097
|
-
offset += 13;
|
|
13098
|
-
}
|
|
13099
|
-
if (endOffset === 0) return null;
|
|
13100
|
-
const name = new TextDecoder().decode(u8.subarray(offset, offset + nameLen));
|
|
13101
|
-
offset += nameLen;
|
|
13102
|
-
const props = [];
|
|
13103
|
-
for (let p = 0; p < numProperties; p++) {
|
|
13104
|
-
const typeCode = String.fromCharCode(u8[offset]);
|
|
13105
|
-
offset += 1;
|
|
13106
|
-
switch (typeCode) {
|
|
13107
|
-
case "Y":
|
|
13108
|
-
props.push(view.getInt16(offset, true));
|
|
13109
|
-
offset += 2;
|
|
13110
|
-
break;
|
|
13111
|
-
case "C":
|
|
13112
|
-
case "B":
|
|
13113
|
-
props.push(view.getUint8(offset) !== 0);
|
|
13114
|
-
offset += 1;
|
|
13115
|
-
break;
|
|
13116
|
-
case "I":
|
|
13117
|
-
props.push(view.getInt32(offset, true));
|
|
13118
|
-
offset += 4;
|
|
13119
|
-
break;
|
|
13120
|
-
case "F":
|
|
13121
|
-
props.push(view.getFloat32(offset, true));
|
|
13122
|
-
offset += 4;
|
|
13123
|
-
break;
|
|
13124
|
-
case "D":
|
|
13125
|
-
props.push(view.getFloat64(offset, true));
|
|
13126
|
-
offset += 8;
|
|
13127
|
-
break;
|
|
13128
|
-
case "L":
|
|
13129
|
-
props.push(Number(view.getBigInt64(offset, true)));
|
|
13130
|
-
offset += 8;
|
|
13131
|
-
break;
|
|
13132
|
-
case "S": {
|
|
13133
|
-
const len = view.getUint32(offset, true);
|
|
13134
|
-
offset += 4;
|
|
13135
|
-
const str = new TextDecoder().decode(u8.subarray(offset, offset + len));
|
|
13136
|
-
props.push(str);
|
|
13137
|
-
offset += len;
|
|
13138
|
-
break;
|
|
13139
|
-
}
|
|
13140
|
-
case "R": {
|
|
13141
|
-
const len = view.getUint32(offset, true);
|
|
13142
|
-
offset += 4;
|
|
13143
|
-
const raw = u8.subarray(offset, offset + len);
|
|
13144
|
-
props.push(raw);
|
|
13145
|
-
offset += len;
|
|
13146
|
-
break;
|
|
13147
|
-
}
|
|
13148
|
-
case "f":
|
|
13149
|
-
case "d":
|
|
13150
|
-
case "i":
|
|
13151
|
-
case "l":
|
|
13152
|
-
case "b":
|
|
13153
|
-
case "c": {
|
|
13154
|
-
const arrayLen = view.getUint32(offset, true);
|
|
13155
|
-
const encoding = view.getUint32(offset + 4, true);
|
|
13156
|
-
const compressedLen = view.getUint32(offset + 8, true);
|
|
13157
|
-
offset += 12;
|
|
13158
|
-
let arrayBuffer;
|
|
13159
|
-
if (encoding === 1) {
|
|
13160
|
-
arrayBuffer = inflateSync(u8.subarray(offset, offset + compressedLen));
|
|
13161
|
-
offset += compressedLen;
|
|
13162
|
-
} else {
|
|
13163
|
-
const totalBytes = arrayLen * (typeCode === "d" || typeCode === "l" ? 8 : typeCode === "f" || typeCode === "i" ? 4 : 1);
|
|
13164
|
-
arrayBuffer = u8.subarray(offset, offset + totalBytes);
|
|
13165
|
-
offset += totalBytes;
|
|
13166
|
-
}
|
|
13167
|
-
const arrayView = new DataView(arrayBuffer.buffer, arrayBuffer.byteOffset, arrayBuffer.byteLength);
|
|
13168
|
-
if (typeCode === "f") {
|
|
13169
|
-
const arr = new Float32Array(arrayLen);
|
|
13170
|
-
for (let k = 0; k < arrayLen; k++) arr[k] = arrayView.getFloat32(k * 4, true);
|
|
13171
|
-
props.push(arr);
|
|
13172
|
-
} else if (typeCode === "d") {
|
|
13173
|
-
const arr = new Float64Array(arrayLen);
|
|
13174
|
-
for (let k = 0; k < arrayLen; k++) arr[k] = arrayView.getFloat64(k * 8, true);
|
|
13175
|
-
props.push(arr);
|
|
13176
|
-
} else if (typeCode === "i") {
|
|
13177
|
-
const arr = new Int32Array(arrayLen);
|
|
13178
|
-
for (let k = 0; k < arrayLen; k++) arr[k] = arrayView.getInt32(k * 4, true);
|
|
13179
|
-
props.push(arr);
|
|
13180
|
-
} else if (typeCode === "l") {
|
|
13181
|
-
const arr = new Float64Array(arrayLen);
|
|
13182
|
-
for (let k = 0; k < arrayLen; k++) arr[k] = Number(arrayView.getBigInt64(k * 8, true));
|
|
13183
|
-
props.push(arr);
|
|
13184
|
-
} else if (typeCode === "b") {
|
|
13185
|
-
const arr = new Uint8Array(arrayLen);
|
|
13186
|
-
for (let k = 0; k < arrayLen; k++) arr[k] = arrayView.getUint8(k);
|
|
13187
|
-
props.push(arr);
|
|
13188
|
-
} else props.push(arrayBuffer);
|
|
13189
|
-
break;
|
|
13190
|
-
}
|
|
13191
|
-
default: break;
|
|
13192
|
-
}
|
|
13193
|
-
}
|
|
13194
|
-
const children = [];
|
|
13195
|
-
while (offset < endOffset) {
|
|
13196
|
-
const child = readNode();
|
|
13197
|
-
if (child) children.push(child);
|
|
13198
|
-
else break;
|
|
13199
|
-
}
|
|
13200
|
-
offset = endOffset;
|
|
13201
|
-
return {
|
|
13202
|
-
name,
|
|
13203
|
-
props,
|
|
13204
|
-
children
|
|
13205
|
-
};
|
|
13206
|
-
};
|
|
13207
|
-
while (offset < u8.byteLength - (is64Bit ? 25 : 13)) {
|
|
13208
|
-
const node = readNode();
|
|
13209
|
-
if (node) root.children.push(node);
|
|
13210
|
-
else break;
|
|
13211
|
-
}
|
|
13212
|
-
return root;
|
|
13210
|
+
}
|
|
13211
|
+
/** Axis-aligned bounds of xyz position arrays (all zero when empty). */
|
|
13212
|
+
function computeBounds(...positionArrays) {
|
|
13213
|
+
let minX = Infinity, minY = Infinity, minZ = Infinity;
|
|
13214
|
+
let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;
|
|
13215
|
+
for (const positions of positionArrays) for (let i = 0; i < positions.length; i += 3) {
|
|
13216
|
+
const x = positions[i];
|
|
13217
|
+
const y = positions[i + 1];
|
|
13218
|
+
const z = positions[i + 2];
|
|
13219
|
+
if (x < minX) minX = x;
|
|
13220
|
+
if (x > maxX) maxX = x;
|
|
13221
|
+
if (y < minY) minY = y;
|
|
13222
|
+
if (y > maxY) maxY = y;
|
|
13223
|
+
if (z < minZ) minZ = z;
|
|
13224
|
+
if (z > maxZ) maxZ = z;
|
|
13213
13225
|
}
|
|
13214
|
-
|
|
13215
|
-
|
|
13216
|
-
|
|
13217
|
-
|
|
13218
|
-
|
|
13219
|
-
|
|
13220
|
-
|
|
13221
|
-
|
|
13222
|
-
|
|
13223
|
-
|
|
13224
|
-
|
|
13225
|
-
|
|
13226
|
-
|
|
13227
|
-
|
|
13228
|
-
|
|
13229
|
-
|
|
13230
|
-
|
|
13231
|
-
|
|
13232
|
-
|
|
13233
|
-
|
|
13234
|
-
|
|
13235
|
-
|
|
13226
|
+
if (!Number.isFinite(minX)) {
|
|
13227
|
+
minX = minY = minZ = 0;
|
|
13228
|
+
maxX = maxY = maxZ = 0;
|
|
13229
|
+
}
|
|
13230
|
+
return {
|
|
13231
|
+
min: [
|
|
13232
|
+
minX,
|
|
13233
|
+
minY,
|
|
13234
|
+
minZ
|
|
13235
|
+
],
|
|
13236
|
+
max: [
|
|
13237
|
+
maxX,
|
|
13238
|
+
maxY,
|
|
13239
|
+
maxZ
|
|
13240
|
+
],
|
|
13241
|
+
center: [
|
|
13242
|
+
(minX + maxX) * .5,
|
|
13243
|
+
(minY + maxY) * .5,
|
|
13244
|
+
(minZ + maxZ) * .5
|
|
13245
|
+
],
|
|
13246
|
+
size: [
|
|
13247
|
+
maxX - minX,
|
|
13248
|
+
maxY - minY,
|
|
13249
|
+
maxZ - minZ
|
|
13250
|
+
]
|
|
13251
|
+
};
|
|
13252
|
+
}
|
|
13253
|
+
/**
|
|
13254
|
+
* The placement `LoadModelOptions` asks for: recentring on the bounds
|
|
13255
|
+
* (`center`), fitting the largest side to `normalizeSize`, then `scale`.
|
|
13256
|
+
*/
|
|
13257
|
+
function resolveModelTransform(bounds, options) {
|
|
13258
|
+
const maxDimension = Math.max(...bounds.size, 1e-4);
|
|
13259
|
+
let scaleMultiplier = 1;
|
|
13260
|
+
if (options.normalizeSize && options.normalizeSize > 0) scaleMultiplier = options.normalizeSize / maxDimension;
|
|
13261
|
+
const scale = [
|
|
13262
|
+
scaleMultiplier,
|
|
13263
|
+
scaleMultiplier,
|
|
13264
|
+
scaleMultiplier
|
|
13265
|
+
];
|
|
13266
|
+
if (typeof options.scale === "number") {
|
|
13267
|
+
scale[0] *= options.scale;
|
|
13268
|
+
scale[1] *= options.scale;
|
|
13269
|
+
scale[2] *= options.scale;
|
|
13270
|
+
} else if (Array.isArray(options.scale)) {
|
|
13271
|
+
scale[0] *= options.scale[0];
|
|
13272
|
+
scale[1] *= options.scale[1];
|
|
13273
|
+
scale[2] *= options.scale[2];
|
|
13274
|
+
}
|
|
13275
|
+
return {
|
|
13276
|
+
offset: options.center ? bounds.center : [
|
|
13277
|
+
0,
|
|
13278
|
+
0,
|
|
13279
|
+
0
|
|
13280
|
+
],
|
|
13281
|
+
scale
|
|
13282
|
+
};
|
|
13283
|
+
}
|
|
13284
|
+
/** `(p - offset) * scale` for every xyz position. */
|
|
13285
|
+
function transformPositions(positions, { offset, scale }) {
|
|
13286
|
+
const out = new Float32Array(positions.length);
|
|
13287
|
+
for (let i = 0; i < positions.length; i += 3) {
|
|
13288
|
+
out[i] = (positions[i] - offset[0]) * scale[0];
|
|
13289
|
+
out[i + 1] = (positions[i + 1] - offset[1]) * scale[1];
|
|
13290
|
+
out[i + 2] = (positions[i + 2] - offset[2]) * scale[2];
|
|
13291
|
+
}
|
|
13292
|
+
return out;
|
|
13293
|
+
}
|
|
13294
|
+
/** Uint16 indices while every vertex fits, Uint32 beyond 65535 vertices. */
|
|
13295
|
+
function createIndexArray(indices, vertexCount) {
|
|
13296
|
+
return vertexCount > 65535 ? new Uint32Array(indices) : new Uint16Array(indices);
|
|
13297
|
+
}
|
|
13298
|
+
/** The model's bounds after `transform`, as `Model3DData.bounds` reports them. */
|
|
13299
|
+
function transformModelBounds(bounds, { offset, scale }) {
|
|
13300
|
+
const min = [
|
|
13301
|
+
(bounds.min[0] - offset[0]) * scale[0],
|
|
13302
|
+
(bounds.min[1] - offset[1]) * scale[1],
|
|
13303
|
+
(bounds.min[2] - offset[2]) * scale[2]
|
|
13304
|
+
];
|
|
13305
|
+
const max = [
|
|
13306
|
+
(bounds.max[0] - offset[0]) * scale[0],
|
|
13307
|
+
(bounds.max[1] - offset[1]) * scale[1],
|
|
13308
|
+
(bounds.max[2] - offset[2]) * scale[2]
|
|
13309
|
+
];
|
|
13310
|
+
return {
|
|
13311
|
+
min,
|
|
13312
|
+
max,
|
|
13313
|
+
center: [
|
|
13314
|
+
(min[0] + max[0]) * .5,
|
|
13315
|
+
(min[1] + max[1]) * .5,
|
|
13316
|
+
(min[2] + max[2]) * .5
|
|
13317
|
+
],
|
|
13318
|
+
size: [
|
|
13319
|
+
max[0] - min[0],
|
|
13320
|
+
max[1] - min[1],
|
|
13321
|
+
max[2] - min[2]
|
|
13322
|
+
],
|
|
13323
|
+
boundingSphereRadius: Math.hypot(max[0] - min[0], max[1] - min[1], max[2] - min[2]) * .5
|
|
13324
|
+
};
|
|
13325
|
+
}
|
|
13326
|
+
/**
|
|
13327
|
+
* Poses a model's scene graph (glTF semantics): samples an animation clip's
|
|
13328
|
+
* translation / rotation / scale tracks at a time, composes the node
|
|
13329
|
+
* hierarchy into model-space matrices, and turns a skin's joints into the
|
|
13330
|
+
* joint matrices the mesh shader blends (joint world × inverse bind).
|
|
13331
|
+
*/
|
|
13332
|
+
/** Joints per skin the mesh shader holds (mesh3d.wgsl jointMatrices). */
|
|
13333
|
+
const MAX_JOINTS = 128;
|
|
13334
|
+
/** Column-major translate · rotate(quaternion) · scale. */
|
|
13335
|
+
function trsMatrix(t, q, s) {
|
|
13336
|
+
const [x, y, z, w] = q;
|
|
13337
|
+
const xx = x * x;
|
|
13338
|
+
const yy = y * y;
|
|
13339
|
+
const zz = z * z;
|
|
13340
|
+
const xy = x * y;
|
|
13341
|
+
const xz = x * z;
|
|
13342
|
+
const yz = y * z;
|
|
13343
|
+
const wx = w * x;
|
|
13344
|
+
const wy = w * y;
|
|
13345
|
+
const wz = w * z;
|
|
13346
|
+
return [
|
|
13347
|
+
(1 - 2 * (yy + zz)) * s[0],
|
|
13348
|
+
2 * (xy + wz) * s[0],
|
|
13349
|
+
2 * (xz - wy) * s[0],
|
|
13350
|
+
0,
|
|
13351
|
+
2 * (xy - wz) * s[1],
|
|
13352
|
+
(1 - 2 * (xx + zz)) * s[1],
|
|
13353
|
+
2 * (yz + wx) * s[1],
|
|
13354
|
+
0,
|
|
13355
|
+
2 * (xz + wy) * s[2],
|
|
13356
|
+
2 * (yz - wx) * s[2],
|
|
13357
|
+
(1 - 2 * (xx + yy)) * s[2],
|
|
13358
|
+
0,
|
|
13359
|
+
t[0],
|
|
13360
|
+
t[1],
|
|
13361
|
+
t[2],
|
|
13362
|
+
1
|
|
13363
|
+
];
|
|
13364
|
+
}
|
|
13365
|
+
function normalizeQuat(q) {
|
|
13366
|
+
const len = Math.hypot(q[0], q[1], q[2], q[3]) || 1;
|
|
13367
|
+
return [
|
|
13368
|
+
q[0] / len,
|
|
13369
|
+
q[1] / len,
|
|
13370
|
+
q[2] / len,
|
|
13371
|
+
q[3] / len
|
|
13372
|
+
];
|
|
13373
|
+
}
|
|
13374
|
+
function slerp(a, b, t) {
|
|
13375
|
+
let cos = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
|
|
13376
|
+
const sign = cos < 0 ? -1 : 1;
|
|
13377
|
+
cos *= sign;
|
|
13378
|
+
if (cos > .9995) return normalizeQuat([
|
|
13379
|
+
a[0] + (sign * b[0] - a[0]) * t,
|
|
13380
|
+
a[1] + (sign * b[1] - a[1]) * t,
|
|
13381
|
+
a[2] + (sign * b[2] - a[2]) * t,
|
|
13382
|
+
a[3] + (sign * b[3] - a[3]) * t
|
|
13383
|
+
]);
|
|
13384
|
+
const theta = Math.acos(cos);
|
|
13385
|
+
const sin = Math.sin(theta);
|
|
13386
|
+
const wa = Math.sin((1 - t) * theta) / sin;
|
|
13387
|
+
const wb = sign * Math.sin(t * theta) / sin;
|
|
13388
|
+
return [
|
|
13389
|
+
a[0] * wa + b[0] * wb,
|
|
13390
|
+
a[1] * wa + b[1] * wb,
|
|
13391
|
+
a[2] * wa + b[2] * wb,
|
|
13392
|
+
a[3] * wa + b[3] * wb
|
|
13393
|
+
];
|
|
13394
|
+
}
|
|
13395
|
+
/** Index of the last keyframe at or before `time` (binary search). */
|
|
13396
|
+
function keyBefore(times, time$2) {
|
|
13397
|
+
let lo = 0;
|
|
13398
|
+
let hi = times.length - 1;
|
|
13399
|
+
while (lo < hi) {
|
|
13400
|
+
const mid = lo + hi + 1 >> 1;
|
|
13401
|
+
if ((times[mid] ?? 0) <= time$2) lo = mid;
|
|
13402
|
+
else hi = mid - 1;
|
|
13403
|
+
}
|
|
13404
|
+
return lo;
|
|
13405
|
+
}
|
|
13406
|
+
/** Element `k` (of `size` components) of a track's values; cubic tracks store [in, value, out] triples. */
|
|
13407
|
+
function valueAt(values, k, size, cubic, part = 1) {
|
|
13408
|
+
const at = cubic ? (k * 3 + part) * size : k * size;
|
|
13409
|
+
return Array.from(values.subarray(at, at + size));
|
|
13410
|
+
}
|
|
13411
|
+
function sampleChannel(track, values, size, time$2) {
|
|
13412
|
+
const { times } = track;
|
|
13413
|
+
const cubic = track.interpolation === "cubic";
|
|
13414
|
+
const last = times.length - 1;
|
|
13415
|
+
if (time$2 <= (times[0] ?? 0)) return valueAt(values, 0, size, cubic);
|
|
13416
|
+
if (time$2 >= (times[last] ?? 0)) return valueAt(values, last, size, cubic);
|
|
13417
|
+
const k = keyBefore(times, time$2);
|
|
13418
|
+
if (track.interpolation === "step") return valueAt(values, k, size, cubic);
|
|
13419
|
+
const t0 = times[k] ?? 0;
|
|
13420
|
+
const dt = (times[k + 1] ?? t0) - t0;
|
|
13421
|
+
const u = dt > 0 ? (time$2 - t0) / dt : 0;
|
|
13422
|
+
const a = valueAt(values, k, size, cubic);
|
|
13423
|
+
const b = valueAt(values, k + 1, size, cubic);
|
|
13424
|
+
if (cubic) {
|
|
13425
|
+
const outA = valueAt(values, k, size, true, 2);
|
|
13426
|
+
const inB = valueAt(values, k + 1, size, true, 0);
|
|
13427
|
+
const u2 = u * u;
|
|
13428
|
+
const u3 = u2 * u;
|
|
13429
|
+
const out = a.map((p0, i) => (2 * u3 - 3 * u2 + 1) * p0 + (u3 - 2 * u2 + u) * dt * (outA[i] ?? 0) + (-2 * u3 + 3 * u2) * (b[i] ?? 0) + (u3 - u2) * dt * (inB[i] ?? 0));
|
|
13430
|
+
return size === 4 ? normalizeQuat(out) : out;
|
|
13431
|
+
}
|
|
13432
|
+
if (size === 4) return slerp(a, b, u);
|
|
13433
|
+
return a.map((v, i) => v + ((b[i] ?? v) - v) * u);
|
|
13434
|
+
}
|
|
13435
|
+
/** Each node's local matrix with the clip's tracks applied at `time` (seconds). */
|
|
13436
|
+
function localMatrices(nodes, clip, time$2) {
|
|
13437
|
+
const t = nodes.map((n) => [...n.translation]);
|
|
13438
|
+
const r = nodes.map((n) => [...n.rotation]);
|
|
13439
|
+
const s = nodes.map((n) => [...n.scale]);
|
|
13440
|
+
const byName = new Map(nodes.map((n, i) => [n.name, i]));
|
|
13441
|
+
for (const track of clip?.tracks ?? []) {
|
|
13442
|
+
const i = track.node ?? byName.get(track.nodeName);
|
|
13443
|
+
if (i === void 0 || !track.times.length) continue;
|
|
13444
|
+
if (track.translations) t[i] = sampleChannel(track, track.translations, 3, time$2);
|
|
13445
|
+
if (track.rotations) r[i] = sampleChannel(track, track.rotations, 4, time$2);
|
|
13446
|
+
if (track.scales) s[i] = sampleChannel(track, track.scales, 3, time$2);
|
|
13447
|
+
}
|
|
13448
|
+
return nodes.map((n, i) => n.matrix ?? trsMatrix(t[i], r[i], s[i]));
|
|
13449
|
+
}
|
|
13450
|
+
/**
|
|
13451
|
+
* Model-space matrix of every node, posed by `clip` at `time` seconds (the
|
|
13452
|
+
* rest pose without a clip). Parents may follow their children in the list.
|
|
13453
|
+
*/
|
|
13454
|
+
function poseNodes(model, clip, time$2) {
|
|
13455
|
+
const nodes = model.nodes ?? [];
|
|
13456
|
+
const local = localMatrices(nodes, clip, time$2);
|
|
13457
|
+
const world = new Array(nodes.length);
|
|
13458
|
+
const resolve$1$1 = (i) => {
|
|
13459
|
+
const done = world[i];
|
|
13460
|
+
if (done) return done;
|
|
13461
|
+
const parent = nodes[i].parent;
|
|
13462
|
+
const m = parent < 0 ? local[i] : Matrix4Math.multiply(resolve$1$1(parent), local[i]);
|
|
13463
|
+
world[i] = m;
|
|
13464
|
+
return m;
|
|
13465
|
+
};
|
|
13466
|
+
return nodes.map((_, i) => resolve$1$1(i));
|
|
13467
|
+
}
|
|
13468
|
+
/** The joint matrices of one skin for a posed scene graph, padded with identity to MAX_JOINTS. */
|
|
13469
|
+
function jointMatrices(model, skinIndex, world) {
|
|
13470
|
+
const skin = model.skins?.[skinIndex];
|
|
13471
|
+
if (!skin) throw new Error(`model has no skin ${skinIndex}`);
|
|
13472
|
+
const out = new Float32Array(MAX_JOINTS * 16);
|
|
13473
|
+
for (let j = 0; j < MAX_JOINTS; j++) {
|
|
13474
|
+
const node = skin.joints[j];
|
|
13475
|
+
if (node === void 0) {
|
|
13476
|
+
out.set(Matrix4Math.identity(), j * 16);
|
|
13477
|
+
continue;
|
|
13478
|
+
}
|
|
13479
|
+
const ibm = Array.from(skin.inverseBindMatrices.subarray(j * 16, j * 16 + 16));
|
|
13480
|
+
out.set(Matrix4Math.multiply(world[node], ibm), j * 16);
|
|
13481
|
+
}
|
|
13482
|
+
return out;
|
|
13483
|
+
}
|
|
13484
|
+
var FbxLoader = class FbxLoader$1 {
|
|
13485
|
+
static FBX_KTIME = 46186158e3;
|
|
13486
|
+
/**
|
|
13487
|
+
* Parses binary or text FBX buffer/string into Model3DData.
|
|
13488
|
+
*/
|
|
13489
|
+
static parse(bufferOrString, options = {}) {
|
|
13490
|
+
const rootNode = typeof bufferOrString === "string" ? FbxLoader$1.parseAscii(bufferOrString) : FbxLoader$1.isBinary(bufferOrString) ? FbxLoader$1.parseBinary(bufferOrString) : FbxLoader$1.parseAscii(new TextDecoder().decode(bufferOrString));
|
|
13491
|
+
return FbxLoader$1.buildModelFromTree(rootNode, options);
|
|
13492
|
+
}
|
|
13493
|
+
static isBinary(buffer) {
|
|
13494
|
+
const view = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
13495
|
+
if (view.length < 27) return false;
|
|
13496
|
+
const header = "Kaydara FBX Binary \0\0";
|
|
13497
|
+
for (let i = 0; i < 23; i++) if (view[i] !== header.charCodeAt(i)) return false;
|
|
13498
|
+
return true;
|
|
13499
|
+
}
|
|
13500
|
+
/**
|
|
13501
|
+
* Parses Binary FBX 7.x/6.x format.
|
|
13502
|
+
*/
|
|
13503
|
+
static parseBinary(buffer) {
|
|
13504
|
+
const u8 = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
13505
|
+
const view = new DataView(u8.buffer, u8.byteOffset, u8.byteLength);
|
|
13506
|
+
const is64Bit = view.getUint32(23, true) >= 7500;
|
|
13507
|
+
let offset = 27;
|
|
13508
|
+
const root = {
|
|
13509
|
+
name: "Root",
|
|
13510
|
+
props: [],
|
|
13511
|
+
children: []
|
|
13512
|
+
};
|
|
13513
|
+
const readNode = () => {
|
|
13514
|
+
if (offset >= u8.byteLength) return null;
|
|
13515
|
+
let endOffset;
|
|
13516
|
+
let numProperties;
|
|
13517
|
+
let nameLen;
|
|
13518
|
+
if (is64Bit) {
|
|
13519
|
+
if (offset + 25 > u8.byteLength) return null;
|
|
13520
|
+
endOffset = Number(view.getBigUint64(offset, true));
|
|
13521
|
+
numProperties = Number(view.getBigUint64(offset + 8, true));
|
|
13522
|
+
nameLen = view.getUint8(offset + 24);
|
|
13523
|
+
offset += 25;
|
|
13524
|
+
} else {
|
|
13525
|
+
if (offset + 13 > u8.byteLength) return null;
|
|
13526
|
+
endOffset = view.getUint32(offset, true);
|
|
13527
|
+
numProperties = view.getUint32(offset + 4, true);
|
|
13528
|
+
nameLen = view.getUint8(offset + 12);
|
|
13529
|
+
offset += 13;
|
|
13530
|
+
}
|
|
13531
|
+
if (endOffset === 0) return null;
|
|
13532
|
+
const name = new TextDecoder().decode(u8.subarray(offset, offset + nameLen));
|
|
13533
|
+
offset += nameLen;
|
|
13534
|
+
const props = [];
|
|
13535
|
+
for (let p = 0; p < numProperties; p++) {
|
|
13536
|
+
const typeCode = String.fromCharCode(u8[offset]);
|
|
13537
|
+
offset += 1;
|
|
13538
|
+
switch (typeCode) {
|
|
13539
|
+
case "Y":
|
|
13540
|
+
props.push(view.getInt16(offset, true));
|
|
13541
|
+
offset += 2;
|
|
13542
|
+
break;
|
|
13543
|
+
case "C":
|
|
13544
|
+
case "B":
|
|
13545
|
+
props.push(view.getUint8(offset) !== 0);
|
|
13546
|
+
offset += 1;
|
|
13547
|
+
break;
|
|
13548
|
+
case "I":
|
|
13549
|
+
props.push(view.getInt32(offset, true));
|
|
13550
|
+
offset += 4;
|
|
13551
|
+
break;
|
|
13552
|
+
case "F":
|
|
13553
|
+
props.push(view.getFloat32(offset, true));
|
|
13554
|
+
offset += 4;
|
|
13555
|
+
break;
|
|
13556
|
+
case "D":
|
|
13557
|
+
props.push(view.getFloat64(offset, true));
|
|
13558
|
+
offset += 8;
|
|
13559
|
+
break;
|
|
13560
|
+
case "L":
|
|
13561
|
+
props.push(Number(view.getBigInt64(offset, true)));
|
|
13562
|
+
offset += 8;
|
|
13563
|
+
break;
|
|
13564
|
+
case "S": {
|
|
13565
|
+
const len = view.getUint32(offset, true);
|
|
13566
|
+
offset += 4;
|
|
13567
|
+
const str = new TextDecoder().decode(u8.subarray(offset, offset + len));
|
|
13568
|
+
props.push(str);
|
|
13569
|
+
offset += len;
|
|
13570
|
+
break;
|
|
13571
|
+
}
|
|
13572
|
+
case "R": {
|
|
13573
|
+
const len = view.getUint32(offset, true);
|
|
13574
|
+
offset += 4;
|
|
13575
|
+
const raw = u8.subarray(offset, offset + len);
|
|
13576
|
+
props.push(raw);
|
|
13577
|
+
offset += len;
|
|
13578
|
+
break;
|
|
13579
|
+
}
|
|
13580
|
+
case "f":
|
|
13581
|
+
case "d":
|
|
13582
|
+
case "i":
|
|
13583
|
+
case "l":
|
|
13584
|
+
case "b":
|
|
13585
|
+
case "c": {
|
|
13586
|
+
const arrayLen = view.getUint32(offset, true);
|
|
13587
|
+
const encoding = view.getUint32(offset + 4, true);
|
|
13588
|
+
const compressedLen = view.getUint32(offset + 8, true);
|
|
13589
|
+
offset += 12;
|
|
13590
|
+
let arrayBuffer;
|
|
13591
|
+
if (encoding === 1) {
|
|
13592
|
+
arrayBuffer = inflateSync(u8.subarray(offset, offset + compressedLen));
|
|
13593
|
+
offset += compressedLen;
|
|
13594
|
+
} else {
|
|
13595
|
+
const totalBytes = arrayLen * (typeCode === "d" || typeCode === "l" ? 8 : typeCode === "f" || typeCode === "i" ? 4 : 1);
|
|
13596
|
+
arrayBuffer = u8.subarray(offset, offset + totalBytes);
|
|
13597
|
+
offset += totalBytes;
|
|
13598
|
+
}
|
|
13599
|
+
const arrayView = new DataView(arrayBuffer.buffer, arrayBuffer.byteOffset, arrayBuffer.byteLength);
|
|
13600
|
+
if (typeCode === "f") {
|
|
13601
|
+
const arr = new Float32Array(arrayLen);
|
|
13602
|
+
for (let k = 0; k < arrayLen; k++) arr[k] = arrayView.getFloat32(k * 4, true);
|
|
13603
|
+
props.push(arr);
|
|
13604
|
+
} else if (typeCode === "d") {
|
|
13605
|
+
const arr = new Float64Array(arrayLen);
|
|
13606
|
+
for (let k = 0; k < arrayLen; k++) arr[k] = arrayView.getFloat64(k * 8, true);
|
|
13607
|
+
props.push(arr);
|
|
13608
|
+
} else if (typeCode === "i") {
|
|
13609
|
+
const arr = new Int32Array(arrayLen);
|
|
13610
|
+
for (let k = 0; k < arrayLen; k++) arr[k] = arrayView.getInt32(k * 4, true);
|
|
13611
|
+
props.push(arr);
|
|
13612
|
+
} else if (typeCode === "l") {
|
|
13613
|
+
const arr = new Float64Array(arrayLen);
|
|
13614
|
+
for (let k = 0; k < arrayLen; k++) arr[k] = Number(arrayView.getBigInt64(k * 8, true));
|
|
13615
|
+
props.push(arr);
|
|
13616
|
+
} else if (typeCode === "b") {
|
|
13617
|
+
const arr = new Uint8Array(arrayLen);
|
|
13618
|
+
for (let k = 0; k < arrayLen; k++) arr[k] = arrayView.getUint8(k);
|
|
13619
|
+
props.push(arr);
|
|
13620
|
+
} else props.push(arrayBuffer);
|
|
13621
|
+
break;
|
|
13622
|
+
}
|
|
13623
|
+
default: break;
|
|
13624
|
+
}
|
|
13625
|
+
}
|
|
13626
|
+
const children = [];
|
|
13627
|
+
while (offset < endOffset) {
|
|
13628
|
+
const child = readNode();
|
|
13629
|
+
if (child) children.push(child);
|
|
13630
|
+
else break;
|
|
13631
|
+
}
|
|
13632
|
+
offset = endOffset;
|
|
13633
|
+
return {
|
|
13634
|
+
name,
|
|
13635
|
+
props,
|
|
13636
|
+
children
|
|
13637
|
+
};
|
|
13638
|
+
};
|
|
13639
|
+
while (offset < u8.byteLength - (is64Bit ? 25 : 13)) {
|
|
13640
|
+
const node = readNode();
|
|
13641
|
+
if (node) root.children.push(node);
|
|
13642
|
+
else break;
|
|
13643
|
+
}
|
|
13644
|
+
return root;
|
|
13645
|
+
}
|
|
13646
|
+
/**
|
|
13647
|
+
* Parses ASCII FBX format.
|
|
13648
|
+
*/
|
|
13649
|
+
static parseAscii(text) {
|
|
13650
|
+
const root = {
|
|
13651
|
+
name: "Root",
|
|
13652
|
+
props: [],
|
|
13653
|
+
children: []
|
|
13654
|
+
};
|
|
13655
|
+
const stack = [root];
|
|
13656
|
+
const lines = text.split(/\r?\n/);
|
|
13657
|
+
for (let i = 0; i < lines.length; i++) {
|
|
13658
|
+
const line = lines[i]?.trim();
|
|
13659
|
+
if (!line || line.startsWith(";")) continue;
|
|
13660
|
+
if (line === "}") {
|
|
13661
|
+
if (stack.length > 1) stack.pop();
|
|
13662
|
+
continue;
|
|
13663
|
+
}
|
|
13664
|
+
const colonIdx = line.indexOf(":");
|
|
13665
|
+
if (colonIdx === -1) continue;
|
|
13666
|
+
const name = line.substring(0, colonIdx).trim();
|
|
13667
|
+
const rest = line.substring(colonIdx + 1).trim();
|
|
13236
13668
|
const hasBrace = rest.endsWith("{");
|
|
13237
13669
|
const propStr = hasBrace ? rest.slice(0, -1).trim() : rest;
|
|
13238
13670
|
const props = [];
|
|
@@ -13253,6 +13685,53 @@ var FbxLoader = class FbxLoader$1 {
|
|
|
13253
13685
|
}
|
|
13254
13686
|
return root;
|
|
13255
13687
|
}
|
|
13688
|
+
/** Material properties a texture can feed, by the FBX (or Maya / 3ds Max) property name. */
|
|
13689
|
+
static textureSlot(prop) {
|
|
13690
|
+
const p = prop.toLowerCase();
|
|
13691
|
+
if (p === "diffusecolor" || p === "diffuse" || p.endsWith("|basecolor") || p.endsWith("|base_color") || p === "basecolor") return "diffuse";
|
|
13692
|
+
if (p === "normalmap" || p.endsWith("|normalcamera") || p.endsWith("|bump_map")) return "normal";
|
|
13693
|
+
}
|
|
13694
|
+
/**
|
|
13695
|
+
* Fills a material's diffuse / normal map from its connected Texture
|
|
13696
|
+
* objects: the bytes embedded in the Video's `Content`, else the file
|
|
13697
|
+
* named by `RelativeFilename` / `FileName`, looked up next to the model.
|
|
13698
|
+
*/
|
|
13699
|
+
static attachTextures(material, materialId, objects, connections, basePath) {
|
|
13700
|
+
const stringChild = (node, name) => {
|
|
13701
|
+
const value = node?.children.find((c) => c.name === name)?.props[0];
|
|
13702
|
+
return typeof value === "string" && value ? value : void 0;
|
|
13703
|
+
};
|
|
13704
|
+
for (const c of connections) {
|
|
13705
|
+
if (c.parentId !== materialId || !c.propName) continue;
|
|
13706
|
+
const slot = FbxLoader$1.textureSlot(c.propName);
|
|
13707
|
+
const texture = objects.get(c.childId);
|
|
13708
|
+
if (!slot || texture?.node.name !== "Texture") continue;
|
|
13709
|
+
if (slot === "diffuse" ? material.diffuseTextureBuffer : material.normalTextureBuffer) continue;
|
|
13710
|
+
const video = connections.filter((v) => v.parentId === c.childId && !v.propName).map((v) => objects.get(v.childId)?.node).find((n) => n?.name === "Video");
|
|
13711
|
+
const ref = stringChild(texture.node, "RelativeFilename") ?? stringChild(texture.node, "FileName") ?? stringChild(video, "RelativeFilename") ?? stringChild(video, "Filename");
|
|
13712
|
+
if (ref && !isSupportedTexture(ref)) {
|
|
13713
|
+
warnMissingTexture("FbxLoader", material.name, ref);
|
|
13714
|
+
continue;
|
|
13715
|
+
}
|
|
13716
|
+
let bytes;
|
|
13717
|
+
const content = video?.children.find((n) => n.name === "Content")?.props[0];
|
|
13718
|
+
if (content instanceof Uint8Array && content.length > 0) bytes = content;
|
|
13719
|
+
else if (ref) bytes = readTextureFile(ref, basePath)?.bytes;
|
|
13720
|
+
if (!bytes) {
|
|
13721
|
+
if (ref) warnMissingTexture("FbxLoader", material.name, ref);
|
|
13722
|
+
continue;
|
|
13723
|
+
}
|
|
13724
|
+
if (slot === "diffuse") {
|
|
13725
|
+
material.diffuseTextureBuffer = bytes;
|
|
13726
|
+
material.diffuseTextureMime = textureMime(ref ?? "");
|
|
13727
|
+
if (ref) material.diffuseTexture = ref;
|
|
13728
|
+
material.textureWrap = "repeat";
|
|
13729
|
+
} else {
|
|
13730
|
+
material.normalTextureBuffer = bytes;
|
|
13731
|
+
if (ref) material.normalTexture = ref;
|
|
13732
|
+
}
|
|
13733
|
+
}
|
|
13734
|
+
}
|
|
13256
13735
|
/**
|
|
13257
13736
|
* Builds ready-to-render Model3DData from parsed FBX node tree.
|
|
13258
13737
|
*/
|
|
@@ -13286,6 +13765,20 @@ var FbxLoader = class FbxLoader$1 {
|
|
|
13286
13765
|
});
|
|
13287
13766
|
}
|
|
13288
13767
|
}
|
|
13768
|
+
const materialNameForGeometry = (geometryId) => {
|
|
13769
|
+
for (const c of connections) {
|
|
13770
|
+
const mat = c.parentId === geometryId ? objects.get(c.childId) : void 0;
|
|
13771
|
+
if (mat?.node.name === "Material" && !c.propName) return mat.name;
|
|
13772
|
+
}
|
|
13773
|
+
for (const g$1 of connections) {
|
|
13774
|
+
if (g$1.childId !== geometryId || g$1.propName) continue;
|
|
13775
|
+
for (const m of connections) {
|
|
13776
|
+
if (m.parentId !== g$1.parentId || m.propName) continue;
|
|
13777
|
+
const mat = objects.get(m.childId);
|
|
13778
|
+
if (mat?.node.name === "Material") return mat.name;
|
|
13779
|
+
}
|
|
13780
|
+
}
|
|
13781
|
+
};
|
|
13289
13782
|
const meshes = [];
|
|
13290
13783
|
const materials = {};
|
|
13291
13784
|
function extractArrayProp(node) {
|
|
@@ -13296,149 +13789,142 @@ var FbxLoader = class FbxLoader$1 {
|
|
|
13296
13789
|
if (Array.isArray(node.props) && node.props.length > 0 && typeof node.props[0] === "number") return node.props;
|
|
13297
13790
|
return [];
|
|
13298
13791
|
}
|
|
13792
|
+
const modelIds = [...objects.values()].filter((o) => o.node.name === "Model").map((o) => o.id);
|
|
13793
|
+
const nodeIndexById = new Map(modelIds.map((id, i) => [id, i]));
|
|
13794
|
+
const nodes = modelIds.map((id) => {
|
|
13795
|
+
const model$1 = objects.get(id);
|
|
13796
|
+
const parentConn = connections.find((c) => c.childId === id && !c.propName && nodeIndexById.has(c.parentId));
|
|
13797
|
+
return {
|
|
13798
|
+
name: model$1.name,
|
|
13799
|
+
parent: parentConn ? nodeIndexById.get(parentConn.parentId) : -1,
|
|
13800
|
+
translation: readVec3(model$1.node, "Lcl Translation", 0),
|
|
13801
|
+
rotation: modelRotation(model$1.node, fbxEulerToQuat(readVec3(model$1.node, "Lcl Rotation", 0), rotationOrder(model$1.node))),
|
|
13802
|
+
scale: readVec3(model$1.node, "Lcl Scaling", 1)
|
|
13803
|
+
};
|
|
13804
|
+
});
|
|
13805
|
+
const modelOfGeometry = (geometryId) => connections.find((c) => c.childId === geometryId && !c.propName && nodeIndexById.has(c.parentId))?.parentId;
|
|
13806
|
+
const skins = [];
|
|
13299
13807
|
for (const [id, entry] of objects) if (entry.node.name === "Geometry" && (entry.type === "Mesh" || entry.node.props[2] === "Mesh" || entry.type === "")) {
|
|
13300
13808
|
const geomNode = entry.node;
|
|
13301
13809
|
const verticesNode = geomNode.children.find((c) => c.name === "Vertices");
|
|
13302
13810
|
const indicesNode = geomNode.children.find((c) => c.name === "PolygonVertexIndex");
|
|
13303
|
-
const normalLayer = geomNode.children.find((c) => c.name === "LayerElementNormal");
|
|
13304
|
-
const uvLayer = geomNode.children.find((c) => c.name === "LayerElementUV");
|
|
13305
13811
|
if (!verticesNode || !indicesNode) continue;
|
|
13306
13812
|
const rawVerts = extractArrayProp(verticesNode);
|
|
13307
13813
|
const rawPolyIndices = extractArrayProp(indicesNode);
|
|
13308
|
-
const
|
|
13309
|
-
|
|
13310
|
-
|
|
13311
|
-
|
|
13312
|
-
|
|
13313
|
-
const
|
|
13314
|
-
const
|
|
13315
|
-
const
|
|
13814
|
+
const layer = (name, data, index, size) => {
|
|
13815
|
+
const node = geomNode.children.find((c) => c.name === name);
|
|
13816
|
+
if (!node) return void 0;
|
|
13817
|
+
return layerElement(node, extractArrayProp(node.children.find((c) => c.name === data)), extractArrayProp(node.children.find((c) => c.name === index)), size);
|
|
13818
|
+
};
|
|
13819
|
+
const normalAt = layer("LayerElementNormal", "Normals", "NormalsIndex", 3);
|
|
13820
|
+
const uvAt = layer("LayerElementUV", "UV", "UVIndex", 2);
|
|
13821
|
+
const corners = [];
|
|
13316
13822
|
let polygon = [];
|
|
13823
|
+
let polyIndex = 0;
|
|
13317
13824
|
for (let i = 0; i < rawPolyIndices.length; i++) {
|
|
13318
13825
|
const idx = rawPolyIndices[i];
|
|
13319
|
-
|
|
13320
|
-
|
|
13321
|
-
|
|
13322
|
-
|
|
13323
|
-
|
|
13324
|
-
|
|
13325
|
-
|
|
13326
|
-
]
|
|
13327
|
-
polygon
|
|
13328
|
-
|
|
13329
|
-
|
|
13330
|
-
|
|
13331
|
-
}
|
|
13332
|
-
|
|
13333
|
-
|
|
13334
|
-
const outNormals = [];
|
|
13335
|
-
const outUvs = [];
|
|
13336
|
-
const outIndices = [];
|
|
13337
|
-
for (let t = 0; t < triangles.length; t++) {
|
|
13338
|
-
const tri = triangles[t];
|
|
13339
|
-
for (let v = 0; v < 3; v++) {
|
|
13340
|
-
const vertIdx = tri[v];
|
|
13341
|
-
const outIdx = outPositions.length / 3;
|
|
13342
|
-
const px = rawVerts[vertIdx * 3] ?? 0;
|
|
13343
|
-
const py = rawVerts[vertIdx * 3 + 1] ?? 0;
|
|
13344
|
-
const pz = rawVerts[vertIdx * 3 + 2] ?? 0;
|
|
13345
|
-
outPositions.push(px, py, pz);
|
|
13346
|
-
if (rawNormals.length > 0) {
|
|
13347
|
-
const nx = rawNormals[vertIdx * 3] ?? 0;
|
|
13348
|
-
const ny = rawNormals[vertIdx * 3 + 1] ?? 0;
|
|
13349
|
-
const nz = rawNormals[vertIdx * 3 + 2] ?? 0;
|
|
13350
|
-
outNormals.push(nx, ny, nz);
|
|
13351
|
-
} else outNormals.push(0, 0, 1);
|
|
13352
|
-
if (rawUvs.length > 0) {
|
|
13353
|
-
let uvIdx = vertIdx;
|
|
13354
|
-
if (rawUvIndices.length > 0) uvIdx = rawUvIndices[vertIdx] ?? vertIdx;
|
|
13355
|
-
const u = rawUvs[uvIdx * 2] ?? 0;
|
|
13356
|
-
const v$1 = rawUvs[uvIdx * 2 + 1] ?? 0;
|
|
13357
|
-
outUvs.push(u, 1 - v$1);
|
|
13358
|
-
} else outUvs.push(0, 0);
|
|
13359
|
-
outIndices.push(outIdx);
|
|
13360
|
-
}
|
|
13826
|
+
polygon.push({
|
|
13827
|
+
cp: idx < 0 ? -(idx + 1) : idx,
|
|
13828
|
+
pv: i
|
|
13829
|
+
});
|
|
13830
|
+
if (idx >= 0) continue;
|
|
13831
|
+
for (let k = 1; k < polygon.length - 1; k++) for (const c of [
|
|
13832
|
+
polygon[0],
|
|
13833
|
+
polygon[k],
|
|
13834
|
+
polygon[k + 1]
|
|
13835
|
+
]) corners.push({
|
|
13836
|
+
...c,
|
|
13837
|
+
poly: polyIndex
|
|
13838
|
+
});
|
|
13839
|
+
polygon = [];
|
|
13840
|
+
polyIndex++;
|
|
13361
13841
|
}
|
|
13362
|
-
|
|
13363
|
-
|
|
13364
|
-
|
|
13365
|
-
|
|
13366
|
-
|
|
13367
|
-
|
|
13368
|
-
|
|
13369
|
-
|
|
13370
|
-
|
|
13371
|
-
|
|
13372
|
-
|
|
13373
|
-
|
|
13374
|
-
|
|
13375
|
-
|
|
13376
|
-
|
|
13377
|
-
|
|
13378
|
-
|
|
13379
|
-
|
|
13380
|
-
|
|
13381
|
-
|
|
13382
|
-
|
|
13383
|
-
|
|
13384
|
-
|
|
13385
|
-
const faceNormal = Vector3Math.cross(edge1, edge2);
|
|
13386
|
-
computedNormals[i0 * 3] += faceNormal[0];
|
|
13387
|
-
computedNormals[i0 * 3 + 1] += faceNormal[1];
|
|
13388
|
-
computedNormals[i0 * 3 + 2] += faceNormal[2];
|
|
13389
|
-
computedNormals[i1 * 3] += faceNormal[0];
|
|
13390
|
-
computedNormals[i1 * 3 + 1] += faceNormal[1];
|
|
13391
|
-
computedNormals[i1 * 3 + 2] += faceNormal[2];
|
|
13392
|
-
computedNormals[i2 * 3] += faceNormal[0];
|
|
13393
|
-
computedNormals[i2 * 3 + 1] += faceNormal[1];
|
|
13394
|
-
computedNormals[i2 * 3 + 2] += faceNormal[2];
|
|
13395
|
-
}
|
|
13396
|
-
for (let v = 0; v < outPositions.length / 3; v++) {
|
|
13397
|
-
const nx = computedNormals[v * 3];
|
|
13398
|
-
const ny = computedNormals[v * 3 + 1];
|
|
13399
|
-
const nz = computedNormals[v * 3 + 2];
|
|
13400
|
-
const len = Math.hypot(nx, ny, nz) || 1;
|
|
13401
|
-
outNormals[v * 3] = nx / len;
|
|
13402
|
-
outNormals[v * 3 + 1] = ny / len;
|
|
13403
|
-
outNormals[v * 3 + 2] = nz / len;
|
|
13404
|
-
}
|
|
13842
|
+
const numVerts = corners.length;
|
|
13843
|
+
const outPositions = new Float32Array(numVerts * 3);
|
|
13844
|
+
const outNormals = new Float32Array(numVerts * 3);
|
|
13845
|
+
const outUvs = new Float32Array(numVerts * 2);
|
|
13846
|
+
const outIndices = new Array(numVerts);
|
|
13847
|
+
corners.forEach(({ cp, pv, poly }, v) => {
|
|
13848
|
+
outPositions[v * 3] = rawVerts[cp * 3] ?? 0;
|
|
13849
|
+
outPositions[v * 3 + 1] = rawVerts[cp * 3 + 1] ?? 0;
|
|
13850
|
+
outPositions[v * 3 + 2] = rawVerts[cp * 3 + 2] ?? 0;
|
|
13851
|
+
const n = normalAt?.(cp, pv, poly);
|
|
13852
|
+
outNormals.set(n ?? [
|
|
13853
|
+
0,
|
|
13854
|
+
0,
|
|
13855
|
+
1
|
|
13856
|
+
], v * 3);
|
|
13857
|
+
const uv = uvAt?.(cp, pv, poly);
|
|
13858
|
+
outUvs[v * 2] = uv?.[0] ?? 0;
|
|
13859
|
+
outUvs[v * 2 + 1] = 1 - (uv?.[1] ?? 0);
|
|
13860
|
+
outIndices[v] = v;
|
|
13861
|
+
});
|
|
13862
|
+
if (!normalAt || options.smoothNormals) {
|
|
13863
|
+
outNormals.fill(0);
|
|
13864
|
+
accumulateVertexNormals(outPositions, outIndices, outNormals);
|
|
13405
13865
|
}
|
|
13406
|
-
const skinConn = connections.find((c) => c.parentId === id && objects.get(c.childId)?.
|
|
13866
|
+
const skinConn = connections.find((c) => c.parentId === id && objects.get(c.childId)?.node.name === "Deformer" && objects.get(c.childId)?.node.props[2] === "Skin");
|
|
13407
13867
|
let jointIndices;
|
|
13408
13868
|
let jointWeights;
|
|
13869
|
+
let skinIndex;
|
|
13409
13870
|
if (skinConn) {
|
|
13410
|
-
const
|
|
13411
|
-
|
|
13412
|
-
|
|
13413
|
-
|
|
13414
|
-
const
|
|
13415
|
-
|
|
13416
|
-
const
|
|
13417
|
-
if (
|
|
13418
|
-
|
|
13419
|
-
|
|
13420
|
-
|
|
13421
|
-
|
|
13422
|
-
|
|
13423
|
-
|
|
13424
|
-
|
|
13425
|
-
|
|
13426
|
-
|
|
13427
|
-
|
|
13871
|
+
const joints = [];
|
|
13872
|
+
const inverseBinds = [];
|
|
13873
|
+
const influences = /* @__PURE__ */ new Map();
|
|
13874
|
+
for (const cc of connections) {
|
|
13875
|
+
const cluster = objects.get(cc.childId);
|
|
13876
|
+
if (cc.parentId !== skinConn.childId || cluster?.node.name !== "Deformer" || cluster.node.props[2] !== "Cluster") continue;
|
|
13877
|
+
const boneId = connections.find((b) => b.parentId === cluster.id && nodeIndexById.has(b.childId))?.childId;
|
|
13878
|
+
if (boneId === void 0) continue;
|
|
13879
|
+
const joint = joints.length;
|
|
13880
|
+
joints.push(nodeIndexById.get(boneId));
|
|
13881
|
+
const transform$1 = matrixChild(cluster.node, "Transform");
|
|
13882
|
+
const link = matrixChild(cluster.node, "TransformLink");
|
|
13883
|
+
inverseBinds.push(...Matrix4Math.multiply(Matrix4Math.invert(link) ?? Matrix4Math.identity(), transform$1));
|
|
13884
|
+
const cpIndexes = extractArrayProp(cluster.node.children.find((c) => c.name === "Indexes"));
|
|
13885
|
+
const cpWeights = extractArrayProp(cluster.node.children.find((c) => c.name === "Weights"));
|
|
13886
|
+
for (let k = 0; k < cpIndexes.length; k++) {
|
|
13887
|
+
const weight = Number(cpWeights[k] ?? 0);
|
|
13888
|
+
if (!(weight > 0)) continue;
|
|
13889
|
+
const cp = Number(cpIndexes[k]);
|
|
13890
|
+
const list = influences.get(cp) ?? [];
|
|
13891
|
+
list.push([joint, weight]);
|
|
13892
|
+
influences.set(cp, list);
|
|
13428
13893
|
}
|
|
13429
|
-
}
|
|
13894
|
+
}
|
|
13895
|
+
if (joints.length > MAX_JOINTS) throw new Error(`FBX skin has ${joints.length} bones; the mesh shader holds ${MAX_JOINTS}`);
|
|
13896
|
+
if (joints.length > 0) {
|
|
13897
|
+
skinIndex = skins.length;
|
|
13898
|
+
skins.push({
|
|
13899
|
+
joints,
|
|
13900
|
+
inverseBindMatrices: new Float32Array(inverseBinds)
|
|
13901
|
+
});
|
|
13902
|
+
jointIndices = new Float32Array(numVerts * 4);
|
|
13903
|
+
jointWeights = new Float32Array(numVerts * 4);
|
|
13904
|
+
corners.forEach(({ cp }, v) => {
|
|
13905
|
+
const top = (influences.get(cp) ?? []).sort((a, b) => b[1] - a[1]).slice(0, 4);
|
|
13906
|
+
const total = top.reduce((sum, [, w]) => sum + w, 0);
|
|
13907
|
+
top.forEach(([joint, weight], slot) => {
|
|
13908
|
+
jointIndices[v * 4 + slot] = joint;
|
|
13909
|
+
jointWeights[v * 4 + slot] = total > 0 ? weight / total : 0;
|
|
13910
|
+
});
|
|
13911
|
+
});
|
|
13912
|
+
}
|
|
13430
13913
|
}
|
|
13431
|
-
const
|
|
13914
|
+
const modelId = modelOfGeometry(id);
|
|
13915
|
+
const isLarge = numVerts > 65535;
|
|
13432
13916
|
meshes.push({
|
|
13433
13917
|
id: `fbx_mesh_${id}`,
|
|
13434
13918
|
name: entry.name,
|
|
13435
|
-
positions:
|
|
13436
|
-
normals:
|
|
13437
|
-
uvs:
|
|
13919
|
+
positions: outPositions,
|
|
13920
|
+
normals: outNormals,
|
|
13921
|
+
uvs: outUvs,
|
|
13438
13922
|
indices: isLarge ? new Uint32Array(outIndices) : new Uint16Array(outIndices),
|
|
13439
13923
|
jointIndices,
|
|
13440
13924
|
jointWeights,
|
|
13441
|
-
materialName: entry.name
|
|
13925
|
+
materialName: materialNameForGeometry(id) ?? entry.name,
|
|
13926
|
+
node: modelId !== void 0 ? nodeIndexById.get(modelId) : void 0,
|
|
13927
|
+
skin: skinIndex
|
|
13442
13928
|
});
|
|
13443
13929
|
}
|
|
13444
13930
|
for (const [, entry] of objects) if (entry.node.name === "Material") {
|
|
@@ -13467,12 +13953,14 @@ var FbxLoader = class FbxLoader$1 {
|
|
|
13467
13953
|
}
|
|
13468
13954
|
}
|
|
13469
13955
|
}
|
|
13470
|
-
|
|
13956
|
+
const material = {
|
|
13471
13957
|
name: entry.name,
|
|
13472
13958
|
diffuseColor,
|
|
13473
13959
|
shininess,
|
|
13474
13960
|
opacity
|
|
13475
13961
|
};
|
|
13962
|
+
FbxLoader$1.attachTextures(material, entry.id, objects, connections, options.basePath);
|
|
13963
|
+
materials[entry.name] = material;
|
|
13476
13964
|
}
|
|
13477
13965
|
const animations = [];
|
|
13478
13966
|
for (const [id, entry] of objects) if (entry.node.name === "AnimationStack") {
|
|
@@ -13492,12 +13980,13 @@ var FbxLoader = class FbxLoader$1 {
|
|
|
13492
13980
|
const key = `${targetModel?.id ?? curveNodeObj.id}|${kind}`;
|
|
13493
13981
|
let group = groups.get(key);
|
|
13494
13982
|
if (!group) {
|
|
13495
|
-
const model = targetModel?.node;
|
|
13983
|
+
const model$1 = targetModel?.node;
|
|
13496
13984
|
group = {
|
|
13497
13985
|
nodeName: targetModel?.name ?? curveNodeObj.name,
|
|
13498
|
-
|
|
13986
|
+
modelId: targetModel?.id,
|
|
13987
|
+
model: model$1,
|
|
13499
13988
|
kind,
|
|
13500
|
-
defaults: staticTransform(model, curveNodeObj.node, kind),
|
|
13989
|
+
defaults: staticTransform(model$1, curveNodeObj.node, kind),
|
|
13501
13990
|
channels: [
|
|
13502
13991
|
void 0,
|
|
13503
13992
|
void 0,
|
|
@@ -13522,7 +14011,13 @@ var FbxLoader = class FbxLoader$1 {
|
|
|
13522
14011
|
}
|
|
13523
14012
|
for (const group of groups.values()) {
|
|
13524
14013
|
const track = buildTransformTrack(group);
|
|
13525
|
-
if (track)
|
|
14014
|
+
if (!track) continue;
|
|
14015
|
+
if (group.modelId !== void 0) track.node = nodeIndexById.get(group.modelId);
|
|
14016
|
+
if (track.rotations && group.model) for (let k = 0; k < track.rotations.length; k += 4) {
|
|
14017
|
+
const q = Array.from(track.rotations.subarray(k, k + 4));
|
|
14018
|
+
track.rotations.set(modelRotation(group.model, q), k);
|
|
14019
|
+
}
|
|
14020
|
+
tracks.push(track);
|
|
13526
14021
|
}
|
|
13527
14022
|
}
|
|
13528
14023
|
let maxDuration = 1;
|
|
@@ -13533,72 +14028,176 @@ var FbxLoader = class FbxLoader$1 {
|
|
|
13533
14028
|
animations.push({
|
|
13534
14029
|
name: stackName,
|
|
13535
14030
|
duration: maxDuration,
|
|
13536
|
-
fps: 30,
|
|
13537
|
-
tracks
|
|
13538
|
-
});
|
|
13539
|
-
}
|
|
13540
|
-
let minX = Infinity;
|
|
13541
|
-
let minY = Infinity;
|
|
13542
|
-
let minZ = Infinity;
|
|
13543
|
-
let maxX = -Infinity;
|
|
13544
|
-
let maxY = -Infinity;
|
|
13545
|
-
let maxZ = -Infinity;
|
|
13546
|
-
for (const mesh of meshes) for (let i = 0; i < mesh.positions.length; i += 3) {
|
|
13547
|
-
const x = mesh.positions[i];
|
|
13548
|
-
const y = mesh.positions[i + 1];
|
|
13549
|
-
const z = mesh.positions[i + 2];
|
|
13550
|
-
if (x < minX) minX = x;
|
|
13551
|
-
if (y < minY) minY = y;
|
|
13552
|
-
if (z < minZ) minZ = z;
|
|
13553
|
-
if (x > maxX) maxX = x;
|
|
13554
|
-
if (y > maxY) maxY = y;
|
|
13555
|
-
if (z > maxZ) maxZ = z;
|
|
13556
|
-
}
|
|
13557
|
-
if (!Number.isFinite(minX)) {
|
|
13558
|
-
minX = -1;
|
|
13559
|
-
minY = -1;
|
|
13560
|
-
minZ = -1;
|
|
13561
|
-
maxX = 1;
|
|
13562
|
-
maxY = 1;
|
|
13563
|
-
maxZ = 1;
|
|
14031
|
+
fps: 30,
|
|
14032
|
+
tracks
|
|
14033
|
+
});
|
|
13564
14034
|
}
|
|
13565
|
-
const
|
|
13566
|
-
const sizeY = maxY - minY;
|
|
13567
|
-
const sizeZ = maxZ - minZ;
|
|
13568
|
-
const centerX = (minX + maxX) * .5;
|
|
13569
|
-
const centerY = (minY + maxY) * .5;
|
|
13570
|
-
const centerZ = (minZ + maxZ) * .5;
|
|
13571
|
-
const sphereRadius = Math.hypot(sizeX, sizeY, sizeZ) * .5;
|
|
13572
|
-
return {
|
|
14035
|
+
const model = {
|
|
13573
14036
|
meshes,
|
|
13574
14037
|
materials,
|
|
13575
14038
|
animations,
|
|
14039
|
+
nodes,
|
|
14040
|
+
skins,
|
|
13576
14041
|
bounds: {
|
|
13577
14042
|
min: [
|
|
13578
|
-
|
|
13579
|
-
|
|
13580
|
-
|
|
14043
|
+
0,
|
|
14044
|
+
0,
|
|
14045
|
+
0
|
|
13581
14046
|
],
|
|
13582
14047
|
max: [
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
14048
|
+
0,
|
|
14049
|
+
0,
|
|
14050
|
+
0
|
|
13586
14051
|
],
|
|
13587
14052
|
center: [
|
|
13588
|
-
|
|
13589
|
-
|
|
13590
|
-
|
|
14053
|
+
0,
|
|
14054
|
+
0,
|
|
14055
|
+
0
|
|
13591
14056
|
],
|
|
13592
14057
|
size: [
|
|
13593
|
-
|
|
13594
|
-
|
|
13595
|
-
|
|
14058
|
+
0,
|
|
14059
|
+
0,
|
|
14060
|
+
0
|
|
13596
14061
|
],
|
|
13597
|
-
boundingSphereRadius:
|
|
14062
|
+
boundingSphereRadius: 0
|
|
14063
|
+
}
|
|
14064
|
+
};
|
|
14065
|
+
const rest = poseNodes(model, void 0, 0);
|
|
14066
|
+
const lo = [
|
|
14067
|
+
Infinity,
|
|
14068
|
+
Infinity,
|
|
14069
|
+
Infinity
|
|
14070
|
+
];
|
|
14071
|
+
const hi = [
|
|
14072
|
+
-Infinity,
|
|
14073
|
+
-Infinity,
|
|
14074
|
+
-Infinity
|
|
14075
|
+
];
|
|
14076
|
+
for (const mesh of meshes) {
|
|
14077
|
+
const place = mesh.node !== void 0 ? rest[mesh.node] : void 0;
|
|
14078
|
+
for (let i = 0; i < mesh.positions.length; i += 3) {
|
|
14079
|
+
const p = [
|
|
14080
|
+
mesh.positions[i],
|
|
14081
|
+
mesh.positions[i + 1],
|
|
14082
|
+
mesh.positions[i + 2]
|
|
14083
|
+
];
|
|
14084
|
+
const q = place ? Matrix4Math.projectPoint(place, p) : p;
|
|
14085
|
+
for (let a = 0; a < 3; a++) {
|
|
14086
|
+
if (q[a] < lo[a]) lo[a] = q[a];
|
|
14087
|
+
if (q[a] > hi[a]) hi[a] = q[a];
|
|
14088
|
+
}
|
|
13598
14089
|
}
|
|
14090
|
+
}
|
|
14091
|
+
if (!Number.isFinite(lo[0])) {
|
|
14092
|
+
lo.fill(-1);
|
|
14093
|
+
hi.fill(1);
|
|
14094
|
+
}
|
|
14095
|
+
const { offset, scale } = resolveModelTransform({
|
|
14096
|
+
min: lo,
|
|
14097
|
+
max: hi,
|
|
14098
|
+
center: [
|
|
14099
|
+
(lo[0] + hi[0]) * .5,
|
|
14100
|
+
(lo[1] + hi[1]) * .5,
|
|
14101
|
+
(lo[2] + hi[2]) * .5
|
|
14102
|
+
],
|
|
14103
|
+
size: [
|
|
14104
|
+
hi[0] - lo[0],
|
|
14105
|
+
hi[1] - lo[1],
|
|
14106
|
+
hi[2] - lo[2]
|
|
14107
|
+
]
|
|
14108
|
+
}, options);
|
|
14109
|
+
model.rootTransform = Matrix4Math.multiply(Matrix4Math.scale(scale[0], scale[1], scale[2]), Matrix4Math.translate(-offset[0], -offset[1], -offset[2]));
|
|
14110
|
+
const min = [
|
|
14111
|
+
0,
|
|
14112
|
+
1,
|
|
14113
|
+
2
|
|
14114
|
+
].map((a) => (lo[a] - offset[a]) * scale[a]);
|
|
14115
|
+
const max = [
|
|
14116
|
+
0,
|
|
14117
|
+
1,
|
|
14118
|
+
2
|
|
14119
|
+
].map((a) => (hi[a] - offset[a]) * scale[a]);
|
|
14120
|
+
model.bounds = {
|
|
14121
|
+
min,
|
|
14122
|
+
max,
|
|
14123
|
+
center: [
|
|
14124
|
+
(min[0] + max[0]) * .5,
|
|
14125
|
+
(min[1] + max[1]) * .5,
|
|
14126
|
+
(min[2] + max[2]) * .5
|
|
14127
|
+
],
|
|
14128
|
+
size: [
|
|
14129
|
+
max[0] - min[0],
|
|
14130
|
+
max[1] - min[1],
|
|
14131
|
+
max[2] - min[2]
|
|
14132
|
+
],
|
|
14133
|
+
boundingSphereRadius: Math.hypot(max[0] - min[0], max[1] - min[1], max[2] - min[2]) * .5
|
|
13599
14134
|
};
|
|
14135
|
+
return model;
|
|
13600
14136
|
}
|
|
13601
14137
|
};
|
|
14138
|
+
/** A Properties70 vector (Lcl Translation / Rotation / Scaling), `fallback` where absent. */
|
|
14139
|
+
function readVec3(node, name, fallback) {
|
|
14140
|
+
const v = readProperty70(node, name);
|
|
14141
|
+
return [
|
|
14142
|
+
0,
|
|
14143
|
+
1,
|
|
14144
|
+
2
|
|
14145
|
+
].map((a) => {
|
|
14146
|
+
const x = v?.[a];
|
|
14147
|
+
return x !== void 0 && Number.isFinite(x) ? x : fallback;
|
|
14148
|
+
});
|
|
14149
|
+
}
|
|
14150
|
+
function multiplyQuat(a, b) {
|
|
14151
|
+
return [
|
|
14152
|
+
a[3] * b[0] + a[0] * b[3] + a[1] * b[2] - a[2] * b[1],
|
|
14153
|
+
a[3] * b[1] - a[0] * b[2] + a[1] * b[3] + a[2] * b[0],
|
|
14154
|
+
a[3] * b[2] + a[0] * b[1] - a[1] * b[0] + a[2] * b[3],
|
|
14155
|
+
a[3] * b[3] - a[0] * b[0] - a[1] * b[1] - a[2] * b[2]
|
|
14156
|
+
];
|
|
14157
|
+
}
|
|
14158
|
+
/**
|
|
14159
|
+
* A Model's full local rotation for an Lcl Rotation `q`:
|
|
14160
|
+
* PreRotation · q · PostRotation⁻¹ (FBX always applies pre/post in XYZ order).
|
|
14161
|
+
*/
|
|
14162
|
+
function modelRotation(model, q) {
|
|
14163
|
+
const pre = readProperty70(model, "PreRotation");
|
|
14164
|
+
const post = readProperty70(model, "PostRotation");
|
|
14165
|
+
let out = q;
|
|
14166
|
+
if (pre) out = multiplyQuat(fbxEulerToQuat(readVec3(model, "PreRotation", 0)), out);
|
|
14167
|
+
if (post) {
|
|
14168
|
+
const p = fbxEulerToQuat(readVec3(model, "PostRotation", 0));
|
|
14169
|
+
out = multiplyQuat(out, [
|
|
14170
|
+
-p[0],
|
|
14171
|
+
-p[1],
|
|
14172
|
+
-p[2],
|
|
14173
|
+
p[3]
|
|
14174
|
+
]);
|
|
14175
|
+
}
|
|
14176
|
+
return out;
|
|
14177
|
+
}
|
|
14178
|
+
/** A 4×4 matrix child (`Transform: *16 { a: … }`), identity when absent. */
|
|
14179
|
+
function matrixChild(node, name) {
|
|
14180
|
+
const child = node.children.find((c) => c.name === name);
|
|
14181
|
+
const raw = child?.children.find((c) => c.name === "a")?.props ?? child?.props;
|
|
14182
|
+
const values = raw?.[0] instanceof Float64Array || raw?.[0] instanceof Float32Array ? Array.from(raw[0]) : (raw ?? []).map(Number);
|
|
14183
|
+
return values.length === 16 ? values : Matrix4Math.identity();
|
|
14184
|
+
}
|
|
14185
|
+
/**
|
|
14186
|
+
* A geometry layer (normals, UVs) as a lookup by corner: its mapping says
|
|
14187
|
+
* whether values are per control point, per polygon vertex, per polygon or
|
|
14188
|
+
* one for all; IndexToDirect layers go through their index array.
|
|
14189
|
+
*/
|
|
14190
|
+
function layerElement(layer, data, index, size) {
|
|
14191
|
+
if (data.length === 0) return void 0;
|
|
14192
|
+
const text = (name) => String(layer.children.find((c) => c.name === name)?.props[0] ?? "");
|
|
14193
|
+
const mapping = text("MappingInformationType");
|
|
14194
|
+
const indexed = /^Index/.test(text("ReferenceInformationType")) && index.length > 0;
|
|
14195
|
+
return (cp, pv, poly) => {
|
|
14196
|
+
let i = mapping === "ByPolygonVertex" ? pv : mapping === "ByPolygon" ? poly : mapping === "AllSame" ? 0 : cp;
|
|
14197
|
+
if (indexed) i = Number(index[i] ?? i);
|
|
14198
|
+
return Array.from({ length: size }, (_, c) => Number(data[i * size + c] ?? 0));
|
|
14199
|
+
};
|
|
14200
|
+
}
|
|
13602
14201
|
/**
|
|
13603
14202
|
* Classifies a curve node from its OP connection property ("Lcl Translation",
|
|
13604
14203
|
* "Lcl Rotation", "Lcl Scaling") or, failing that, its short name ("T", "R", "S").
|
|
@@ -13728,193 +14327,46 @@ function buildTransformTrack(group) {
|
|
|
13728
14327
|
return channel ? sampleCurve(channel, key) : group.defaults[axis];
|
|
13729
14328
|
});
|
|
13730
14329
|
if (!isRotation) {
|
|
13731
|
-
values.set(v, k * 3);
|
|
13732
|
-
return;
|
|
13733
|
-
}
|
|
13734
|
-
const q = fbxEulerToQuat(v, order);
|
|
13735
|
-
if (prev && prev[0] * q[0] + prev[1] * q[1] + prev[2] * q[2] + prev[3] * q[3] < 0) for (let i = 0; i < 4; i++) q[i] = -q[i];
|
|
13736
|
-
prev = q;
|
|
13737
|
-
values.set(q, k * 4);
|
|
13738
|
-
});
|
|
13739
|
-
return {
|
|
13740
|
-
nodeName: group.nodeName,
|
|
13741
|
-
times,
|
|
13742
|
-
translations: group.kind === "T" ? values : void 0,
|
|
13743
|
-
rotations: isRotation ? values : void 0,
|
|
13744
|
-
scales: group.kind === "S" ? values : void 0
|
|
13745
|
-
};
|
|
13746
|
-
}
|
|
13747
|
-
function parseFBX(bufferOrText, options = {}) {
|
|
13748
|
-
return FbxLoader.parse(bufferOrText, options);
|
|
13749
|
-
}
|
|
13750
|
-
function loadFBX(srcOrData, options = {}) {
|
|
13751
|
-
let data = srcOrData;
|
|
13752
|
-
if (typeof srcOrData === "string") {
|
|
13753
|
-
const trimmed = srcOrData.trim();
|
|
13754
|
-
if (!(trimmed.includes("FBXHeaderExtension") || trimmed.includes("Kaydara FBX")) && typeof fs !== "undefined" && fs.existsSync) try {
|
|
13755
|
-
let filePath = srcOrData.startsWith("file://") ? srcOrData.slice(7) : srcOrData;
|
|
13756
|
-
try {
|
|
13757
|
-
filePath = decodeURIComponent(filePath);
|
|
13758
|
-
} catch (_) {}
|
|
13759
|
-
if (fs.existsSync(filePath)) {
|
|
13760
|
-
const buf = fs.readFileSync(filePath);
|
|
13761
|
-
data = new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
13762
|
-
}
|
|
13763
|
-
} catch (_) {}
|
|
13764
|
-
}
|
|
13765
|
-
return FbxLoader.parse(data, options);
|
|
13766
|
-
}
|
|
13767
|
-
/**
|
|
13768
|
-
* Adds each triangle's (area-weighted) face normal to its three vertices, then
|
|
13769
|
-
* normalizes every vertex normal in place.
|
|
13770
|
-
*/
|
|
13771
|
-
function accumulateVertexNormals(positions, indices, normals) {
|
|
13772
|
-
const vertex = (i) => [
|
|
13773
|
-
positions[i * 3],
|
|
13774
|
-
positions[i * 3 + 1],
|
|
13775
|
-
positions[i * 3 + 2]
|
|
13776
|
-
];
|
|
13777
|
-
for (let i = 0; i < indices.length; i += 3) {
|
|
13778
|
-
const i0 = indices[i];
|
|
13779
|
-
const i1 = indices[i + 1];
|
|
13780
|
-
const i2 = indices[i + 2];
|
|
13781
|
-
const p0 = vertex(i0);
|
|
13782
|
-
const fn = Vector3Math.cross(Vector3Math.subtract(vertex(i1), p0), Vector3Math.subtract(vertex(i2), p0));
|
|
13783
|
-
for (const v of [
|
|
13784
|
-
i0,
|
|
13785
|
-
i1,
|
|
13786
|
-
i2
|
|
13787
|
-
]) {
|
|
13788
|
-
normals[v * 3] += fn[0];
|
|
13789
|
-
normals[v * 3 + 1] += fn[1];
|
|
13790
|
-
normals[v * 3 + 2] += fn[2];
|
|
13791
|
-
}
|
|
13792
|
-
}
|
|
13793
|
-
for (let i = 0; i < normals.length; i += 3) {
|
|
13794
|
-
const nx = normals[i];
|
|
13795
|
-
const ny = normals[i + 1];
|
|
13796
|
-
const nz = normals[i + 2];
|
|
13797
|
-
const len = Math.hypot(nx, ny, nz) || 1;
|
|
13798
|
-
normals[i] = nx / len;
|
|
13799
|
-
normals[i + 1] = ny / len;
|
|
13800
|
-
normals[i + 2] = nz / len;
|
|
13801
|
-
}
|
|
13802
|
-
}
|
|
13803
|
-
/** Axis-aligned bounds of xyz position arrays (all zero when empty). */
|
|
13804
|
-
function computeBounds(...positionArrays) {
|
|
13805
|
-
let minX = Infinity, minY = Infinity, minZ = Infinity;
|
|
13806
|
-
let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;
|
|
13807
|
-
for (const positions of positionArrays) for (let i = 0; i < positions.length; i += 3) {
|
|
13808
|
-
const x = positions[i];
|
|
13809
|
-
const y = positions[i + 1];
|
|
13810
|
-
const z = positions[i + 2];
|
|
13811
|
-
if (x < minX) minX = x;
|
|
13812
|
-
if (x > maxX) maxX = x;
|
|
13813
|
-
if (y < minY) minY = y;
|
|
13814
|
-
if (y > maxY) maxY = y;
|
|
13815
|
-
if (z < minZ) minZ = z;
|
|
13816
|
-
if (z > maxZ) maxZ = z;
|
|
13817
|
-
}
|
|
13818
|
-
if (!Number.isFinite(minX)) {
|
|
13819
|
-
minX = minY = minZ = 0;
|
|
13820
|
-
maxX = maxY = maxZ = 0;
|
|
13821
|
-
}
|
|
13822
|
-
return {
|
|
13823
|
-
min: [
|
|
13824
|
-
minX,
|
|
13825
|
-
minY,
|
|
13826
|
-
minZ
|
|
13827
|
-
],
|
|
13828
|
-
max: [
|
|
13829
|
-
maxX,
|
|
13830
|
-
maxY,
|
|
13831
|
-
maxZ
|
|
13832
|
-
],
|
|
13833
|
-
center: [
|
|
13834
|
-
(minX + maxX) * .5,
|
|
13835
|
-
(minY + maxY) * .5,
|
|
13836
|
-
(minZ + maxZ) * .5
|
|
13837
|
-
],
|
|
13838
|
-
size: [
|
|
13839
|
-
maxX - minX,
|
|
13840
|
-
maxY - minY,
|
|
13841
|
-
maxZ - minZ
|
|
13842
|
-
]
|
|
13843
|
-
};
|
|
13844
|
-
}
|
|
13845
|
-
/**
|
|
13846
|
-
* The placement `LoadModelOptions` asks for: recentring on the bounds
|
|
13847
|
-
* (`center`), fitting the largest side to `normalizeSize`, then `scale`.
|
|
13848
|
-
*/
|
|
13849
|
-
function resolveModelTransform(bounds, options) {
|
|
13850
|
-
const maxDimension = Math.max(...bounds.size, 1e-4);
|
|
13851
|
-
let scaleMultiplier = 1;
|
|
13852
|
-
if (options.normalizeSize && options.normalizeSize > 0) scaleMultiplier = options.normalizeSize / maxDimension;
|
|
13853
|
-
const scale = [
|
|
13854
|
-
scaleMultiplier,
|
|
13855
|
-
scaleMultiplier,
|
|
13856
|
-
scaleMultiplier
|
|
13857
|
-
];
|
|
13858
|
-
if (typeof options.scale === "number") {
|
|
13859
|
-
scale[0] *= options.scale;
|
|
13860
|
-
scale[1] *= options.scale;
|
|
13861
|
-
scale[2] *= options.scale;
|
|
13862
|
-
} else if (Array.isArray(options.scale)) {
|
|
13863
|
-
scale[0] *= options.scale[0];
|
|
13864
|
-
scale[1] *= options.scale[1];
|
|
13865
|
-
scale[2] *= options.scale[2];
|
|
13866
|
-
}
|
|
13867
|
-
return {
|
|
13868
|
-
offset: options.center ? bounds.center : [
|
|
13869
|
-
0,
|
|
13870
|
-
0,
|
|
13871
|
-
0
|
|
13872
|
-
],
|
|
13873
|
-
scale
|
|
13874
|
-
};
|
|
13875
|
-
}
|
|
13876
|
-
/** `(p - offset) * scale` for every xyz position. */
|
|
13877
|
-
function transformPositions(positions, { offset, scale }) {
|
|
13878
|
-
const out = new Float32Array(positions.length);
|
|
13879
|
-
for (let i = 0; i < positions.length; i += 3) {
|
|
13880
|
-
out[i] = (positions[i] - offset[0]) * scale[0];
|
|
13881
|
-
out[i + 1] = (positions[i + 1] - offset[1]) * scale[1];
|
|
13882
|
-
out[i + 2] = (positions[i + 2] - offset[2]) * scale[2];
|
|
13883
|
-
}
|
|
13884
|
-
return out;
|
|
13885
|
-
}
|
|
13886
|
-
/** Uint16 indices while every vertex fits, Uint32 beyond 65535 vertices. */
|
|
13887
|
-
function createIndexArray(indices, vertexCount) {
|
|
13888
|
-
return vertexCount > 65535 ? new Uint32Array(indices) : new Uint16Array(indices);
|
|
13889
|
-
}
|
|
13890
|
-
/** The model's bounds after `transform`, as `Model3DData.bounds` reports them. */
|
|
13891
|
-
function transformModelBounds(bounds, { offset, scale }) {
|
|
13892
|
-
const min = [
|
|
13893
|
-
(bounds.min[0] - offset[0]) * scale[0],
|
|
13894
|
-
(bounds.min[1] - offset[1]) * scale[1],
|
|
13895
|
-
(bounds.min[2] - offset[2]) * scale[2]
|
|
13896
|
-
];
|
|
13897
|
-
const max = [
|
|
13898
|
-
(bounds.max[0] - offset[0]) * scale[0],
|
|
13899
|
-
(bounds.max[1] - offset[1]) * scale[1],
|
|
13900
|
-
(bounds.max[2] - offset[2]) * scale[2]
|
|
13901
|
-
];
|
|
14330
|
+
values.set(v, k * 3);
|
|
14331
|
+
return;
|
|
14332
|
+
}
|
|
14333
|
+
const q = fbxEulerToQuat(v, order);
|
|
14334
|
+
if (prev && prev[0] * q[0] + prev[1] * q[1] + prev[2] * q[2] + prev[3] * q[3] < 0) for (let i = 0; i < 4; i++) q[i] = -q[i];
|
|
14335
|
+
prev = q;
|
|
14336
|
+
values.set(q, k * 4);
|
|
14337
|
+
});
|
|
13902
14338
|
return {
|
|
13903
|
-
|
|
13904
|
-
|
|
13905
|
-
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
(min[2] + max[2]) * .5
|
|
13909
|
-
],
|
|
13910
|
-
size: [
|
|
13911
|
-
max[0] - min[0],
|
|
13912
|
-
max[1] - min[1],
|
|
13913
|
-
max[2] - min[2]
|
|
13914
|
-
],
|
|
13915
|
-
boundingSphereRadius: Math.hypot(max[0] - min[0], max[1] - min[1], max[2] - min[2]) * .5
|
|
14339
|
+
nodeName: group.nodeName,
|
|
14340
|
+
times,
|
|
14341
|
+
translations: group.kind === "T" ? values : void 0,
|
|
14342
|
+
rotations: isRotation ? values : void 0,
|
|
14343
|
+
scales: group.kind === "S" ? values : void 0
|
|
13916
14344
|
};
|
|
13917
14345
|
}
|
|
14346
|
+
function parseFBX(bufferOrText, options = {}) {
|
|
14347
|
+
return FbxLoader.parse(bufferOrText, options);
|
|
14348
|
+
}
|
|
14349
|
+
function loadFBX(srcOrData, options = {}) {
|
|
14350
|
+
let data = srcOrData;
|
|
14351
|
+
if (typeof srcOrData === "string") {
|
|
14352
|
+
const trimmed = srcOrData.trim();
|
|
14353
|
+
if (!(trimmed.includes("FBXHeaderExtension") || trimmed.includes("Kaydara FBX")) && typeof fs !== "undefined" && fs.existsSync) try {
|
|
14354
|
+
let filePath = srcOrData.startsWith("file://") ? srcOrData.slice(7) : srcOrData;
|
|
14355
|
+
try {
|
|
14356
|
+
filePath = decodeURIComponent(filePath);
|
|
14357
|
+
} catch (_) {}
|
|
14358
|
+
if (fs.existsSync(filePath)) {
|
|
14359
|
+
const buf = fs.readFileSync(filePath);
|
|
14360
|
+
data = new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
14361
|
+
options = {
|
|
14362
|
+
basePath: path.dirname(filePath),
|
|
14363
|
+
...options
|
|
14364
|
+
};
|
|
14365
|
+
}
|
|
14366
|
+
} catch (_) {}
|
|
14367
|
+
}
|
|
14368
|
+
return FbxLoader.parse(data, options);
|
|
14369
|
+
}
|
|
13918
14370
|
var StlLoader = class StlLoader$1 {
|
|
13919
14371
|
/**
|
|
13920
14372
|
* Checks if buffer is Binary STL or ASCII STL.
|
|
@@ -14384,7 +14836,12 @@ var PlyLoader = class PlyLoader$1 {
|
|
|
14384
14836
|
const indexArray = createIndexArray(rawIndices, positions.length / 3);
|
|
14385
14837
|
const defaultMaterial = {
|
|
14386
14838
|
name: "ply_default",
|
|
14387
|
-
diffuseColor: [
|
|
14839
|
+
diffuseColor: rawColors ? [
|
|
14840
|
+
1,
|
|
14841
|
+
1,
|
|
14842
|
+
1,
|
|
14843
|
+
1
|
|
14844
|
+
] : [
|
|
14388
14845
|
.8,
|
|
14389
14846
|
.8,
|
|
14390
14847
|
.85,
|
|
@@ -14427,164 +14884,6 @@ var PlyLoader = class PlyLoader$1 {
|
|
|
14427
14884
|
function loadPLY(srcOrData, options = {}) {
|
|
14428
14885
|
return PlyLoader.load(srcOrData, options);
|
|
14429
14886
|
}
|
|
14430
|
-
/**
|
|
14431
|
-
* Poses a model's scene graph (glTF semantics): samples an animation clip's
|
|
14432
|
-
* translation / rotation / scale tracks at a time, composes the node
|
|
14433
|
-
* hierarchy into model-space matrices, and turns a skin's joints into the
|
|
14434
|
-
* joint matrices the mesh shader blends (joint world × inverse bind).
|
|
14435
|
-
*/
|
|
14436
|
-
/** Joints per skin the mesh shader holds (mesh3d.wgsl jointMatrices). */
|
|
14437
|
-
const MAX_JOINTS = 128;
|
|
14438
|
-
/** Column-major translate · rotate(quaternion) · scale. */
|
|
14439
|
-
function trsMatrix(t, q, s) {
|
|
14440
|
-
const [x, y, z, w] = q;
|
|
14441
|
-
const xx = x * x;
|
|
14442
|
-
const yy = y * y;
|
|
14443
|
-
const zz = z * z;
|
|
14444
|
-
const xy = x * y;
|
|
14445
|
-
const xz = x * z;
|
|
14446
|
-
const yz = y * z;
|
|
14447
|
-
const wx = w * x;
|
|
14448
|
-
const wy = w * y;
|
|
14449
|
-
const wz = w * z;
|
|
14450
|
-
return [
|
|
14451
|
-
(1 - 2 * (yy + zz)) * s[0],
|
|
14452
|
-
2 * (xy + wz) * s[0],
|
|
14453
|
-
2 * (xz - wy) * s[0],
|
|
14454
|
-
0,
|
|
14455
|
-
2 * (xy - wz) * s[1],
|
|
14456
|
-
(1 - 2 * (xx + zz)) * s[1],
|
|
14457
|
-
2 * (yz + wx) * s[1],
|
|
14458
|
-
0,
|
|
14459
|
-
2 * (xz + wy) * s[2],
|
|
14460
|
-
2 * (yz - wx) * s[2],
|
|
14461
|
-
(1 - 2 * (xx + yy)) * s[2],
|
|
14462
|
-
0,
|
|
14463
|
-
t[0],
|
|
14464
|
-
t[1],
|
|
14465
|
-
t[2],
|
|
14466
|
-
1
|
|
14467
|
-
];
|
|
14468
|
-
}
|
|
14469
|
-
function normalizeQuat(q) {
|
|
14470
|
-
const len = Math.hypot(q[0], q[1], q[2], q[3]) || 1;
|
|
14471
|
-
return [
|
|
14472
|
-
q[0] / len,
|
|
14473
|
-
q[1] / len,
|
|
14474
|
-
q[2] / len,
|
|
14475
|
-
q[3] / len
|
|
14476
|
-
];
|
|
14477
|
-
}
|
|
14478
|
-
function slerp(a, b, t) {
|
|
14479
|
-
let cos = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
|
|
14480
|
-
const sign = cos < 0 ? -1 : 1;
|
|
14481
|
-
cos *= sign;
|
|
14482
|
-
if (cos > .9995) return normalizeQuat([
|
|
14483
|
-
a[0] + (sign * b[0] - a[0]) * t,
|
|
14484
|
-
a[1] + (sign * b[1] - a[1]) * t,
|
|
14485
|
-
a[2] + (sign * b[2] - a[2]) * t,
|
|
14486
|
-
a[3] + (sign * b[3] - a[3]) * t
|
|
14487
|
-
]);
|
|
14488
|
-
const theta = Math.acos(cos);
|
|
14489
|
-
const sin = Math.sin(theta);
|
|
14490
|
-
const wa = Math.sin((1 - t) * theta) / sin;
|
|
14491
|
-
const wb = sign * Math.sin(t * theta) / sin;
|
|
14492
|
-
return [
|
|
14493
|
-
a[0] * wa + b[0] * wb,
|
|
14494
|
-
a[1] * wa + b[1] * wb,
|
|
14495
|
-
a[2] * wa + b[2] * wb,
|
|
14496
|
-
a[3] * wa + b[3] * wb
|
|
14497
|
-
];
|
|
14498
|
-
}
|
|
14499
|
-
/** Index of the last keyframe at or before `time` (binary search). */
|
|
14500
|
-
function keyBefore(times, time$2) {
|
|
14501
|
-
let lo = 0;
|
|
14502
|
-
let hi = times.length - 1;
|
|
14503
|
-
while (lo < hi) {
|
|
14504
|
-
const mid = lo + hi + 1 >> 1;
|
|
14505
|
-
if ((times[mid] ?? 0) <= time$2) lo = mid;
|
|
14506
|
-
else hi = mid - 1;
|
|
14507
|
-
}
|
|
14508
|
-
return lo;
|
|
14509
|
-
}
|
|
14510
|
-
/** Element `k` (of `size` components) of a track's values; cubic tracks store [in, value, out] triples. */
|
|
14511
|
-
function valueAt(values, k, size, cubic, part = 1) {
|
|
14512
|
-
const at = cubic ? (k * 3 + part) * size : k * size;
|
|
14513
|
-
return Array.from(values.subarray(at, at + size));
|
|
14514
|
-
}
|
|
14515
|
-
function sampleChannel(track, values, size, time$2) {
|
|
14516
|
-
const { times } = track;
|
|
14517
|
-
const cubic = track.interpolation === "cubic";
|
|
14518
|
-
const last = times.length - 1;
|
|
14519
|
-
if (time$2 <= (times[0] ?? 0)) return valueAt(values, 0, size, cubic);
|
|
14520
|
-
if (time$2 >= (times[last] ?? 0)) return valueAt(values, last, size, cubic);
|
|
14521
|
-
const k = keyBefore(times, time$2);
|
|
14522
|
-
if (track.interpolation === "step") return valueAt(values, k, size, cubic);
|
|
14523
|
-
const t0 = times[k] ?? 0;
|
|
14524
|
-
const dt = (times[k + 1] ?? t0) - t0;
|
|
14525
|
-
const u = dt > 0 ? (time$2 - t0) / dt : 0;
|
|
14526
|
-
const a = valueAt(values, k, size, cubic);
|
|
14527
|
-
const b = valueAt(values, k + 1, size, cubic);
|
|
14528
|
-
if (cubic) {
|
|
14529
|
-
const outA = valueAt(values, k, size, true, 2);
|
|
14530
|
-
const inB = valueAt(values, k + 1, size, true, 0);
|
|
14531
|
-
const u2 = u * u;
|
|
14532
|
-
const u3 = u2 * u;
|
|
14533
|
-
const out = a.map((p0, i) => (2 * u3 - 3 * u2 + 1) * p0 + (u3 - 2 * u2 + u) * dt * (outA[i] ?? 0) + (-2 * u3 + 3 * u2) * (b[i] ?? 0) + (u3 - u2) * dt * (inB[i] ?? 0));
|
|
14534
|
-
return size === 4 ? normalizeQuat(out) : out;
|
|
14535
|
-
}
|
|
14536
|
-
if (size === 4) return slerp(a, b, u);
|
|
14537
|
-
return a.map((v, i) => v + ((b[i] ?? v) - v) * u);
|
|
14538
|
-
}
|
|
14539
|
-
/** Each node's local matrix with the clip's tracks applied at `time` (seconds). */
|
|
14540
|
-
function localMatrices(nodes, clip, time$2) {
|
|
14541
|
-
const t = nodes.map((n) => [...n.translation]);
|
|
14542
|
-
const r = nodes.map((n) => [...n.rotation]);
|
|
14543
|
-
const s = nodes.map((n) => [...n.scale]);
|
|
14544
|
-
const byName = new Map(nodes.map((n, i) => [n.name, i]));
|
|
14545
|
-
for (const track of clip?.tracks ?? []) {
|
|
14546
|
-
const i = track.node ?? byName.get(track.nodeName);
|
|
14547
|
-
if (i === void 0 || !track.times.length) continue;
|
|
14548
|
-
if (track.translations) t[i] = sampleChannel(track, track.translations, 3, time$2);
|
|
14549
|
-
if (track.rotations) r[i] = sampleChannel(track, track.rotations, 4, time$2);
|
|
14550
|
-
if (track.scales) s[i] = sampleChannel(track, track.scales, 3, time$2);
|
|
14551
|
-
}
|
|
14552
|
-
return nodes.map((n, i) => n.matrix ?? trsMatrix(t[i], r[i], s[i]));
|
|
14553
|
-
}
|
|
14554
|
-
/**
|
|
14555
|
-
* Model-space matrix of every node, posed by `clip` at `time` seconds (the
|
|
14556
|
-
* rest pose without a clip). Parents may follow their children in the list.
|
|
14557
|
-
*/
|
|
14558
|
-
function poseNodes(model, clip, time$2) {
|
|
14559
|
-
const nodes = model.nodes ?? [];
|
|
14560
|
-
const local = localMatrices(nodes, clip, time$2);
|
|
14561
|
-
const world = new Array(nodes.length);
|
|
14562
|
-
const resolve$1$1 = (i) => {
|
|
14563
|
-
const done = world[i];
|
|
14564
|
-
if (done) return done;
|
|
14565
|
-
const parent = nodes[i].parent;
|
|
14566
|
-
const m = parent < 0 ? local[i] : Matrix4Math.multiply(resolve$1$1(parent), local[i]);
|
|
14567
|
-
world[i] = m;
|
|
14568
|
-
return m;
|
|
14569
|
-
};
|
|
14570
|
-
return nodes.map((_, i) => resolve$1$1(i));
|
|
14571
|
-
}
|
|
14572
|
-
/** The joint matrices of one skin for a posed scene graph, padded with identity to MAX_JOINTS. */
|
|
14573
|
-
function jointMatrices(model, skinIndex, world) {
|
|
14574
|
-
const skin = model.skins?.[skinIndex];
|
|
14575
|
-
if (!skin) throw new Error(`model has no skin ${skinIndex}`);
|
|
14576
|
-
const out = new Float32Array(MAX_JOINTS * 16);
|
|
14577
|
-
for (let j = 0; j < MAX_JOINTS; j++) {
|
|
14578
|
-
const node = skin.joints[j];
|
|
14579
|
-
if (node === void 0) {
|
|
14580
|
-
out.set(Matrix4Math.identity(), j * 16);
|
|
14581
|
-
continue;
|
|
14582
|
-
}
|
|
14583
|
-
const ibm = Array.from(skin.inverseBindMatrices.subarray(j * 16, j * 16 + 16));
|
|
14584
|
-
out.set(Matrix4Math.multiply(world[node], ibm), j * 16);
|
|
14585
|
-
}
|
|
14586
|
-
return out;
|
|
14587
|
-
}
|
|
14588
14887
|
const COMPONENTS = {
|
|
14589
14888
|
SCALAR: 1,
|
|
14590
14889
|
VEC2: 2,
|
|
@@ -14613,6 +14912,11 @@ function componentReader(componentType, normalized = false) {
|
|
|
14613
14912
|
default: return (dv, at) => dv.getFloat32(at, true);
|
|
14614
14913
|
}
|
|
14615
14914
|
}
|
|
14915
|
+
/** Mesh compression the loader cannot decode: a file that requires it fails with a clear error. */
|
|
14916
|
+
const UNSUPPORTED_REQUIRED_EXTENSIONS = {
|
|
14917
|
+
KHR_draco_mesh_compression: "Draco mesh compression",
|
|
14918
|
+
EXT_meshopt_compression: "meshopt compression"
|
|
14919
|
+
};
|
|
14616
14920
|
const GLB_MAGIC = 1179937895;
|
|
14617
14921
|
const CHUNK_TYPE_JSON = 1313821514;
|
|
14618
14922
|
const CHUNK_TYPE_BIN = 5130562;
|
|
@@ -14667,6 +14971,10 @@ var GltfLoader = class GltfLoader$1 {
|
|
|
14667
14971
|
}
|
|
14668
14972
|
}
|
|
14669
14973
|
}
|
|
14974
|
+
for (const ext of doc.extensionsRequired ?? []) {
|
|
14975
|
+
const what = UNSUPPORTED_REQUIRED_EXTENSIONS[ext];
|
|
14976
|
+
if (what) throw new Error(`glTF file requires ${ext} (${what}), which framefields cannot decode. Re-export the model without mesh compression (in Blender's glTF exporter, turn off Compression).`);
|
|
14977
|
+
}
|
|
14670
14978
|
return GltfLoader$1.buildModel(doc, binaryBuffers, options, basePath);
|
|
14671
14979
|
}
|
|
14672
14980
|
static unpackGlb(bytes) {
|
|
@@ -14754,11 +15062,59 @@ var GltfLoader = class GltfLoader$1 {
|
|
|
14754
15062
|
}
|
|
14755
15063
|
if (!basePath) return void 0;
|
|
14756
15064
|
const file = path.isAbsolute(image.uri) ? image.uri : path.join(basePath, decodeURIComponent(image.uri));
|
|
14757
|
-
if (!fs.existsSync(file))
|
|
14758
|
-
|
|
15065
|
+
if (!fs.existsSync(file)) {
|
|
15066
|
+
GltfLoader$1.warn(`Image "${image.uri}" was not found next to the model; textures using it are skipped.`);
|
|
15067
|
+
return;
|
|
15068
|
+
}
|
|
14759
15069
|
return {
|
|
14760
15070
|
bytes: new Uint8Array(fs.readFileSync(file)),
|
|
14761
|
-
mime: image.mimeType ?? (
|
|
15071
|
+
mime: image.mimeType ?? textureMime(file)
|
|
15072
|
+
};
|
|
15073
|
+
}
|
|
15074
|
+
static warn(message) {
|
|
15075
|
+
console.warn(`[GltfLoader] ${message}`);
|
|
15076
|
+
}
|
|
15077
|
+
/** The UV set of a texture reference (KHR_texture_transform may override it). */
|
|
15078
|
+
static texCoordOf(info) {
|
|
15079
|
+
return info.extensions?.KHR_texture_transform?.texCoord ?? info.texCoord ?? 0;
|
|
15080
|
+
}
|
|
15081
|
+
/** The UV set and transform of the material's base color map (else its first map). */
|
|
15082
|
+
static uvPlan(mat) {
|
|
15083
|
+
const first = [
|
|
15084
|
+
mat?.pbrMetallicRoughness?.baseColorTexture,
|
|
15085
|
+
mat?.normalTexture,
|
|
15086
|
+
mat?.pbrMetallicRoughness?.metallicRoughnessTexture,
|
|
15087
|
+
mat?.occlusionTexture,
|
|
15088
|
+
mat?.emissiveTexture
|
|
15089
|
+
].find((t) => t !== void 0);
|
|
15090
|
+
return first ? {
|
|
15091
|
+
texCoord: GltfLoader$1.texCoordOf(first),
|
|
15092
|
+
transform: first.extensions?.KHR_texture_transform
|
|
15093
|
+
} : { texCoord: 0 };
|
|
15094
|
+
}
|
|
15095
|
+
/**
|
|
15096
|
+
* A texture's decodable image: EXT_texture_webp's source when present.
|
|
15097
|
+
* KTX2 / Basis (KHR_texture_basisu) and other formats the renderer
|
|
15098
|
+
* cannot decode are skipped with a warning.
|
|
15099
|
+
*/
|
|
15100
|
+
static textureImage(doc, binaryBuffers, textureIndex, basePath, label) {
|
|
15101
|
+
const texture = doc.textures?.[textureIndex];
|
|
15102
|
+
if (!texture) return void 0;
|
|
15103
|
+
const source = texture.extensions?.EXT_texture_webp?.source ?? texture.source;
|
|
15104
|
+
if (source === void 0) {
|
|
15105
|
+
if (texture.extensions?.KHR_texture_basisu) GltfLoader$1.warn(`${label} is a KTX2 / Basis texture, which framefields cannot decode; it is skipped (use PNG, JPEG or WebP).`);
|
|
15106
|
+
return;
|
|
15107
|
+
}
|
|
15108
|
+
const image = GltfLoader$1.imageBytes(doc, binaryBuffers, source, basePath);
|
|
15109
|
+
if (!image) return void 0;
|
|
15110
|
+
if (!SUPPORTED_IMAGE_MIMES.has(image.mime)) {
|
|
15111
|
+
GltfLoader$1.warn(`${label} is ${image.mime}, which framefields cannot decode; it is skipped (use PNG, JPEG or WebP).`);
|
|
15112
|
+
return;
|
|
15113
|
+
}
|
|
15114
|
+
const sampler = texture.sampler !== void 0 ? doc.samplers?.[texture.sampler] : void 0;
|
|
15115
|
+
return {
|
|
15116
|
+
...image,
|
|
15117
|
+
sampler
|
|
14762
15118
|
};
|
|
14763
15119
|
}
|
|
14764
15120
|
static buildMaterial(doc, binaryBuffers, mat, name, basePath) {
|
|
@@ -14798,38 +15154,45 @@ var GltfLoader = class GltfLoader$1 {
|
|
|
14798
15154
|
1
|
|
14799
15155
|
];
|
|
14800
15156
|
} else if (mat.extensions?.KHR_materials_unlit) material.shading = "unlit";
|
|
14801
|
-
const
|
|
14802
|
-
const
|
|
14803
|
-
|
|
14804
|
-
const
|
|
14805
|
-
|
|
14806
|
-
|
|
14807
|
-
|
|
14808
|
-
|
|
14809
|
-
material.textureWrap = wrap === 33071 ? "clamp" : wrap === 33648 ? "mirror" : "repeat";
|
|
15157
|
+
const plan = GltfLoader$1.uvPlan(mat);
|
|
15158
|
+
const image = (info, slot) => {
|
|
15159
|
+
if (!info) return void 0;
|
|
15160
|
+
const label = `The ${slot} map of material "${name}"`;
|
|
15161
|
+
const set = GltfLoader$1.texCoordOf(info);
|
|
15162
|
+
if (set !== plan.texCoord) {
|
|
15163
|
+
GltfLoader$1.warn(`${label} uses UV set ${set}, but the mesh draws with UV set ${plan.texCoord}; the map is skipped.`);
|
|
15164
|
+
return;
|
|
14810
15165
|
}
|
|
14811
|
-
|
|
14812
|
-
|
|
14813
|
-
|
|
14814
|
-
return tex?.source !== void 0 ? GltfLoader$1.imageBytes(doc, binaryBuffers, tex.source, basePath)?.bytes : void 0;
|
|
15166
|
+
const t = info.extensions?.KHR_texture_transform;
|
|
15167
|
+
if (JSON.stringify(t ?? null) !== JSON.stringify(plan.transform ?? null)) GltfLoader$1.warn(`${label} has a different KHR_texture_transform than the mesh's first map; it is drawn with that one's.`);
|
|
15168
|
+
return GltfLoader$1.textureImage(doc, binaryBuffers, info.index, basePath, label);
|
|
14815
15169
|
};
|
|
14816
|
-
const
|
|
15170
|
+
const base = image(pbr?.baseColorTexture, "base color");
|
|
15171
|
+
if (base) {
|
|
15172
|
+
material.diffuseTextureBuffer = base.bytes;
|
|
15173
|
+
material.diffuseTextureMime = base.mime;
|
|
15174
|
+
const wrap = base.sampler?.wrapS;
|
|
15175
|
+
material.textureWrap = wrap === 33071 ? "clamp" : wrap === 33648 ? "mirror" : "repeat";
|
|
15176
|
+
if (base.sampler?.magFilter === 9728) material.textureFilter = "nearest";
|
|
15177
|
+
}
|
|
15178
|
+
const mapBytes = (info, slot) => image(info, slot)?.bytes;
|
|
15179
|
+
const normal = mapBytes(mat.normalTexture, "normal");
|
|
14817
15180
|
if (normal) {
|
|
14818
15181
|
material.normalTextureBuffer = normal;
|
|
14819
15182
|
material.normalScale = mat.normalTexture?.scale ?? 1;
|
|
14820
15183
|
}
|
|
14821
|
-
const mr = mapBytes(pbr?.metallicRoughnessTexture);
|
|
15184
|
+
const mr = mapBytes(pbr?.metallicRoughnessTexture, "metallic-roughness");
|
|
14822
15185
|
if (mr) {
|
|
14823
15186
|
material.metallicRoughnessTextureBuffer = mr;
|
|
14824
15187
|
material.roughness = pbr?.roughnessFactor ?? 1;
|
|
14825
15188
|
material.metallic = pbr?.metallicFactor ?? 1;
|
|
14826
15189
|
}
|
|
14827
|
-
const occlusion = mapBytes(mat.occlusionTexture);
|
|
15190
|
+
const occlusion = mapBytes(mat.occlusionTexture, "occlusion");
|
|
14828
15191
|
if (occlusion) {
|
|
14829
15192
|
material.occlusionTextureBuffer = occlusion;
|
|
14830
15193
|
material.occlusionStrength = mat.occlusionTexture?.strength ?? 1;
|
|
14831
15194
|
}
|
|
14832
|
-
const emissiveMap = material.emissive && mapBytes(mat.emissiveTexture);
|
|
15195
|
+
const emissiveMap = material.emissive && mapBytes(mat.emissiveTexture, "emissive");
|
|
14833
15196
|
if (emissiveMap) material.emissiveTextureBuffer = emissiveMap;
|
|
14834
15197
|
return material;
|
|
14835
15198
|
}
|
|
@@ -14903,6 +15266,7 @@ var GltfLoader = class GltfLoader$1 {
|
|
|
14903
15266
|
const key = materialKeys[idx];
|
|
14904
15267
|
materials[key] = GltfLoader$1.buildMaterial(doc, binaryBuffers, mat, key, basePath);
|
|
14905
15268
|
});
|
|
15269
|
+
const uvPlans = (doc.materials ?? []).map((mat) => GltfLoader$1.uvPlan(mat));
|
|
14906
15270
|
const nodes = GltfLoader$1.buildNodes(doc);
|
|
14907
15271
|
const skins = (doc.skins ?? []).map((skin) => ({
|
|
14908
15272
|
joints: skin.joints,
|
|
@@ -14966,11 +15330,18 @@ var GltfLoader = class GltfLoader$1 {
|
|
|
14966
15330
|
const read = (acc) => acc === void 0 ? void 0 : GltfLoader$1.readFloats(doc, binaryBuffers, acc);
|
|
14967
15331
|
const pos = read(prim.attributes.POSITION);
|
|
14968
15332
|
const numVerts = pos.count;
|
|
15333
|
+
const plan = prim.material !== void 0 ? uvPlans[prim.material] : void 0;
|
|
15334
|
+
const attributes = prim.attributes;
|
|
15335
|
+
const uvs = read(attributes[`TEXCOORD_${plan?.texCoord ?? 0}`])?.data ?? read(prim.attributes.TEXCOORD_0)?.data ?? new Float32Array(numVerts * 2);
|
|
15336
|
+
if (plan?.transform) applyTextureTransform(uvs, plan.transform);
|
|
14969
15337
|
const colors = read(prim.attributes.COLOR_0);
|
|
14970
15338
|
let rgba;
|
|
14971
15339
|
if (colors) {
|
|
14972
15340
|
rgba = new Float32Array(numVerts * 4).fill(1);
|
|
14973
|
-
for (let v = 0; v < numVerts; v++) for (let c = 0; c < colors.itemSize; c++)
|
|
15341
|
+
for (let v = 0; v < numVerts; v++) for (let c = 0; c < colors.itemSize; c++) {
|
|
15342
|
+
const value = colors.data[v * colors.itemSize + c] ?? 1;
|
|
15343
|
+
rgba[v * 4 + c] = c < 3 ? linearToSrgb(value) : value;
|
|
15344
|
+
}
|
|
14974
15345
|
}
|
|
14975
15346
|
let indices;
|
|
14976
15347
|
if (prim.indices !== void 0) indices = GltfLoader$1.readIndices(doc, binaryBuffers, prim.indices);
|
|
@@ -14998,7 +15369,7 @@ var GltfLoader = class GltfLoader$1 {
|
|
|
14998
15369
|
name: meshDef.name ?? `Mesh_${inst.mesh}`,
|
|
14999
15370
|
positions: pos.data,
|
|
15000
15371
|
normals: read(prim.attributes.NORMAL)?.data ?? new Float32Array(numVerts * 3),
|
|
15001
|
-
uvs
|
|
15372
|
+
uvs,
|
|
15002
15373
|
colors: rgba,
|
|
15003
15374
|
jointIndices: skinned ? read(prim.attributes.JOINTS_0)?.data : void 0,
|
|
15004
15375
|
jointWeights: skinned ? read(prim.attributes.WEIGHTS_0)?.data : void 0,
|
|
@@ -15072,8 +15443,8 @@ var GltfLoader = class GltfLoader$1 {
|
|
|
15072
15443
|
*/
|
|
15073
15444
|
static load(srcOrData, options = {}) {
|
|
15074
15445
|
if (typeof srcOrData !== "string") return GltfLoader$1.parse(srcOrData, options);
|
|
15075
|
-
|
|
15076
|
-
|
|
15446
|
+
const cleanPath = srcOrData.startsWith("file://") ? srcOrData.replace("file://", "") : srcOrData;
|
|
15447
|
+
if (srcOrData.startsWith("/") || srcOrData.startsWith("./") || srcOrData.startsWith("../") || srcOrData.startsWith("file://") || !srcOrData.trimStart().startsWith("{") && fs.existsSync(cleanPath)) {
|
|
15077
15448
|
const buf = fs.readFileSync(cleanPath);
|
|
15078
15449
|
const basePath = path.dirname(cleanPath);
|
|
15079
15450
|
return GltfLoader$1.parse(buf, options, basePath);
|
|
@@ -15087,6 +15458,33 @@ function loadGLTF(srcOrData, options = {}) {
|
|
|
15087
15458
|
function loadGLB(srcOrData, options = {}) {
|
|
15088
15459
|
return GltfLoader.load(srcOrData, options);
|
|
15089
15460
|
}
|
|
15461
|
+
function linearToSrgb(c) {
|
|
15462
|
+
const x = Math.min(Math.max(c, 0), 1);
|
|
15463
|
+
return x <= .0031308 ? x * 12.92 : 1.055 * x ** (1 / 2.4) - .055;
|
|
15464
|
+
}
|
|
15465
|
+
/** The image types the renderer decodes (sharp). */
|
|
15466
|
+
const SUPPORTED_IMAGE_MIMES = new Set([
|
|
15467
|
+
"image/png",
|
|
15468
|
+
"image/jpeg",
|
|
15469
|
+
"image/webp",
|
|
15470
|
+
"image/gif",
|
|
15471
|
+
"image/tiff",
|
|
15472
|
+
"image/avif"
|
|
15473
|
+
]);
|
|
15474
|
+
/**
|
|
15475
|
+
* Bakes KHR_texture_transform into UVs in place: uv' = T * R * S * uv
|
|
15476
|
+
* (offset, then rotation counter-clockwise in UV space, then scale).
|
|
15477
|
+
*/
|
|
15478
|
+
function applyTextureTransform(uvs, { offset = [0, 0], rotation = 0, scale = [1, 1] }) {
|
|
15479
|
+
const c = Math.cos(rotation);
|
|
15480
|
+
const s = Math.sin(rotation);
|
|
15481
|
+
for (let i = 0; i < uvs.length; i += 2) {
|
|
15482
|
+
const u = uvs[i] * scale[0];
|
|
15483
|
+
const v = uvs[i + 1] * scale[1];
|
|
15484
|
+
uvs[i] = c * u + s * v + offset[0];
|
|
15485
|
+
uvs[i + 1] = -s * u + c * v + offset[1];
|
|
15486
|
+
}
|
|
15487
|
+
}
|
|
15090
15488
|
const DEFAULT_PALETTE = [[
|
|
15091
15489
|
0,
|
|
15092
15490
|
0,
|
|
@@ -15660,7 +16058,12 @@ var OffLoader = class OffLoader$1 {
|
|
|
15660
16058
|
const indexArray = createIndexArray(rawIndices, positions.length / 3);
|
|
15661
16059
|
const defaultMaterial = {
|
|
15662
16060
|
name: "off_default",
|
|
15663
|
-
diffuseColor: [
|
|
16061
|
+
diffuseColor: hasColors ? [
|
|
16062
|
+
1,
|
|
16063
|
+
1,
|
|
16064
|
+
1,
|
|
16065
|
+
1
|
|
16066
|
+
] : [
|
|
15664
16067
|
.8,
|
|
15665
16068
|
.8,
|
|
15666
16069
|
.85,
|
|
@@ -26595,6 +26998,7 @@ struct VertexInput {
|
|
|
26595
26998
|
@location(2) normal : vec3<f32>,
|
|
26596
26999
|
@location(3) joints : vec4<f32>,
|
|
26597
27000
|
@location(4) weights : vec4<f32>,
|
|
27001
|
+
@location(5) color : vec4<f32>, // vertex color (display / sRGB), white when absent
|
|
26598
27002
|
};
|
|
26599
27003
|
|
|
26600
27004
|
struct VertexOutput {
|
|
@@ -26603,6 +27007,7 @@ struct VertexOutput {
|
|
|
26603
27007
|
@location(1) worldPos : vec3<f32>,
|
|
26604
27008
|
@location(2) worldNormal : vec3<f32>,
|
|
26605
27009
|
@location(3) linearDepth : f32,
|
|
27010
|
+
@location(4) color : vec4<f32>,
|
|
26606
27011
|
};
|
|
26607
27012
|
|
|
26608
27013
|
@vertex
|
|
@@ -26647,6 +27052,7 @@ fn vs_main(in: VertexInput) -> VertexOutput {
|
|
|
26647
27052
|
|
|
26648
27053
|
out.clipPos = cam.viewProjMatrix * worldPos4;
|
|
26649
27054
|
out.uv = in.uv;
|
|
27055
|
+
out.color = in.color;
|
|
26650
27056
|
|
|
26651
27057
|
out.linearDepth = dot(worldPos4.xyz - cam.cameraPos.xyz, cam.cameraDir.xyz);
|
|
26652
27058
|
return out;
|
|
@@ -26791,12 +27197,12 @@ fn shadeMesh(in: VertexOutput, isFront: bool) -> MeshFragment {
|
|
|
26791
27197
|
if (texColor.a < model.shade.a) {
|
|
26792
27198
|
discard;
|
|
26793
27199
|
}
|
|
26794
|
-
let alpha = texColor.a * model.params.x * model.colorTint.a * matteCoverage(in.clipPos.xy);
|
|
27200
|
+
let alpha = texColor.a * in.color.a * model.params.x * model.colorTint.a * matteCoverage(in.clipPos.xy);
|
|
26795
27201
|
if (alpha <= 0.001) {
|
|
26796
27202
|
discard;
|
|
26797
27203
|
}
|
|
26798
27204
|
|
|
26799
|
-
let baseRgb = texColor.rgb * model.colorTint.rgb;
|
|
27205
|
+
let baseRgb = texColor.rgb * in.color.rgb * model.colorTint.rgb;
|
|
26800
27206
|
var out: MeshFragment;
|
|
26801
27207
|
if (model.materialParams.w > 1.5) {
|
|
26802
27208
|
var toon = baseRgb;
|
|
@@ -27488,6 +27894,11 @@ var Mesh3DPipeline = class {
|
|
|
27488
27894
|
/** (0.5, 0.5, 1): an unperturbed tangent-space normal. */
|
|
27489
27895
|
flatNormalTexture;
|
|
27490
27896
|
defaultSkinningBuffer;
|
|
27897
|
+
/** White vertex colors for meshes without any, grown to the largest mesh. */
|
|
27898
|
+
whiteColorBuffer = null;
|
|
27899
|
+
whiteColorCapacity = 0;
|
|
27900
|
+
/** Outgrown white buffers: earlier draws this frame may still read them. */
|
|
27901
|
+
retiredColorBuffers = [];
|
|
27491
27902
|
modelData = new Float32Array(52 + SURFACE_PARAMS_FLOATS);
|
|
27492
27903
|
constructor(device, format, depthFormat = "depth24plus", cameraLayout, lightsLayout, sampleCount = 1) {
|
|
27493
27904
|
this.device = device;
|
|
@@ -27579,6 +27990,13 @@ var Mesh3DPipeline = class {
|
|
|
27579
27990
|
format: "float32x4"
|
|
27580
27991
|
}
|
|
27581
27992
|
]
|
|
27993
|
+
}, {
|
|
27994
|
+
arrayStride: 16,
|
|
27995
|
+
attributes: [{
|
|
27996
|
+
shaderLocation: 5,
|
|
27997
|
+
offset: 0,
|
|
27998
|
+
format: "float32x4"
|
|
27999
|
+
}]
|
|
27582
28000
|
}]
|
|
27583
28001
|
};
|
|
27584
28002
|
const base = {
|
|
@@ -27773,6 +28191,7 @@ var Mesh3DPipeline = class {
|
|
|
27773
28191
|
pass.setBindGroup(2, textureBindGroup);
|
|
27774
28192
|
pass.setBindGroup(3, lightsBindGroup);
|
|
27775
28193
|
pass.setVertexBuffer(0, meshBuffers.vertexBuffer);
|
|
28194
|
+
pass.setVertexBuffer(1, this.colorsFor(meshBuffers));
|
|
27776
28195
|
pass.setIndexBuffer(meshBuffers.indexBuffer, meshBuffers.indexFormat);
|
|
27777
28196
|
pass.drawIndexed(meshBuffers.indexCount);
|
|
27778
28197
|
}
|
|
@@ -27782,10 +28201,31 @@ var Mesh3DPipeline = class {
|
|
|
27782
28201
|
pass.setBindGroup(0, lightCameraBindGroup);
|
|
27783
28202
|
pass.setBindGroup(1, this.packModel(data));
|
|
27784
28203
|
pass.setVertexBuffer(0, meshBuffers.vertexBuffer);
|
|
28204
|
+
pass.setVertexBuffer(1, this.colorsFor(meshBuffers));
|
|
27785
28205
|
pass.setIndexBuffer(meshBuffers.indexBuffer, meshBuffers.indexFormat);
|
|
27786
28206
|
pass.drawIndexed(meshBuffers.indexCount);
|
|
27787
28207
|
}
|
|
28208
|
+
colorsFor(meshBuffers) {
|
|
28209
|
+
if (meshBuffers.colorBuffer) return meshBuffers.colorBuffer;
|
|
28210
|
+
const needed = Math.max(1, Math.ceil(meshBuffers.vertexBuffer.size / 64));
|
|
28211
|
+
if (!this.whiteColorBuffer || this.whiteColorCapacity < needed) {
|
|
28212
|
+
if (this.whiteColorBuffer) this.retiredColorBuffers.push(this.whiteColorBuffer);
|
|
28213
|
+
const capacity = 2 ** Math.ceil(Math.log2(needed));
|
|
28214
|
+
this.whiteColorBuffer = this.device.createBuffer({
|
|
28215
|
+
label: "Mesh3DWhiteVertexColors",
|
|
28216
|
+
size: capacity * 16,
|
|
28217
|
+
usage: GPUBufferUsage.VERTEX,
|
|
28218
|
+
mappedAtCreation: true
|
|
28219
|
+
});
|
|
28220
|
+
new Float32Array(this.whiteColorBuffer.getMappedRange()).fill(1);
|
|
28221
|
+
this.whiteColorBuffer.unmap();
|
|
28222
|
+
this.whiteColorCapacity = capacity;
|
|
28223
|
+
}
|
|
28224
|
+
return this.whiteColorBuffer;
|
|
28225
|
+
}
|
|
27788
28226
|
destroy() {
|
|
28227
|
+
this.whiteColorBuffer?.destroy();
|
|
28228
|
+
for (const buffer of this.retiredColorBuffers) buffer.destroy();
|
|
27789
28229
|
this.modelPool.destroy();
|
|
27790
28230
|
this.skinningPool.destroy();
|
|
27791
28231
|
this.defaultWhiteTexture.destroy();
|
|
@@ -30332,11 +30772,23 @@ var Renderer3D = class {
|
|
|
30332
30772
|
if (is32Bit) new Uint32Array(indexBuffer.getMappedRange()).set(mesh.indices);
|
|
30333
30773
|
else new Uint16Array(indexBuffer.getMappedRange()).set(mesh.indices);
|
|
30334
30774
|
indexBuffer.unmap();
|
|
30775
|
+
let colorBuffer;
|
|
30776
|
+
if (mesh.colors && mesh.colors.length >= numVerts * 4) {
|
|
30777
|
+
colorBuffer = this.device.createBuffer({
|
|
30778
|
+
label: "Mesh3DVertexColors",
|
|
30779
|
+
size: Math.max(16, numVerts * 16),
|
|
30780
|
+
usage: GPUBufferUsage.VERTEX,
|
|
30781
|
+
mappedAtCreation: true
|
|
30782
|
+
});
|
|
30783
|
+
new Float32Array(colorBuffer.getMappedRange()).set(mesh.colors.subarray(0, numVerts * 4));
|
|
30784
|
+
colorBuffer.unmap();
|
|
30785
|
+
}
|
|
30335
30786
|
cached$1 = {
|
|
30336
30787
|
vertexBuffer,
|
|
30337
30788
|
indexBuffer,
|
|
30338
30789
|
indexCount: mesh.indices.length,
|
|
30339
|
-
indexFormat: is32Bit ? "uint32" : "uint16"
|
|
30790
|
+
indexFormat: is32Bit ? "uint32" : "uint16",
|
|
30791
|
+
colorBuffer
|
|
30340
30792
|
};
|
|
30341
30793
|
this.meshBuffersCache.set(mesh, cached$1);
|
|
30342
30794
|
return cached$1;
|
|
@@ -30354,7 +30806,8 @@ var Renderer3D = class {
|
|
|
30354
30806
|
}),
|
|
30355
30807
|
indexBuffer: meshBuffers.indexBuffer,
|
|
30356
30808
|
indexCount: meshBuffers.indexCount,
|
|
30357
|
-
indexFormat: meshBuffers.indexFormat
|
|
30809
|
+
indexFormat: meshBuffers.indexFormat,
|
|
30810
|
+
colorBuffer: meshBuffers.colorBuffer
|
|
30358
30811
|
};
|
|
30359
30812
|
}
|
|
30360
30813
|
drawMesh3D(pass, cameraBindGroup, lightsBindGroup, meshOrBuffers, texture, opts = {}, useMrt = false) {
|
|
@@ -30364,13 +30817,15 @@ var Renderer3D = class {
|
|
|
30364
30817
|
1,
|
|
30365
30818
|
1,
|
|
30366
30819
|
1
|
|
30367
|
-
], twoSided = true, wireframe = false, isSkinned = false, skinningMatrices, material = "lit", shadeColor, alphaCutoff, textureWrap = "clamp", shininess = 32, roughness, specularIntensity = .5, ambientIntensity = 1, metallic } = opts;
|
|
30820
|
+
], twoSided = true, wireframe = false, isSkinned = false, skinningMatrices, material = "lit", shadeColor, alphaCutoff, textureWrap = "clamp", textureFilter = "linear", shininess = 32, roughness, specularIntensity = .5, ambientIntensity = 1, metallic } = opts;
|
|
30368
30821
|
const m = this.meshModelMatrix(opts);
|
|
30369
30822
|
const normalMatrix = opts.normalMatrix ?? Light3D.computeNormalMatrix(m);
|
|
30370
30823
|
const address = ADDRESS_MODES[textureWrap];
|
|
30371
30824
|
const sampler = this.samplerCache.getSampler(this.device, {
|
|
30372
30825
|
addressModeU: address,
|
|
30373
|
-
addressModeV: address
|
|
30826
|
+
addressModeV: address,
|
|
30827
|
+
magFilter: textureFilter,
|
|
30828
|
+
...textureFilter === "nearest" && { maxAnisotropy: 1 }
|
|
30374
30829
|
});
|
|
30375
30830
|
const glassy = material === "glass" || material === "acrylic" || material === "frosted";
|
|
30376
30831
|
const glass = glassy ? {
|
|
@@ -30469,7 +30924,14 @@ var Renderer3D = class {
|
|
|
30469
30924
|
"sharp"
|
|
30470
30925
|
)).default;
|
|
30471
30926
|
const source = Buffer.from(encoded instanceof Uint8Array ? encoded : new Uint8Array(encoded));
|
|
30472
|
-
|
|
30927
|
+
let width;
|
|
30928
|
+
let height;
|
|
30929
|
+
try {
|
|
30930
|
+
({width, height} = await sharp(source).metadata());
|
|
30931
|
+
} catch (err) {
|
|
30932
|
+
console.warn(`[Renderer3D] Could not decode texture "${label}"; drawing without it:`, err instanceof Error ? err.message : err);
|
|
30933
|
+
return;
|
|
30934
|
+
}
|
|
30473
30935
|
if (!width || !height) return void 0;
|
|
30474
30936
|
const mipLevelCount = Math.floor(Math.log2(Math.max(width, height))) + 1;
|
|
30475
30937
|
const texture = this.device.createTexture({
|
|
@@ -31207,4 +31669,4 @@ if (typeof globalThis !== "undefined") globalThis.__GATEWAI_DELAYS__ = globalThi
|
|
|
31207
31669
|
|
|
31208
31670
|
//#endregion
|
|
31209
31671
|
export { resolveTextSpans as $, TextSelectorSchema as $t, ensureDevice as A, sampleAudioSpectrumScale as An, GlyphAnchorGroupingSchema as At, loadModel3D as B, SignalRegistry as Bt, drawGifNode as C, evaluateTypewriterState as Cn, AudioSpectrumTypographySchema as Ct, drawSignalNode as D, getScramblePool as Dn, EnhancedTextNodeSchema as Dt, drawParagraphNode as E, generatePathSegments as En, DynamicStrokePropertiesSchema as Et, getRenderer2D as F, ParticleDissolveConfigSchema as Ft, parseColor as G, TextAnimatorBuilder as Gt, lutStore as H, Spatial3DPropertiesSchema as Ht, initHeadlessWebGPU as I, SelectorBasedOnSchema as It, parseOBJ as J, TextPathBuilder as Jt, parseFBX as K, TextCursorConfigSchema as Kt, inputStore as L, SelectorModeSchema as Lt, generateExtrudedTextGeometry as M, samplePathChainGeometry as Mn, KineticMarqueeConfigSchema as Mt, getHeadlessFontPath as N, signalRegistry as Nn, LineSpacingDynamicsSchema as Nt, drawSvgNode as O, getShuffledOrder as On, ExpressionSelectorSchema as Ot, getPrimitiveGeometry as P, waveToCubicBeziers as Pn, LongShadowConfigSchema as Pt, registerHeadlessFont as Q, TextScrambleConfigSchema as Qt, jointMatrices as R, SelectorShapeSchema as Rt, drawCaptionNode as S, evaluateSpringProgress as Sn, AudioSignalComputePipeline as St, drawLottieNode as T, generateArcLengthLUT as Tn, CubicBezierSegmentSchema as Tt, measureMaxCaptionHeight as U, SpringPhysicsSchema as Ut, loadOBJ as V, SkewPropertiesSchema as Vt, mediaDecoderCache as W, TextAnchorConfigSchema as Wt, poseNodes as X, TextPathSourceSchema as Xt, parseSvgPathToSegments as Y, TextPathOptionsSchema as Yt, probeVideoSize as Z, TextRangeSelectorSchema as Zt, buildShapeSvgPath as _, evaluateCubicBezierDerivative as _n, AdvancedTextAnimatorBuilder as _t, GlassPipeline as a, Vec2Schema as an, resolveMediaSourceUrl as at, colorMatrixWgsl as b, evaluateSelectorCombination as bn, AnchorPresetSchema as bt, Renderer2D as c, buildPathLUT as cn, LIGHT_UNIFORM_SIZE_BYTES as ct, ScreenSpaceRelightPipeline as d, computeLineLeadingDisplacement as dn, Matrix4Math as dt, TextSignalSelectorSchema as en, shaderStore as et, ShadowPipeline as f, computeRangeSelectorWeight as fn, Path3D as ft, WebGPUAudioProcessor as g, evaluateCubicBezier as gn, AETextAnimatorSchema as gt, SlugPipeline as h, ellipseToCubicBeziers as hn, resolveEnvironment as ht, EffectPipeline as i, VariableFontAxesSchema as in, GetFontAssetUrl as it, fitSpansToText as j, sampleCurveGeometry as jn, GlyphAnchorPointSchema as jt, drawVideoNode as k, parseSvgPathToCubicBeziers as kn, ExtendedGlyphPropertiesSchema as kt, Renderer3D as l, buildWGSLSignalFn as ln, Light3D as lt, SlugGeometry as m, distanceToCurveParameter as mn, parseColorToRgb as mt, AudioLatentTrackCache as n, TypewriterAnimatorSchema as nn, srtLoader as nt, MotionBlurPipeline as o, VolumetricFormationConfigSchema as on, Camera3D as ot, SlugFontCache as p, deterministicWigglyNoise as pn, Vector3Math as pt, parseMTL as q, TextCursorStyleSchema as qt, AudioMeshDeformPipeline as r, TypingCadenceSchema as rn, textureCache as rt, NodeSurfaceProvider as s, VolumetricFormationModeSchema as sn, ENVIRONMENT_PRESETS as st, AudioLatentEngine as t, TextWigglySelectorSchema as tn, spansText as tt, SSAOPipeline as u, computeAnchorPivotOffset as un, MAX_LIGHTS as ut, clearAllVideoCache as v, evaluateExpressionSelector as vn, AdvancedTextAnimatorSchema as vt, drawImageNode as w, evaluateVolumetricFormation as wn, ChromaticGlitchConfigSchema as wt, describeGpu as x, evaluateSkewMatrix as xn, AnimatableGlyphPropsSchema as xt, clearHeadlessFonts as y, evaluateMarqueeOffset as yn, AnchorGroupingSchema as yt, loadFBX as z, SelectorUnitsSchema as zt };
|
|
31210
|
-
//# sourceMappingURL=dist-
|
|
31672
|
+
//# sourceMappingURL=dist-CspOG4V1.mjs.map
|