@holoscript/core 8.0.7 → 8.0.9
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/bin/holoscript.cjs +5 -1
- package/dist/GLTFPipeline-L76YTXKA.js +15 -0
- package/dist/GLTFPipeline-ZWJN7GI6.cjs +36 -0
- package/dist/HoloCompositionParser-K76KTEEE.js +12 -0
- package/dist/HoloCompositionParser-UZH6Y4HO.cjs +45 -0
- package/dist/HoloScriptCodeParser-2D4ERFUZ.js +6 -0
- package/dist/HoloScriptCodeParser-UDRLDA7I.cjs +23 -0
- package/dist/HoloScriptPlusParser-FTMCGWXD.js +13 -0
- package/dist/HoloScriptPlusParser-LQR5GIKF.cjs +30 -0
- package/dist/HoloScriptRuntime-UTRLJI5L.js +12 -0
- package/dist/HoloScriptRuntime-YBYXJHJN.cjs +21 -0
- package/dist/SceneIRCompiler-63KA3M2F.js +17 -0
- package/dist/SceneIRCompiler-KWUFHZ4O.cjs +42 -0
- package/dist/{USDZExporter-AUHZODOF.cjs → USDZExporter-ML4UMIGC.cjs} +3 -3
- package/dist/{USDZExporter-GXB4AUSG.js → USDZExporter-ZFKLQ76G.js} +3 -3
- package/dist/agents/index.cjs +1 -1
- package/dist/agents/index.js +1 -1
- package/dist/audit/AuditLogger.d.ts +106 -0
- package/dist/audit/AuditQueryBuilder.d.ts +79 -0
- package/dist/audit/ComplianceReporter.d.ts +90 -0
- package/dist/audit/index.d.ts +13 -0
- package/dist/{chunk-FGMDMJM7.js → chunk-2BYAUHBO.js} +3 -3
- package/dist/{chunk-EDPYCLRC.cjs → chunk-2E6PP5UE.cjs} +83 -59
- package/dist/{chunk-GASCWJK5.js → chunk-2EGGAZT3.js} +65 -287
- package/dist/{chunk-SIEXCILW.js → chunk-2I3XAGMF.js} +3 -3
- package/dist/{chunk-OS533P33.cjs → chunk-2KKOYZYI.cjs} +1074 -1655
- package/dist/chunk-2MQKNDNH.js +51 -0
- package/dist/{chunk-7DMMMBCY.cjs → chunk-2X3IPCBK.cjs} +10 -10
- package/dist/chunk-2ZOTBO25.cjs +202 -0
- package/dist/chunk-356N4NPM.cjs +152 -0
- package/dist/{chunk-X3GJPRVK.cjs → chunk-36NPLOI4.cjs} +92 -81
- package/dist/{chunk-SLU6UPJI.cjs → chunk-37HHY7RH.cjs} +5 -5
- package/dist/{chunk-YDPEHCCI.cjs → chunk-3CDDRUER.cjs} +3 -118
- package/dist/chunk-3F7ZZWIN.js +1651 -0
- package/dist/chunk-3ILD7TKP.cjs +187 -0
- package/dist/{chunk-X27QRG4C.cjs → chunk-3IUHTGDD.cjs} +153 -41
- package/dist/{chunk-PXNZ6TME.js → chunk-4376VHNJ.js} +60 -36
- package/dist/{chunk-YKGPCZEE.cjs → chunk-4FIBOJW6.cjs} +10 -10
- package/dist/chunk-4Q7RKQQI.cjs +14195 -0
- package/dist/{chunk-YCM6QQRT.cjs → chunk-566ZB4LZ.cjs} +180 -8
- package/dist/{chunk-2Y3V22SG.js → chunk-5CURIYGT.js} +3 -3
- package/dist/{chunk-QBWNJXNR.js → chunk-5FYMCVBY.js} +5 -5
- package/dist/{chunk-ZA34AN3R.js → chunk-5LVFTGKH.js} +841 -12
- package/dist/chunk-63AUAIL6.js +48 -0
- package/dist/chunk-655FATJU.js +110 -0
- package/dist/{chunk-TQ377OLB.cjs → chunk-65S62L4D.cjs} +28 -22
- package/dist/chunk-6NTAZN5Z.cjs +502 -0
- package/dist/chunk-6TRX6AR2.js +9376 -0
- package/dist/chunk-6ZCCLKS2.cjs +51 -0
- package/dist/{chunk-MDR235RZ.js → chunk-734OB5SK.js} +721 -8
- package/dist/{chunk-Q2Q34NF3.js → chunk-77QI552M.js} +6 -6
- package/dist/{chunk-WKX5AMOY.js → chunk-7I74JWPW.js} +3 -3
- package/dist/{chunk-5FSKKMR7.cjs → chunk-7IDJDMPU.cjs} +232 -4
- package/dist/chunk-7VBKRGIZ.cjs +847 -0
- package/dist/{chunk-KCPHASCO.js → chunk-AATYYLYK.js} +5 -5
- package/dist/{chunk-WFKVS2K4.cjs → chunk-AUZRKIHQ.cjs} +1101 -55
- package/dist/{chunk-DTGBOSEM.cjs → chunk-AWXFEAQL.cjs} +12 -12
- package/dist/{chunk-THCK6ECW.js → chunk-B3CWTCK2.js} +231 -3
- package/dist/chunk-BCP4E7MD.cjs +997 -0
- package/dist/chunk-BG7RPYJP.js +91 -0
- package/dist/{chunk-VF257YKO.js → chunk-BP4KTMLY.js} +117 -5
- package/dist/{chunk-YN6IETRZ.js → chunk-BQJ3YBF3.js} +6424 -987
- package/dist/{chunk-KOUAQL2B.cjs → chunk-CANAL6CT.cjs} +1569 -168
- package/dist/{chunk-FDSGHPAK.js → chunk-CBSDJF3B.js} +3 -3
- package/dist/{chunk-FEWUHQNM.cjs → chunk-CFVK26P4.cjs} +4 -4
- package/dist/{chunk-M7K4LE66.cjs → chunk-CI33NINL.cjs} +4 -4
- package/dist/{chunk-2OWDB4FB.js → chunk-CKV5NYAE.js} +6 -6
- package/dist/{chunk-LPS5AMQD.cjs → chunk-CM4NHXVO.cjs} +24 -24
- package/dist/chunk-D3HSRXYB.js +115 -0
- package/dist/{chunk-FNHJRI32.js → chunk-DBH3D2MU.js} +1561 -160
- package/dist/{chunk-GW3LKD5C.js → chunk-DJNH4HFW.js} +3 -3
- package/dist/{chunk-2GCNOI2U.cjs → chunk-DN6F4DHH.cjs} +9 -3
- package/dist/chunk-DQRJ5RJG.js +432 -0
- package/dist/{chunk-C7ZBSV2Q.js → chunk-DUG3OQAS.js} +106 -43
- package/dist/chunk-ECUYJOJ2.cjs +199 -0
- package/dist/chunk-EEMTCAK7.js +182 -0
- package/dist/{chunk-3SKLAUDD.cjs → chunk-EI3J6LTW.cjs} +359 -581
- package/dist/{chunk-SSSN7VAM.js → chunk-EM2OGPYE.js} +4 -4
- package/dist/{chunk-56VOWURB.cjs → chunk-ENZCIQZC.cjs} +522 -453
- package/dist/chunk-ESBXUYOC.cjs +836 -0
- package/dist/{chunk-L5U4W6JC.js → chunk-ESSEF6U2.js} +4 -4
- package/dist/chunk-ET3AN4W3.js +824 -0
- package/dist/chunk-EXKSFGSX.cjs +14 -14
- package/dist/{chunk-I76GIKN7.cjs → chunk-F3YT6GUF.cjs} +17 -17
- package/dist/{chunk-WRWEX5ZF.js → chunk-F75DZBBI.js} +3 -3
- package/dist/{chunk-4JGRWHZJ.js → chunk-FG6PYGIZ.js} +12 -6
- package/dist/chunk-FGGJQRLZ.js +14 -14
- package/dist/{chunk-SXOSDZD6.js → chunk-FWCHPCD4.js} +128 -10
- package/dist/{chunk-XW6IXEQH.cjs → chunk-G35CAQ7I.cjs} +5 -5
- package/dist/{chunk-7VMGP2FW.js → chunk-G6KACNMO.js} +132 -188
- package/dist/{chunk-FJPADH77.cjs → chunk-GAWJJAGT.cjs} +6 -6
- package/dist/chunk-GGR7QUKK.cjs +4724 -0
- package/dist/chunk-GIBF4BHH.js +14098 -0
- package/dist/{chunk-AWB7QYY6.cjs → chunk-GILYQ5VH.cjs} +6 -6
- package/dist/{chunk-FWVYAMNW.cjs → chunk-GKFCHGCM.cjs} +4 -4
- package/dist/{chunk-Y3ZFVUUU.js → chunk-GLEJ2TLS.js} +3 -3
- package/dist/{chunk-3GWWJT7L.js → chunk-GP3OKSKT.js} +13 -13
- package/dist/chunk-GTIPOEHN.js +196 -0
- package/dist/{chunk-LMJ5EBV7.cjs → chunk-GZPUA2TL.cjs} +16 -15
- package/dist/{chunk-IELX2OKI.js → chunk-H4LJ4HEA.js} +3 -115
- package/dist/{chunk-ACVWFGBI.cjs → chunk-HCX4SMFK.cjs} +3 -3
- package/dist/{chunk-HYNTS5CP.js → chunk-HHRZ6STP.js} +24 -2
- package/dist/chunk-HIDEIEFG.js +48 -0
- package/dist/{chunk-W6RW64BB.cjs → chunk-HSWBIDZM.cjs} +228 -5
- package/dist/{chunk-GSOUNWEL.js → chunk-HVX7QQYK.js} +1035 -1616
- package/dist/{chunk-TRCGG42I.cjs → chunk-IFW5IW4L.cjs} +6502 -1019
- package/dist/{chunk-F5LKJ6F5.cjs → chunk-IJU6AS67.cjs} +32 -28
- package/dist/{chunk-TVANHNJ7.js → chunk-IK6Z2HNC.js} +173 -3
- package/dist/{chunk-QGMUTVVH.cjs → chunk-IS7NTKY5.cjs} +20 -20
- package/dist/{chunk-YFVQWSNJ.js → chunk-IXWGYWH6.js} +3 -3
- package/dist/chunk-J2DAS2PL.js +148 -0
- package/dist/chunk-JBQXZIWB.js +148 -0
- package/dist/chunk-JBYBMBMW.js +261 -0
- package/dist/{chunk-LWUOUCYL.js → chunk-JEJ7TT54.js} +5 -5
- package/dist/{chunk-DUCB6LGL.js → chunk-JOTCTHN5.js} +211 -5
- package/dist/{chunk-47RUFYKR.js → chunk-K56UVEXV.js} +3 -3
- package/dist/{chunk-XSFNHP2E.js → chunk-KB26H447.js} +3 -3
- package/dist/{chunk-3NGDZZR4.js → chunk-KEYG7HGY.js} +430 -37
- package/dist/{chunk-DY72BMU5.js → chunk-KFVNCW4Q.js} +4 -4
- package/dist/chunk-KPGC7SK2.js +192 -0
- package/dist/chunk-KROXXBK5.cjs +53 -0
- package/dist/{chunk-ZPZAVHXL.cjs → chunk-LB3ZZMKT.cjs} +137 -19
- package/dist/chunk-LDYZWNJW.cjs +1654 -0
- package/dist/{chunk-ULMSSHCJ.cjs → chunk-LMB555QB.cjs} +405 -38
- package/dist/{chunk-CBJY23VL.js → chunk-MD4IVS42.js} +3 -3
- package/dist/{chunk-VMLKSV26.js → chunk-MDDWEBCX.js} +226 -3
- package/dist/chunk-MUWH4QK5.cjs +94 -0
- package/dist/{chunk-T6W3Z3SH.cjs → chunk-N2ILK7BF.cjs} +4 -4
- package/dist/{chunk-6EX3I5P4.cjs → chunk-N74QRJGP.cjs} +6 -6
- package/dist/chunk-NFFHLX37.cjs +132 -0
- package/dist/chunk-NJSYWX7H.js +190 -0
- package/dist/{chunk-SH5PPVK7.cjs → chunk-NQN5LFN4.cjs} +165 -221
- package/dist/chunk-NTQRFOPP.cjs +56 -0
- package/dist/{chunk-YFWRJW4B.js → chunk-NWMJPTVL.js} +51 -55
- package/dist/{chunk-63ZGNR2T.cjs → chunk-OC6GV5QH.cjs} +42 -42
- package/dist/{chunk-7E7GCQCK.js → chunk-OG3MBHM3.js} +9 -3
- package/dist/chunk-OMNHTCS4.cjs +264 -0
- package/dist/chunk-OQXB6NNC.cjs +117 -0
- package/dist/{chunk-Y57W2CT5.cjs → chunk-OV46CCA2.cjs} +51 -55
- package/dist/{chunk-6PRZIHGL.cjs → chunk-OV6HHKLE.cjs} +21 -266
- package/dist/{chunk-C37BHB7N.cjs → chunk-P26YYPOO.cjs} +5 -5
- package/dist/{chunk-2BZHWUSR.cjs → chunk-P7JEKJTZ.cjs} +16 -16
- package/dist/{chunk-NGBXXZLL.cjs → chunk-PDXX5UI4.cjs} +45 -45
- package/dist/{chunk-FHQFPYV4.js → chunk-PJFTTSKE.js} +8 -7
- package/dist/{chunk-GVFJ6T4S.cjs → chunk-PVODJEJ7.cjs} +721 -8
- package/dist/{chunk-ZZ7RO2UQ.js → chunk-Q265VZJ4.js} +3 -3
- package/dist/{chunk-E7JP3BS3.cjs → chunk-Q47JEE2C.cjs} +4 -4
- package/dist/chunk-QBY7LRN2.js +281 -0
- package/dist/{chunk-Z6PMDS4G.js → chunk-QDQWKSU3.js} +1090 -53
- package/dist/{chunk-GH6C2QGW.cjs → chunk-QEDMOGF3.cjs} +857 -16
- package/dist/{chunk-5WUNN6ZN.cjs → chunk-QHSAVOOL.cjs} +24 -2
- package/dist/chunk-QJNCDVYM.cjs +137 -0
- package/dist/chunk-QM7FJB5W.js +4717 -0
- package/dist/chunk-QQFB4RT2.cjs +448 -0
- package/dist/chunk-QSYBHQAD.cjs +196 -0
- package/dist/{chunk-UGXHYIWT.cjs → chunk-QUJ3ZB55.cjs} +28 -28
- package/dist/{chunk-2YSNA2F2.cjs → chunk-QVJMDVYZ.cjs} +5 -5
- package/dist/chunk-RAJMAX6D.js +131 -0
- package/dist/{chunk-VVKVQZI6.js → chunk-RAN3ECAS.js} +3 -3
- package/dist/chunk-RKGUZBOC.js +79 -0
- package/dist/{chunk-HLFDZ35S.cjs → chunk-RRQIAJLQ.cjs} +8 -8
- package/dist/{chunk-PABONWKI.js → chunk-RXQNRZ5F.js} +3 -3
- package/dist/{chunk-7ZHYEITD.cjs → chunk-S4O7CFHQ.cjs} +10 -11
- package/dist/chunk-SE7ANBGN.js +128 -0
- package/dist/{chunk-X2AVEAZM.cjs → chunk-SJIRCTIS.cjs} +176 -2
- package/dist/{chunk-WXQ57LAO.js → chunk-SQXAZHDG.js} +4 -4
- package/dist/chunk-SR73L5ZP.cjs +84 -0
- package/dist/{chunk-OABEO6HH.js → chunk-SZOLTWWD.js} +2349 -214
- package/dist/{chunk-5JEU52DW.js → chunk-TPZ3BN2D.js} +3 -3
- package/dist/{chunk-QFU53KRH.js → chunk-TSTFYGGX.js} +4 -5
- package/dist/{chunk-EBS32AJI.cjs → chunk-TZCFKZ6Z.cjs} +5 -5
- package/dist/chunk-UCVZXQ63.js +724 -0
- package/dist/chunk-UGQ3QNV6.js +992 -0
- package/dist/chunk-UNMVGZVW.js +142 -0
- package/dist/{chunk-TEVX443G.js → chunk-UTUD6GJI.js} +178 -6
- package/dist/chunk-UXBYA7DV.cjs +155 -0
- package/dist/chunk-V6GXFSK7.cjs +443 -0
- package/dist/chunk-VHORVGCG.cjs +761 -0
- package/dist/{chunk-B4EKV6HQ.js → chunk-VKCTYLDN.js} +500 -442
- package/dist/{chunk-O3MGZDCT.cjs → chunk-VTEXJOSD.cjs} +63 -63
- package/dist/chunk-VVAAZITA.cjs +287 -0
- package/dist/{chunk-V7AKE5VT.cjs → chunk-W2GA3EQB.cjs} +435 -42
- package/dist/chunk-W4GABFCR.js +37 -0
- package/dist/chunk-WKEK4NCA.js +490 -0
- package/dist/{chunk-5A4TCHOC.cjs → chunk-WNYXT4TE.cjs} +4 -4
- package/dist/{chunk-S762UEV5.js → chunk-WTH23ISI.js} +6 -6
- package/dist/{chunk-BTKZGHAV.js → chunk-WWNCM473.js} +10 -6
- package/dist/{chunk-7X5PNIQJ.js → chunk-X3YFRH6K.js} +27 -25
- package/dist/{chunk-4YNYPHH3.cjs → chunk-X75H75UY.cjs} +2351 -213
- package/dist/{chunk-LYJJI7ZK.cjs → chunk-XCUDDFKC.cjs} +216 -9
- package/dist/chunk-YAO4HPJL.cjs +120 -0
- package/dist/chunk-YKY2JBER.cjs +9443 -0
- package/dist/chunk-YP5CHEYU.cjs +154 -0
- package/dist/{chunk-WRNEH5MO.js → chunk-YW3I2FQL.js} +18 -7
- package/dist/{chunk-BRNUPDHJ.js → chunk-Z557DVYN.js} +386 -19
- package/dist/{chunk-VSACG2AR.js → chunk-Z6LZUYZF.js} +21 -264
- package/dist/chunk-ZHPMP447.cjs +43 -0
- package/dist/{chunk-LODTHGST.cjs → chunk-ZK7KX5CD.cjs} +133 -70
- package/dist/{chunk-CCPSNT6B.cjs → chunk-ZRPALBQB.cjs} +5 -5
- package/dist/chunk-ZVFHPMC5.js +824 -0
- package/dist/chunk-ZVQMKUGJ.js +443 -0
- package/dist/cli/holoscript-runner.cjs +86 -48
- package/dist/cli/holoscript-runner.js +54 -16
- package/dist/codebase/index.cjs +1 -1
- package/dist/codebase/index.js +1 -1
- package/dist/compiler/agent-inference.cjs +11 -11
- package/dist/compiler/agent-inference.js +9 -6
- package/dist/compiler/android-xr.cjs +13 -12
- package/dist/compiler/android-xr.js +11 -10
- package/dist/compiler/android.cjs +12 -12
- package/dist/compiler/android.js +10 -10
- package/dist/compiler/business-quest.cjs +10 -10
- package/dist/compiler/business-quest.js +2 -2
- package/dist/compiler/coco.cjs +1 -1
- package/dist/compiler/coco.js +1 -1
- package/dist/compiler/context.cjs +9 -9
- package/dist/compiler/context.js +6 -6
- package/dist/compiler/daimon-seed.cjs +36 -0
- package/dist/compiler/daimon-seed.js +12 -0
- package/dist/compiler/domain-block-utils.cjs +205 -156
- package/dist/compiler/domain-block-utils.js +8 -7
- package/dist/compiler/dtdl.cjs +10 -10
- package/dist/compiler/dtdl.js +7 -7
- package/dist/compiler/gltf-pipeline.cjs +9 -9
- package/dist/compiler/gltf-pipeline.js +2 -2
- package/dist/compiler/godot.cjs +10 -9
- package/dist/compiler/godot.js +9 -8
- package/dist/compiler/incremental.cjs +11 -11
- package/dist/compiler/incremental.js +6 -6
- package/dist/compiler/index.cjs +2585 -3273
- package/dist/compiler/index.d.ts +149 -35
- package/dist/compiler/index.js +2197 -3102
- package/dist/compiler/ios.cjs +11 -11
- package/dist/compiler/ios.js +9 -9
- package/dist/compiler/llm-provider-capabilities.cjs +9 -9
- package/dist/compiler/llm-provider-capabilities.js +6 -6
- package/dist/compiler/nodetoy.cjs +1 -1
- package/dist/compiler/nodetoy.js +1 -1
- package/dist/compiler/openxr.cjs +11 -10
- package/dist/compiler/openxr.js +10 -9
- package/dist/compiler/remotion.cjs +1 -1
- package/dist/compiler/remotion.js +1 -1
- package/dist/compiler/reproducibility.cjs +1 -1
- package/dist/compiler/reproducibility.js +1 -1
- package/dist/compiler/sdf.cjs +11 -10
- package/dist/compiler/sdf.js +9 -8
- package/dist/compiler/semantic-scene.cjs +7 -7
- package/dist/compiler/semantic-scene.js +2 -2
- package/dist/compiler/state.cjs +9 -9
- package/dist/compiler/state.js +7 -7
- package/dist/compiler/trait-composition.cjs +11 -11
- package/dist/compiler/trait-composition.js +7 -7
- package/dist/compiler/traits/ProvenanceSemiring.d.ts +167 -0
- package/dist/compiler/traits/Semiring.d.ts +26 -0
- package/dist/compiler/unity.cjs +11 -10
- package/dist/compiler/unity.js +10 -9
- package/dist/compiler/unreal.cjs +12 -11
- package/dist/compiler/unreal.js +10 -9
- package/dist/compiler/urdf.cjs +18 -17
- package/dist/compiler/urdf.js +9 -8
- package/dist/compiler/usd-physics.cjs +11 -10
- package/dist/compiler/usd-physics.js +8 -7
- package/dist/compiler/visionos.cjs +11 -10
- package/dist/compiler/visionos.js +10 -9
- package/dist/compiler/vrchat.cjs +11 -10
- package/dist/compiler/vrchat.js +9 -8
- package/dist/compiler/wasm.cjs +14 -13
- package/dist/compiler/wasm.js +9 -8
- package/dist/compiler/webgpu.cjs +10 -9
- package/dist/compiler/webgpu.js +9 -8
- package/dist/constants.cjs +398 -0
- package/dist/constants.js +9 -0
- package/dist/coordinators/index.cjs +4 -1
- package/dist/coordinators/index.js +4 -1
- package/dist/debugger.cjs +11 -9
- package/dist/debugger.js +9 -7
- package/dist/{dist-ACXG6IH5.cjs → dist-GRMOP2UL.cjs} +341 -65
- package/dist/{dist-VD4L6V7Q.js → dist-ZBUKU2JG.js} +333 -63
- package/dist/entries/interop.cjs +23 -23
- package/dist/entries/interop.js +3 -3
- package/dist/entries/scripting.cjs +12 -11
- package/dist/entries/scripting.js +8 -7
- package/dist/evolution/index.cjs +66 -0
- package/dist/evolution/index.d.ts +162 -0
- package/dist/evolution/index.js +17 -0
- package/dist/hololand/index.cjs +41 -37
- package/dist/hololand/index.js +3 -3
- package/dist/index.cjs +12394 -3224
- package/dist/index.d.ts +260 -18
- package/dist/index.js +10755 -2182
- package/dist/keyword-registry/PluginKeywordRegistry.d.ts +138 -0
- package/dist/keyword-registry/index.cjs +29 -0
- package/dist/keyword-registry/index.d.ts +1 -0
- package/dist/keyword-registry/index.js +4 -0
- package/dist/math/tropical-spmv.cjs +11 -11
- package/dist/math/tropical-spmv.d.ts +1 -0
- package/dist/math/tropical-spmv.js +2 -2
- package/dist/math/tropicalSpmv.d.ts +43 -0
- package/dist/math/vec3.cjs +1 -1
- package/dist/math/vec3.js +1 -1
- package/dist/matter/StagedMatter.d.ts +82 -0
- package/dist/matter/index.cjs +17 -0
- package/dist/matter/index.d.ts +1 -0
- package/dist/matter/index.js +4 -0
- package/dist/{ml-dsa-Z7JDKW4L.js → ml-dsa-J6VKVT4K.js} +3 -3
- package/dist/{ml-dsa-FSKBTE3W.cjs → ml-dsa-MTIK4ZUQ.cjs} +23 -23
- package/dist/paper-0c-spike/index.cjs +1 -1
- package/dist/paper-0c-spike/index.js +1 -1
- package/dist/parameter-envelope/ParameterEnvelope.d.ts +128 -0
- package/dist/parameter-envelope/index.cjs +17 -0
- package/dist/parameter-envelope/index.d.ts +2 -0
- package/dist/parameter-envelope/index.js +4 -0
- package/dist/parser/HoloCompositionTypes.d.ts +2013 -0
- package/dist/parser/PipelineParser.d.ts +162 -0
- package/dist/parser.cjs +36 -20
- package/dist/parser.js +13 -9
- package/dist/plugin-manifest/ManifestAutoLoader.d.ts +35 -0
- package/dist/plugin-manifest/PluginManifest.d.ts +156 -0
- package/dist/plugin-manifest/index.cjs +25 -0
- package/dist/plugin-manifest/index.d.ts +2 -0
- package/dist/plugin-manifest/index.js +4 -0
- package/dist/plugin-solver-contract/PluginSolverContract.d.ts +288 -0
- package/dist/plugin-solver-contract/index.cjs +41 -0
- package/dist/plugin-solver-contract/index.d.ts +1 -0
- package/dist/plugin-solver-contract/index.js +4 -0
- package/dist/policy/ContentPolicyGate.d.ts +51 -0
- package/dist/policy/PolicyPack.d.ts +120 -0
- package/dist/policy/blocklist.d.ts +32 -0
- package/dist/policy/defaults.d.ts +44 -0
- package/dist/policy/index.cjs +106 -0
- package/dist/policy/index.d.ts +17 -0
- package/dist/policy/index.js +5 -0
- package/dist/policy/jsonLogic.d.ts +31 -0
- package/dist/policy/types.d.ts +174 -0
- package/dist/proof-composition/ProofCompositionLaw.d.ts +93 -0
- package/dist/proof-composition/index.cjs +25 -0
- package/dist/proof-composition/index.d.ts +1 -0
- package/dist/proof-composition/index.js +4 -0
- package/dist/receipts/hash-policy.d.ts +85 -0
- package/dist/reconstruction/index.cjs +75 -47
- package/dist/reconstruction/index.js +5 -5
- package/dist/runtime/plugin-trait-registrar.d.ts +36 -0
- package/dist/runtime.cjs +81 -79
- package/dist/runtime.js +9 -7
- package/dist/scene-presets-EDKYZ5GW.js +4 -0
- package/dist/scene-presets-NCW2CFRS.cjs +17 -0
- package/dist/self-improvement/index.cjs +1 -1
- package/dist/self-improvement/index.js +1 -1
- package/dist/{src-PT2FERDV.cjs → src-G3D7ZATQ.cjs} +545 -21
- package/dist/{src-J6CM4AUR.js → src-UXYA7HM6.js} +539 -16
- package/dist/storage/index.cjs +10 -10
- package/dist/storage/index.js +3 -3
- package/dist/testing.cjs +1 -1
- package/dist/testing.js +1 -1
- package/dist/tools/index.cjs +3631 -0
- package/dist/tools/index.js +3581 -0
- package/dist/traitDocs/traitDocs.cjs +9 -9
- package/dist/traitDocs/traitDocs.d.ts +1 -0
- package/dist/traitDocs/traitDocs.js +3 -3
- package/dist/traits/ControlLoopTrait.d.ts +154 -0
- package/dist/traits/KinematicChainTrait.d.ts +116 -0
- package/dist/traits/SensorSamplingTrait.d.ts +154 -0
- package/dist/traits/TraitTypes.d.ts +270 -0
- package/dist/traits/TransactionTrait.d.ts +121 -0
- package/dist/traits/botanical-lotus.cjs +54 -50
- package/dist/traits/botanical-lotus.js +2 -5
- package/dist/traits/control-loop.cjs +21 -0
- package/dist/traits/control-loop.d.ts +1 -0
- package/dist/traits/control-loop.js +4 -0
- package/dist/traits/engines/cloth-verlet.d.ts +65 -0
- package/dist/traits/engines/index.cjs +19 -19
- package/dist/traits/engines/index.d.ts +15 -275
- package/dist/traits/engines/index.js +3 -3
- package/dist/traits/engines/motion-data-schema.d.ts +119 -0
- package/dist/traits/engines/motion-matching.d.ts +102 -0
- package/dist/traits/engines/noise.d.ts +25 -0
- package/dist/traits/engines/onnx-adapter.d.ts +173 -0
- package/dist/traits/engines/onnx-motion-matching.d.ts +163 -0
- package/dist/traits/engines/pfnn-network.d.ts +92 -0
- package/dist/traits/engines/synthetic-walk-cycle.d.ts +38 -0
- package/dist/traits/engines/tensor-ops.d.ts +15 -0
- package/dist/traits/index.cjs +2789 -1259
- package/dist/traits/index.d.ts +35 -0
- package/dist/traits/index.js +1692 -411
- package/dist/traits/kinematic-chain.cjs +25 -0
- package/dist/traits/kinematic-chain.d.ts +1 -0
- package/dist/traits/kinematic-chain.js +4 -0
- package/dist/traits/sensor-sampling.cjs +33 -0
- package/dist/traits/sensor-sampling.d.ts +1 -0
- package/dist/traits/sensor-sampling.js +4 -0
- package/dist/traits/simulation-solver-factory.cjs +1 -1
- package/dist/traits/simulation-solver-factory.js +1 -1
- package/dist/traits/transaction.cjs +29 -0
- package/dist/traits/transaction.d.ts +1 -0
- package/dist/traits/transaction.js +4 -0
- package/dist/traits/webcam-gaze.cjs +1 -1
- package/dist/traits/webcam-gaze.js +1 -1
- package/dist/type-checker.cjs +7 -6
- package/dist/type-checker.js +5 -4
- package/dist/types/AdvancedTypeSystem.d.ts +489 -0
- package/dist/types/HoloScriptPlus.d.ts +810 -0
- package/dist/types/base.d.ts +248 -0
- package/dist/types.d.ts +799 -0
- package/dist/world/index.cjs +3 -4
- package/dist/world/index.js +3 -4
- package/dist/world-model/index.cjs +1 -1
- package/dist/world-model/index.js +1 -1
- package/dist/wot/index.cjs +1 -1
- package/dist/wot/index.js +1 -1
- package/package.json +80 -13
- package/dist/GLTFPipeline-3EJLL3TS.cjs +0 -38
- package/dist/GLTFPipeline-3OWJV2VK.js +0 -17
- package/dist/HoloScriptPlusParser-ADWRY5OS.cjs +0 -698
- package/dist/HoloScriptPlusParser-JLJDXHSC.js +0 -693
- package/dist/HoloScriptPlusParser-QCGFPWIL.cjs +0 -27
- package/dist/HoloScriptPlusParser-WENAFEFV.js +0 -10
- package/dist/HoloScriptRuntime-GGRVEU4T.cjs +0 -19
- package/dist/HoloScriptRuntime-GJK6VJPH.js +0 -10
- package/dist/chunk-22Q5A6RV.js +0 -979
- package/dist/chunk-4C57PR42.js +0 -468
- package/dist/chunk-4W5G5QVL.cjs +0 -847
- package/dist/chunk-5ET6L4NS.js +0 -487
- package/dist/chunk-C4GSLCHE.cjs +0 -7153
- package/dist/chunk-F2G6CWFT.js +0 -7089
- package/dist/chunk-G6PNEASF.cjs +0 -814
- package/dist/chunk-GTA4Q3A3.js +0 -1491
- package/dist/chunk-HCCQLAA4.cjs +0 -74
- package/dist/chunk-HFSVMKM3.cjs +0 -72
- package/dist/chunk-KAIVDEIG.cjs +0 -4539
- package/dist/chunk-KQU64CIX.cjs +0 -1508
- package/dist/chunk-MSYSQ2AJ.js +0 -4533
- package/dist/chunk-NHJLP37F.js +0 -70
- package/dist/chunk-NHYRRAGI.cjs +0 -490
- package/dist/chunk-OIQYIIO3.cjs +0 -473
- package/dist/chunk-OL46QLBJ.js +0 -61
- package/dist/chunk-SKZPC5AG.cjs +0 -984
- package/dist/chunk-SLHLXUMO.js +0 -445
- package/dist/chunk-UOIGFQXC.cjs +0 -9750
- package/dist/chunk-UOL6Y5TD.cjs +0 -759
- package/dist/chunk-UVFI7XIR.cjs +0 -452
- package/dist/chunk-VEPGBETF.js +0 -844
- package/dist/chunk-XQ5MWMP2.js +0 -756
- package/dist/chunk-XT6JY5W5.js +0 -9684
- package/dist/chunk-YRRAUB35.js +0 -811
- package/dist/compiler/GasOptimizationAnalyzer.d.ts +0 -73
- package/dist/compiler/NFTMarketplaceCompiler.d.ts +0 -23
- package/dist/compiler/ar.cjs +0 -23
- package/dist/compiler/ar.js +0 -11
- package/dist/compiler/babylon.cjs +0 -21
- package/dist/compiler/babylon.js +0 -15
- package/dist/compiler/multi-layer.cjs +0 -24
- package/dist/compiler/multi-layer.js +0 -15
- package/dist/compiler/playcanvas.cjs +0 -19
- package/dist/compiler/playcanvas.js +0 -13
- package/dist/compiler/r3f.cjs +0 -39
- package/dist/compiler/r3f.d.ts +0 -22
- package/dist/compiler/r3f.js +0 -17
- package/dist/compiler/vrr.cjs +0 -24
- package/dist/compiler/vrr.js +0 -12
- package/dist/parser/NFTMarketplaceTypes.d.ts +0 -191
- package/dist/playwright-3AT3AKTV.cjs +0 -98673
- package/dist/playwright-VZPDVUEQ.js +0 -98660
|
@@ -1,1015 +1,1014 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
3
|
+
var chunkCFVK26P4_cjs = require('./chunk-CFVK26P4.cjs');
|
|
4
|
+
var chunkZK7KX5CD_cjs = require('./chunk-ZK7KX5CD.cjs');
|
|
5
|
+
var chunkAWXFEAQL_cjs = require('./chunk-AWXFEAQL.cjs');
|
|
6
|
+
var chunkN74QRJGP_cjs = require('./chunk-N74QRJGP.cjs');
|
|
7
|
+
var chunkZHPMP447_cjs = require('./chunk-ZHPMP447.cjs');
|
|
8
8
|
var ans = require('@holoscript/core-types/ans');
|
|
9
9
|
|
|
10
|
-
// src/compiler/
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
10
|
+
// src/compiler/AndroidSceneViewFeatureGenerators.ts
|
|
11
|
+
function objectsOf(composition) {
|
|
12
|
+
return composition.objects ?? [];
|
|
13
|
+
}
|
|
14
|
+
function traitsOf(obj) {
|
|
15
|
+
return obj.traits ?? [];
|
|
16
|
+
}
|
|
17
|
+
function traitName(trait) {
|
|
18
|
+
return typeof trait === "string" ? trait : trait.name ?? "";
|
|
19
|
+
}
|
|
20
|
+
function traitConfig(trait) {
|
|
21
|
+
if (!trait || typeof trait === "string") return {};
|
|
22
|
+
return trait.config ?? trait.params ?? {};
|
|
23
|
+
}
|
|
24
|
+
function findTrait(obj, name) {
|
|
25
|
+
return traitsOf(obj).find((trait) => traitName(trait) === name);
|
|
26
|
+
}
|
|
27
|
+
function hasAnyTrait(composition, names) {
|
|
28
|
+
return objectsOf(composition).some(
|
|
29
|
+
(obj) => traitsOf(obj).some((trait) => names.includes(traitName(trait)))
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
function collectUsedTraits(composition, names) {
|
|
33
|
+
const used = /* @__PURE__ */ new Set();
|
|
34
|
+
for (const obj of objectsOf(composition)) {
|
|
35
|
+
for (const trait of traitsOf(obj)) {
|
|
36
|
+
const name = traitName(trait);
|
|
37
|
+
if (names.includes(name)) used.add(name);
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
|
-
return
|
|
40
|
+
return [...used].sort();
|
|
40
41
|
}
|
|
41
|
-
function
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
"geospatial_rooftop_anchor",
|
|
47
|
-
"geospatial_streetscape",
|
|
48
|
-
"geospatial_heading"
|
|
49
|
-
];
|
|
50
|
-
for (const obj of composition.objects || []) {
|
|
51
|
-
for (const trait of obj.traits || []) {
|
|
52
|
-
const name = typeof trait === "string" ? trait : trait.name;
|
|
53
|
-
if (geospatialTraitNames.includes(name)) return true;
|
|
54
|
-
}
|
|
42
|
+
function numberConfig(config, keys, fallback) {
|
|
43
|
+
for (const key of keys) {
|
|
44
|
+
const raw = config[key];
|
|
45
|
+
const numeric = typeof raw === "number" ? raw : Number(raw);
|
|
46
|
+
if (Number.isFinite(numeric)) return numeric;
|
|
55
47
|
}
|
|
56
|
-
return
|
|
48
|
+
return fallback;
|
|
49
|
+
}
|
|
50
|
+
function floatLiteral(value) {
|
|
51
|
+
return `${Number.isInteger(value) ? value.toFixed(0) : value}f`;
|
|
52
|
+
}
|
|
53
|
+
function quotedKotlin(compiler, value) {
|
|
54
|
+
return `"${compiler.escapeStringValue(String(value), "Kotlin")}"`;
|
|
55
|
+
}
|
|
56
|
+
function emitHeader(compiler, composition, title, requirements) {
|
|
57
|
+
compiler.lines = [];
|
|
58
|
+
compiler.indentLevel = 0;
|
|
59
|
+
compiler.emit(`// Auto-generated by HoloScript AndroidCompiler - ${title}`);
|
|
60
|
+
compiler.emit(
|
|
61
|
+
`// Source: composition "${compiler.escapeStringValue(String(composition.name), "Kotlin")}"`
|
|
62
|
+
);
|
|
63
|
+
for (const requirement of requirements) {
|
|
64
|
+
compiler.emit(`// Requires ${requirement}`);
|
|
65
|
+
}
|
|
66
|
+
compiler.emit("// SceneView-native sidecar generated without legacy fragment or node factories.");
|
|
67
|
+
compiler.emit("");
|
|
68
|
+
compiler.emit(`package ${compiler.options.packageName}`);
|
|
69
|
+
compiler.emit("");
|
|
70
|
+
}
|
|
71
|
+
function finish(compiler) {
|
|
72
|
+
return `${compiler.lines.join("\n")}
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
function emitUsedTraits(compiler, used) {
|
|
76
|
+
if (used.length === 0) {
|
|
77
|
+
compiler.emit("private val usedTraits = emptySet<String>()");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
compiler.emit(`private val usedTraits = setOf(${used.map((trait) => `"${trait}"`).join(", ")})`);
|
|
81
|
+
}
|
|
82
|
+
function hasGeoAnchorTraits(composition) {
|
|
83
|
+
return hasAnyTrait(composition, GEO_ANCHOR_TRAITS);
|
|
84
|
+
}
|
|
85
|
+
function hasGeoTraits(composition) {
|
|
86
|
+
return hasGeoAnchorTraits(composition) || hasGeospatialVPSTraits(composition);
|
|
87
|
+
}
|
|
88
|
+
function hasGeospatialVPSTraits(composition) {
|
|
89
|
+
return hasAnyTrait(composition, GEOSPATIAL_TRAITS);
|
|
90
|
+
}
|
|
91
|
+
function hasDepthScanTraits(composition) {
|
|
92
|
+
return hasAnyTrait(composition, chunkAWXFEAQL_cjs.DEPTH_SCANNER_TRAITS);
|
|
93
|
+
}
|
|
94
|
+
function hasPortalARTraits(composition) {
|
|
95
|
+
return hasAnyTrait(composition, chunkN74QRJGP_cjs.PORTAL_AR_TRAITS);
|
|
96
|
+
}
|
|
97
|
+
function hasHandTrackingTraits(composition) {
|
|
98
|
+
return hasAnyTrait(composition, chunkN74QRJGP_cjs.CAMERA_HAND_TRACKING_TRAITS);
|
|
57
99
|
}
|
|
58
100
|
function emitGeoAnchorSetup(compiler, composition) {
|
|
101
|
+
emitHeader(compiler, composition, "SceneView Geo-Anchor Setup", [
|
|
102
|
+
"ARCore Earth anchors",
|
|
103
|
+
"Google Play Services location"
|
|
104
|
+
]);
|
|
105
|
+
compiler.emit("import android.content.Context");
|
|
106
|
+
compiler.emit("import android.util.Log");
|
|
107
|
+
compiler.emit("import com.google.ar.core.Anchor");
|
|
108
|
+
compiler.emit("import com.google.ar.core.Config");
|
|
109
|
+
compiler.emit("import com.google.ar.core.Earth");
|
|
110
|
+
compiler.emit("import com.google.ar.core.Session");
|
|
111
|
+
compiler.emit("import com.google.ar.core.TrackingState");
|
|
59
112
|
compiler.emit("");
|
|
60
|
-
compiler.emit("// === Geo-Anchor: GPS-pinned persistent holograms ===");
|
|
61
113
|
compiler.emit(
|
|
62
|
-
|
|
114
|
+
`class ${compiler.options.className}GeoAnchorManager(private val context: Context) {`
|
|
63
115
|
);
|
|
116
|
+
compiler.indentLevel++;
|
|
117
|
+
emitUsedTraits(compiler, collectUsedTraits(composition, GEO_ANCHOR_TRAITS));
|
|
64
118
|
compiler.emit("private val geoAnchors = mutableMapOf<String, Anchor>()");
|
|
119
|
+
compiler.emit("private val requestedAnchors = listOf(");
|
|
120
|
+
compiler.indentLevel++;
|
|
121
|
+
const anchors = objectsOf(composition).filter((obj) => findTrait(obj, "geo_anchor"));
|
|
122
|
+
if (anchors.length === 0) {
|
|
123
|
+
compiler.emit("// No explicit geo_anchor objects; call createGeoAnchor at runtime.");
|
|
124
|
+
}
|
|
125
|
+
anchors.forEach((obj, index) => {
|
|
126
|
+
const geoConfig = traitConfig(findTrait(obj, "geo_anchor"));
|
|
127
|
+
const altitudeConfig = traitConfig(findTrait(obj, "geo_altitude"));
|
|
128
|
+
const headingConfig = traitConfig(findTrait(obj, "geo_compass_heading"));
|
|
129
|
+
const lat = numberConfig(geoConfig, ["latitude", "lat"], 0);
|
|
130
|
+
const lng = numberConfig(geoConfig, ["longitude", "lng"], 0);
|
|
131
|
+
const altitude = numberConfig(altitudeConfig, ["meters", "altitude"], 0);
|
|
132
|
+
const heading = numberConfig(headingConfig, ["degrees", "heading"], 0);
|
|
133
|
+
compiler.emit(
|
|
134
|
+
`SceneViewGeoAnchor(${quotedKotlin(compiler, obj.name)}, ${lat}, ${lng}, ${altitude}, ${floatLiteral(
|
|
135
|
+
heading
|
|
136
|
+
)})${index === anchors.length - 1 ? "" : ","}`
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
compiler.indentLevel--;
|
|
140
|
+
compiler.emit(")");
|
|
65
141
|
compiler.emit("");
|
|
66
|
-
compiler.emit("
|
|
142
|
+
compiler.emit("fun setupGeoAnchors(session: Session, earth: Earth?) {");
|
|
143
|
+
compiler.indentLevel++;
|
|
144
|
+
compiler.emit("configureSessionForGeospatial(session)");
|
|
145
|
+
compiler.emit("val earthRef = earth ?: return");
|
|
146
|
+
compiler.emit("for (anchor in requestedAnchors) {");
|
|
67
147
|
compiler.indentLevel++;
|
|
68
148
|
compiler.emit(
|
|
69
|
-
"
|
|
149
|
+
"createGeoAnchor(anchor.name, earthRef, anchor.latitude, anchor.longitude, anchor.altitude, anchor.heading)"
|
|
70
150
|
);
|
|
71
|
-
compiler.
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
compiler.emit("
|
|
75
|
-
compiler.emit("val session = arFragment.arSceneView.session ?: return");
|
|
76
|
-
compiler.emit("val config = session.config");
|
|
77
|
-
compiler.emit("config.geospatialMode = Config.GeospatialMode.ENABLED");
|
|
78
|
-
compiler.emit("session.configure(config)");
|
|
79
|
-
compiler.emit("");
|
|
80
|
-
}
|
|
81
|
-
for (const obj of composition.objects || []) {
|
|
82
|
-
const traits = obj.traits || [];
|
|
83
|
-
const hasGeoAnchor = traits.some((t) => {
|
|
84
|
-
const name = typeof t === "string" ? t : t.name;
|
|
85
|
-
return name === "geo_anchor";
|
|
86
|
-
});
|
|
87
|
-
if (!hasGeoAnchor) continue;
|
|
88
|
-
const geoAnchorTrait = traits.find((t) => {
|
|
89
|
-
const name = typeof t === "string" ? t : t.name;
|
|
90
|
-
return name === "geo_anchor";
|
|
91
|
-
});
|
|
92
|
-
const config = typeof geoAnchorTrait === "string" ? {} : geoAnchorTrait?.config || {};
|
|
93
|
-
const lat = config.latitude ?? 0;
|
|
94
|
-
const lng = config.longitude ?? 0;
|
|
95
|
-
const altTrait = traits.find((t) => {
|
|
96
|
-
const name = typeof t === "string" ? t : t.name;
|
|
97
|
-
return name === "geo_altitude";
|
|
98
|
-
});
|
|
99
|
-
const altConfig = typeof altTrait === "string" ? {} : altTrait?.config || {};
|
|
100
|
-
const alt = altConfig.meters ?? 0;
|
|
101
|
-
const headingTrait = traits.find((t) => {
|
|
102
|
-
const name = typeof t === "string" ? t : t.name;
|
|
103
|
-
return name === "geo_compass_heading";
|
|
104
|
-
});
|
|
105
|
-
const headingConfig = typeof headingTrait === "string" ? {} : headingTrait?.config || {};
|
|
106
|
-
const heading = headingConfig.degrees ?? 0;
|
|
107
|
-
compiler.emit(`// Geo-anchor: ${compiler.escapeStringValue(obj.name, "Kotlin")}`);
|
|
108
|
-
compiler.emit(
|
|
109
|
-
`createGeoAnchor("${compiler.escapeStringValue(obj.name, "Kotlin")}", ${lat}, ${lng}, ${alt}, ${heading}f)`
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
const usesPersist = compiler.compositionHasTrait(composition, "geo_persist");
|
|
113
|
-
const usesCloud = compiler.compositionHasTrait(composition, "geo_cloud_anchor");
|
|
114
|
-
if (usesPersist || usesCloud) {
|
|
115
|
-
compiler.emit("");
|
|
116
|
-
compiler.emit("// Restore persisted geo anchors");
|
|
117
|
-
compiler.emit("restoreGeoAnchors()");
|
|
151
|
+
compiler.indentLevel--;
|
|
152
|
+
compiler.emit("}");
|
|
153
|
+
if (compiler.compositionHasTrait(composition, "geo_persist")) {
|
|
154
|
+
compiler.emit("restoreGeoAnchors { name, restored -> geoAnchors[name] = restored }");
|
|
118
155
|
}
|
|
119
156
|
compiler.indentLevel--;
|
|
120
157
|
compiler.emit("}");
|
|
121
158
|
compiler.emit("");
|
|
159
|
+
compiler.emit("fun configureSessionForGeospatial(session: Session) {");
|
|
160
|
+
compiler.indentLevel++;
|
|
161
|
+
compiler.emit("val config = session.config");
|
|
162
|
+
compiler.emit("config.geospatialMode = Config.GeospatialMode.ENABLED");
|
|
163
|
+
compiler.emit("session.configure(config)");
|
|
164
|
+
compiler.indentLevel--;
|
|
165
|
+
compiler.emit("}");
|
|
166
|
+
compiler.emit("");
|
|
122
167
|
compiler.emit(
|
|
123
|
-
"
|
|
168
|
+
"fun createGeoAnchor(name: String, earth: Earth, latitude: Double, longitude: Double, altitude: Double, heading: Float): Anchor? {"
|
|
124
169
|
);
|
|
125
170
|
compiler.indentLevel++;
|
|
126
|
-
compiler.emit("
|
|
127
|
-
compiler.emit("val
|
|
128
|
-
compiler.emit("if (earth.trackingState != TrackingState.TRACKING) return");
|
|
129
|
-
compiler.emit("");
|
|
171
|
+
compiler.emit("if (earth.trackingState != TrackingState.TRACKING) return null");
|
|
172
|
+
compiler.emit("val halfRadians = Math.toRadians(heading.toDouble()) / 2.0");
|
|
130
173
|
compiler.emit(
|
|
131
|
-
"val anchor = earth.createAnchor(
|
|
174
|
+
"val anchor = earth.createAnchor(latitude, longitude, altitude, 0f, 0f, Math.sin(halfRadians).toFloat(), Math.cos(halfRadians).toFloat())"
|
|
132
175
|
);
|
|
133
176
|
compiler.emit("geoAnchors[name] = anchor");
|
|
177
|
+
compiler.emit('Log.d("HoloScript", "SceneView geo anchor created: " + name)');
|
|
178
|
+
if (compiler.compositionHasTrait(composition, "geo_cloud_anchor") || compiler.compositionHasTrait(composition, "geo_persist")) {
|
|
179
|
+
compiler.emit('saveGeoAnchorToCloud(name, anchor.cloudAnchorId ?: "")');
|
|
180
|
+
}
|
|
181
|
+
compiler.emit("return anchor");
|
|
182
|
+
compiler.indentLevel--;
|
|
183
|
+
compiler.emit("}");
|
|
134
184
|
compiler.emit("");
|
|
135
|
-
compiler.emit("
|
|
136
|
-
compiler.emit("anchorNode.setParent(arFragment.arSceneView.scene)");
|
|
137
|
-
compiler.emit("");
|
|
138
|
-
compiler.emit("NodeFactory.createDefaultNode(this) { renderable ->");
|
|
185
|
+
compiler.emit("fun saveGeoAnchorToCloud(name: String, cloudAnchorId: String) {");
|
|
139
186
|
compiler.indentLevel++;
|
|
140
|
-
compiler.emit(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
compiler.emit("placedNodes[name] = node");
|
|
144
|
-
compiler.emit('android.util.Log.d("HoloScript", "Geo-anchored: $name at ($lat, $lng, $alt)")');
|
|
187
|
+
compiler.emit(
|
|
188
|
+
'context.getSharedPreferences("sceneview_geo_anchors", Context.MODE_PRIVATE).edit().putString(name, cloudAnchorId).apply()'
|
|
189
|
+
);
|
|
145
190
|
compiler.indentLevel--;
|
|
146
191
|
compiler.emit("}");
|
|
192
|
+
compiler.emit("");
|
|
193
|
+
compiler.emit("fun restoreGeoAnchors(onRestore: (String, Anchor) -> Unit) {");
|
|
194
|
+
compiler.indentLevel++;
|
|
195
|
+
compiler.emit(
|
|
196
|
+
"// Cloud anchor resolution is provided by the app shell when network policy is available."
|
|
197
|
+
);
|
|
198
|
+
compiler.emit(
|
|
199
|
+
'Log.d("HoloScript", "restoreGeoAnchors requested for " + usedTraits.joinToString())'
|
|
200
|
+
);
|
|
147
201
|
compiler.indentLevel--;
|
|
148
202
|
compiler.emit("}");
|
|
149
203
|
compiler.emit("");
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
compiler.emit("if (state == Anchor.CloudAnchorState.SUCCESS && cloudId != null) {");
|
|
157
|
-
compiler.indentLevel++;
|
|
158
|
-
compiler.emit('val prefs = getSharedPreferences("geo_anchors", MODE_PRIVATE)');
|
|
159
|
-
compiler.emit("prefs.edit().putString(name, cloudId).apply()");
|
|
160
|
-
compiler.emit('android.util.Log.d("HoloScript", "Cloud anchor saved: $name -> $cloudId")');
|
|
161
|
-
compiler.indentLevel--;
|
|
162
|
-
compiler.emit("}");
|
|
163
|
-
compiler.indentLevel--;
|
|
164
|
-
compiler.emit("}");
|
|
165
|
-
compiler.indentLevel--;
|
|
166
|
-
compiler.emit("}");
|
|
167
|
-
compiler.emit("");
|
|
168
|
-
compiler.emit("private fun restoreGeoAnchors() {");
|
|
169
|
-
compiler.indentLevel++;
|
|
170
|
-
compiler.emit('val prefs = getSharedPreferences("geo_anchors", MODE_PRIVATE)');
|
|
171
|
-
compiler.emit("val session = arFragment.arSceneView.session ?: return");
|
|
172
|
-
compiler.emit("for ((name, cloudId) in prefs.all) {");
|
|
173
|
-
compiler.indentLevel++;
|
|
174
|
-
compiler.emit("val id = cloudId as? String ?: continue");
|
|
175
|
-
compiler.emit("session.resolveCloudAnchorAsync(id) { anchor, state ->");
|
|
176
|
-
compiler.indentLevel++;
|
|
177
|
-
compiler.emit("if (state == Anchor.CloudAnchorState.SUCCESS && anchor != null) {");
|
|
178
|
-
compiler.indentLevel++;
|
|
179
|
-
compiler.emit("geoAnchors[name] = anchor");
|
|
180
|
-
compiler.emit("val anchorNode = AnchorNode(anchor)");
|
|
181
|
-
compiler.emit("anchorNode.setParent(arFragment.arSceneView.scene)");
|
|
182
|
-
compiler.emit('android.util.Log.d("HoloScript", "Restored cloud anchor: $name")');
|
|
183
|
-
compiler.indentLevel--;
|
|
184
|
-
compiler.emit("}");
|
|
185
|
-
compiler.indentLevel--;
|
|
186
|
-
compiler.emit("}");
|
|
187
|
-
compiler.indentLevel--;
|
|
188
|
-
compiler.emit("}");
|
|
189
|
-
compiler.indentLevel--;
|
|
190
|
-
compiler.emit("}");
|
|
191
|
-
compiler.emit("");
|
|
192
|
-
}
|
|
204
|
+
compiler.emit(
|
|
205
|
+
"data class SceneViewGeoAnchor(val name: String, val latitude: Double, val longitude: Double, val altitude: Double, val heading: Float)"
|
|
206
|
+
);
|
|
207
|
+
compiler.indentLevel--;
|
|
208
|
+
compiler.emit("}");
|
|
209
|
+
return finish(compiler);
|
|
193
210
|
}
|
|
194
211
|
function emitGeospatialVPSSetup(compiler, composition) {
|
|
212
|
+
emitHeader(compiler, composition, "SceneView Geospatial VPS Setup", [
|
|
213
|
+
"ARCore GeospatialMode",
|
|
214
|
+
"Google Play Services location"
|
|
215
|
+
]);
|
|
216
|
+
compiler.emit("import android.util.Log");
|
|
217
|
+
compiler.emit("import com.google.ar.core.Anchor");
|
|
218
|
+
compiler.emit("import com.google.ar.core.Config");
|
|
219
|
+
compiler.emit("import com.google.ar.core.Earth");
|
|
220
|
+
compiler.emit("import com.google.ar.core.Session");
|
|
221
|
+
compiler.emit("import com.google.ar.core.StreetscapeGeometry");
|
|
222
|
+
compiler.emit("import com.google.ar.core.TrackingState");
|
|
195
223
|
compiler.emit("");
|
|
196
|
-
compiler.emit(
|
|
224
|
+
compiler.emit(`class ${compiler.options.className}GeospatialVPSManager {`);
|
|
225
|
+
compiler.indentLevel++;
|
|
226
|
+
emitUsedTraits(compiler, collectUsedTraits(composition, GEOSPATIAL_TRAITS));
|
|
197
227
|
compiler.emit("private var earth: Earth? = null");
|
|
198
228
|
compiler.emit("private val geospatialAnchors = mutableMapOf<String, Anchor>()");
|
|
229
|
+
compiler.emit(
|
|
230
|
+
`private val horizontalAccuracyThreshold = ${chunkAWXFEAQL_cjs.GEOSPATIAL_DEFAULTS.vps.accuracyThreshold}.0`
|
|
231
|
+
);
|
|
232
|
+
compiler.emit(
|
|
233
|
+
`private val headingAccuracyThreshold = ${chunkAWXFEAQL_cjs.GEOSPATIAL_DEFAULTS.vps.headingAccuracyThreshold}.0`
|
|
234
|
+
);
|
|
199
235
|
compiler.emit("");
|
|
200
|
-
compiler.emit("
|
|
236
|
+
compiler.emit("fun setupGeospatialVPS(session: Session) {");
|
|
201
237
|
compiler.indentLevel++;
|
|
202
|
-
compiler.emit("val session = arFragment.arSceneView.session ?: return");
|
|
203
238
|
compiler.emit("val config = session.config");
|
|
204
239
|
compiler.emit("config.geospatialMode = Config.GeospatialMode.ENABLED");
|
|
205
|
-
|
|
206
|
-
if (usesStreetscape) {
|
|
240
|
+
if (compiler.compositionHasTrait(composition, "geospatial_streetscape")) {
|
|
207
241
|
compiler.emit("config.streetscapeGeometryMode = Config.StreetscapeGeometryMode.ENABLED");
|
|
208
242
|
}
|
|
209
243
|
compiler.emit("session.configure(config)");
|
|
244
|
+
compiler.emit("earth = session.earth");
|
|
245
|
+
compiler.indentLevel--;
|
|
246
|
+
compiler.emit("}");
|
|
210
247
|
compiler.emit("");
|
|
211
|
-
compiler.emit("
|
|
212
|
-
compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener {");
|
|
248
|
+
compiler.emit("fun updateEarthTracking(session: Session) {");
|
|
213
249
|
compiler.indentLevel++;
|
|
214
|
-
compiler.emit("
|
|
215
|
-
compiler.emit("
|
|
216
|
-
compiler.emit("
|
|
217
|
-
compiler.emit("
|
|
218
|
-
compiler.emit("");
|
|
219
|
-
compiler.emit("val geospatialState = earth?.cameraGeospatialPose ?: return@addOnUpdateListener");
|
|
250
|
+
compiler.emit("earth = session.earth");
|
|
251
|
+
compiler.emit("val earthRef = earth ?: return");
|
|
252
|
+
compiler.emit("if (earthRef.trackingState != TrackingState.TRACKING) return");
|
|
253
|
+
compiler.emit("val geospatialState = earthRef.cameraGeospatialPose");
|
|
220
254
|
compiler.emit("val horizontalAccuracy = geospatialState.horizontalAccuracy");
|
|
221
255
|
compiler.emit("val headingAccuracy = geospatialState.headingAccuracy");
|
|
256
|
+
compiler.emit(
|
|
257
|
+
"if (horizontalAccuracy > horizontalAccuracyThreshold || headingAccuracy > headingAccuracyThreshold) return"
|
|
258
|
+
);
|
|
259
|
+
compiler.emit('Log.d("HoloScript", "cameraGeospatialPose localized")');
|
|
260
|
+
if (compiler.compositionHasTrait(composition, "geospatial_streetscape")) {
|
|
261
|
+
compiler.emit("processStreetscapeGeometry(session)");
|
|
262
|
+
}
|
|
263
|
+
compiler.indentLevel--;
|
|
264
|
+
compiler.emit("}");
|
|
222
265
|
compiler.emit("");
|
|
223
266
|
compiler.emit(
|
|
224
|
-
|
|
267
|
+
"fun createGeospatialAnchor(name: String, lat: Double, lng: Double, alt: Double, heading: Float): Anchor? {"
|
|
225
268
|
);
|
|
226
269
|
compiler.indentLevel++;
|
|
227
|
-
compiler.emit("
|
|
228
|
-
compiler.emit("return
|
|
270
|
+
compiler.emit("val earthRef = earth ?: return null");
|
|
271
|
+
compiler.emit("if (earthRef.trackingState != TrackingState.TRACKING) return null");
|
|
272
|
+
compiler.emit("val halfRadians = Math.toRadians(heading.toDouble()) / 2.0");
|
|
273
|
+
compiler.emit(
|
|
274
|
+
"val anchor = earthRef.createAnchor(lat, lng, alt, 0f, 0f, Math.sin(halfRadians).toFloat(), Math.cos(halfRadians).toFloat())"
|
|
275
|
+
);
|
|
276
|
+
compiler.emit("geospatialAnchors[name] = anchor");
|
|
277
|
+
compiler.emit("return anchor");
|
|
229
278
|
compiler.indentLevel--;
|
|
230
279
|
compiler.emit("}");
|
|
231
280
|
compiler.emit("");
|
|
232
281
|
compiler.emit(
|
|
233
|
-
|
|
282
|
+
"fun resolveTerrainAnchor(name: String, lat: Double, lng: Double, altitudeOffset: Double, heading: Float) {"
|
|
283
|
+
);
|
|
284
|
+
compiler.indentLevel++;
|
|
285
|
+
compiler.emit("val earthRef = earth ?: return");
|
|
286
|
+
compiler.emit("val halfRadians = Math.toRadians(heading.toDouble()) / 2.0");
|
|
287
|
+
compiler.emit(
|
|
288
|
+
"earthRef.resolveAnchorOnTerrainAsync(lat, lng, altitudeOffset, 0f, Math.sin(halfRadians).toFloat(), 0f, Math.cos(halfRadians).toFloat()) { anchor, state ->"
|
|
289
|
+
);
|
|
290
|
+
compiler.indentLevel++;
|
|
291
|
+
compiler.emit(
|
|
292
|
+
"if (state == Anchor.TerrainAnchorState.SUCCESS && anchor != null) geospatialAnchors[name] = anchor"
|
|
234
293
|
);
|
|
235
|
-
if (usesStreetscape) {
|
|
236
|
-
compiler.emit("");
|
|
237
|
-
compiler.emit("// Process Streetscape Geometry meshes");
|
|
238
|
-
compiler.emit("processStreetscapeGeometry(sessionRef)");
|
|
239
|
-
}
|
|
240
294
|
compiler.indentLevel--;
|
|
241
295
|
compiler.emit("}");
|
|
242
296
|
compiler.indentLevel--;
|
|
243
297
|
compiler.emit("}");
|
|
244
298
|
compiler.emit("");
|
|
245
299
|
compiler.emit(
|
|
246
|
-
"
|
|
300
|
+
"fun resolveRooftopAnchor(name: String, lat: Double, lng: Double, altitudeOffset: Double, heading: Float) {"
|
|
247
301
|
);
|
|
248
302
|
compiler.indentLevel++;
|
|
249
303
|
compiler.emit("val earthRef = earth ?: return");
|
|
250
|
-
compiler.emit("
|
|
251
|
-
compiler.emit("");
|
|
304
|
+
compiler.emit("val halfRadians = Math.toRadians(heading.toDouble()) / 2.0");
|
|
252
305
|
compiler.emit(
|
|
253
|
-
"
|
|
306
|
+
"earthRef.resolveAnchorOnRooftopAsync(lat, lng, altitudeOffset, 0f, Math.sin(halfRadians).toFloat(), 0f, Math.cos(halfRadians).toFloat()) { anchor, state ->"
|
|
254
307
|
);
|
|
255
|
-
compiler.emit("geospatialAnchors[name] = anchor");
|
|
256
|
-
compiler.emit("");
|
|
257
|
-
compiler.emit("val anchorNode = AnchorNode(anchor)");
|
|
258
|
-
compiler.emit("anchorNode.setParent(arFragment.arSceneView.scene)");
|
|
259
|
-
compiler.emit("");
|
|
260
|
-
compiler.emit("NodeFactory.createDefaultNode(this) { renderable ->");
|
|
261
308
|
compiler.indentLevel++;
|
|
262
|
-
compiler.emit("val node = TransformableNode(arFragment.transformationSystem)");
|
|
263
|
-
compiler.emit("node.setParent(anchorNode)");
|
|
264
|
-
compiler.emit("node.renderable = renderable");
|
|
265
|
-
compiler.emit("placedNodes[name] = node");
|
|
266
309
|
compiler.emit(
|
|
267
|
-
|
|
310
|
+
"if (state == Anchor.RooftopAnchorState.SUCCESS && anchor != null) geospatialAnchors[name] = anchor"
|
|
268
311
|
);
|
|
269
312
|
compiler.indentLevel--;
|
|
270
313
|
compiler.emit("}");
|
|
271
314
|
compiler.indentLevel--;
|
|
272
315
|
compiler.emit("}");
|
|
273
316
|
compiler.emit("");
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
compiler.indentLevel++;
|
|
293
|
-
compiler.emit("geospatialAnchors[name] = anchor");
|
|
294
|
-
compiler.emit("val anchorNode = AnchorNode(anchor)");
|
|
295
|
-
compiler.emit("anchorNode.setParent(arFragment.arSceneView.scene)");
|
|
296
|
-
compiler.emit("");
|
|
297
|
-
compiler.emit(
|
|
298
|
-
"NodeFactory.createDefaultNode(this@" + compiler.options.className + "Activity) { renderable ->"
|
|
299
|
-
);
|
|
300
|
-
compiler.indentLevel++;
|
|
301
|
-
compiler.emit("val node = TransformableNode(arFragment.transformationSystem)");
|
|
302
|
-
compiler.emit("node.setParent(anchorNode)");
|
|
303
|
-
compiler.emit("node.renderable = renderable");
|
|
304
|
-
compiler.emit("placedNodes[name] = node");
|
|
305
|
-
compiler.emit('android.util.Log.d("HoloScript", "Terrain anchor resolved: $name")');
|
|
306
|
-
compiler.indentLevel--;
|
|
307
|
-
compiler.emit("}");
|
|
308
|
-
compiler.indentLevel--;
|
|
309
|
-
compiler.emit("}");
|
|
310
|
-
compiler.indentLevel--;
|
|
311
|
-
compiler.emit("}");
|
|
312
|
-
compiler.indentLevel--;
|
|
313
|
-
compiler.emit("}");
|
|
314
|
-
compiler.emit("");
|
|
315
|
-
}
|
|
316
|
-
if (compiler.compositionHasTrait(composition, "geospatial_rooftop_anchor")) {
|
|
317
|
-
compiler.emit(
|
|
318
|
-
"private fun resolveRooftopAnchor(name: String, lat: Double, lng: Double, altOffset: Double, heading: Float) {"
|
|
319
|
-
);
|
|
320
|
-
compiler.indentLevel++;
|
|
321
|
-
compiler.emit("val earthRef = earth ?: return");
|
|
322
|
-
compiler.emit("if (earthRef.trackingState != TrackingState.TRACKING) return");
|
|
323
|
-
compiler.emit("");
|
|
324
|
-
compiler.emit("val qx = 0f");
|
|
325
|
-
compiler.emit("val qy = Math.sin(Math.toRadians(heading.toDouble() / 2)).toFloat()");
|
|
326
|
-
compiler.emit("val qz = 0f");
|
|
327
|
-
compiler.emit("val qw = Math.cos(Math.toRadians(heading.toDouble() / 2)).toFloat()");
|
|
328
|
-
compiler.emit("");
|
|
329
|
-
compiler.emit(
|
|
330
|
-
"earthRef.resolveAnchorOnRooftopAsync(lat, lng, altOffset, qx, qy, qz, qw) { anchor, state ->"
|
|
331
|
-
);
|
|
332
|
-
compiler.indentLevel++;
|
|
333
|
-
compiler.emit("if (state == Anchor.RooftopAnchorState.SUCCESS && anchor != null) {");
|
|
334
|
-
compiler.indentLevel++;
|
|
335
|
-
compiler.emit("geospatialAnchors[name] = anchor");
|
|
336
|
-
compiler.emit("val anchorNode = AnchorNode(anchor)");
|
|
337
|
-
compiler.emit("anchorNode.setParent(arFragment.arSceneView.scene)");
|
|
338
|
-
compiler.emit("");
|
|
339
|
-
compiler.emit(
|
|
340
|
-
"NodeFactory.createDefaultNode(this@" + compiler.options.className + "Activity) { renderable ->"
|
|
341
|
-
);
|
|
342
|
-
compiler.indentLevel++;
|
|
343
|
-
compiler.emit("val node = TransformableNode(arFragment.transformationSystem)");
|
|
344
|
-
compiler.emit("node.setParent(anchorNode)");
|
|
345
|
-
compiler.emit("node.renderable = renderable");
|
|
346
|
-
compiler.emit("placedNodes[name] = node");
|
|
347
|
-
compiler.emit('android.util.Log.d("HoloScript", "Rooftop anchor resolved: $name")');
|
|
348
|
-
compiler.indentLevel--;
|
|
349
|
-
compiler.emit("}");
|
|
350
|
-
compiler.indentLevel--;
|
|
351
|
-
compiler.emit("}");
|
|
352
|
-
compiler.indentLevel--;
|
|
353
|
-
compiler.emit("}");
|
|
354
|
-
compiler.indentLevel--;
|
|
355
|
-
compiler.emit("}");
|
|
356
|
-
compiler.emit("");
|
|
357
|
-
}
|
|
358
|
-
if (usesStreetscape) {
|
|
359
|
-
compiler.emit("private fun processStreetscapeGeometry(session: Session) {");
|
|
360
|
-
compiler.indentLevel++;
|
|
361
|
-
compiler.emit(
|
|
362
|
-
"val streetscapeGeometries = session.getAllTrackables(StreetscapeGeometry::class.java)"
|
|
363
|
-
);
|
|
364
|
-
compiler.emit("for (geometry in streetscapeGeometries) {");
|
|
365
|
-
compiler.indentLevel++;
|
|
366
|
-
compiler.emit("if (geometry.trackingState != TrackingState.TRACKING) continue");
|
|
367
|
-
compiler.emit("");
|
|
368
|
-
compiler.emit("val mesh = geometry.meshes.firstOrNull() ?: continue");
|
|
369
|
-
compiler.emit("val type = geometry.type");
|
|
370
|
-
compiler.emit(
|
|
371
|
-
'android.util.Log.d("HoloScript", "Streetscape geometry: type=$type, vertices=${mesh.vertexList.size}")'
|
|
372
|
-
);
|
|
373
|
-
compiler.emit("");
|
|
374
|
-
compiler.emit("// Streetscape mesh available for occlusion, raycasting, or rendering");
|
|
375
|
-
compiler.emit("// Type is TERRAIN or BUILDING");
|
|
376
|
-
compiler.indentLevel--;
|
|
377
|
-
compiler.emit("}");
|
|
378
|
-
compiler.indentLevel--;
|
|
379
|
-
compiler.emit("}");
|
|
380
|
-
compiler.emit("");
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
function hasDepthScanTraits(composition) {
|
|
384
|
-
for (const obj of composition.objects || []) {
|
|
385
|
-
for (const trait of obj.traits || []) {
|
|
386
|
-
const name = typeof trait === "string" ? trait : trait.name;
|
|
387
|
-
if (chunkDTGBOSEM_cjs.DEPTH_SCANNER_TRAITS.includes(name)) return true;
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
return false;
|
|
317
|
+
compiler.emit("fun processStreetscapeGeometry(session: Session) {");
|
|
318
|
+
compiler.indentLevel++;
|
|
319
|
+
compiler.emit("val geometries = session.getAllTrackables(StreetscapeGeometry::class.java)");
|
|
320
|
+
compiler.emit("for (geometry in geometries) {");
|
|
321
|
+
compiler.indentLevel++;
|
|
322
|
+
compiler.emit("if (geometry.trackingState != TrackingState.TRACKING) continue");
|
|
323
|
+
compiler.emit('Log.d("HoloScript", "Streetscape geometry: " + geometry.type)');
|
|
324
|
+
compiler.indentLevel--;
|
|
325
|
+
compiler.emit("}");
|
|
326
|
+
compiler.indentLevel--;
|
|
327
|
+
compiler.emit("}");
|
|
328
|
+
compiler.emit("");
|
|
329
|
+
compiler.emit(
|
|
330
|
+
"data class SceneViewGeospatialAnchor(val name: String, val latitude: Double, val longitude: Double, val altitude: Double, val heading: Float)"
|
|
331
|
+
);
|
|
332
|
+
compiler.indentLevel--;
|
|
333
|
+
compiler.emit("}");
|
|
334
|
+
return finish(compiler);
|
|
391
335
|
}
|
|
392
336
|
function emitDepthScanSetup(compiler, composition) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
compiler.emit(
|
|
401
|
-
compiler.
|
|
337
|
+
emitHeader(compiler, composition, "SceneView Depth Scanner Setup", ["ARCore Depth API"]);
|
|
338
|
+
compiler.emit("import android.media.Image");
|
|
339
|
+
compiler.emit("import android.util.Log");
|
|
340
|
+
compiler.emit("import com.google.ar.core.Config");
|
|
341
|
+
compiler.emit("import com.google.ar.core.Frame");
|
|
342
|
+
compiler.emit("import com.google.ar.core.Session");
|
|
343
|
+
compiler.emit("");
|
|
344
|
+
compiler.emit(`class ${compiler.options.className}DepthScanner {`);
|
|
345
|
+
compiler.indentLevel++;
|
|
346
|
+
emitUsedTraits(compiler, collectUsedTraits(composition, chunkAWXFEAQL_cjs.DEPTH_SCANNER_TRAITS));
|
|
402
347
|
compiler.emit(
|
|
403
|
-
`private val depthConfidenceThreshold = ${
|
|
348
|
+
`private val depthConfidenceThreshold = ${chunkAWXFEAQL_cjs.DEPTH_SCANNER_DEFAULTS.scan.confidenceThreshold}`
|
|
349
|
+
);
|
|
350
|
+
compiler.emit(
|
|
351
|
+
`private val depthMaxMeters = ${floatLiteral(chunkAWXFEAQL_cjs.DEPTH_SCANNER_DEFAULTS.scan.maxDepthMeters)}`
|
|
352
|
+
);
|
|
353
|
+
compiler.emit(
|
|
354
|
+
`private val depthMeshDecimation = ${floatLiteral(chunkAWXFEAQL_cjs.DEPTH_SCANNER_DEFAULTS.scan.meshDecimation)}`
|
|
404
355
|
);
|
|
405
|
-
compiler.emit(`private val depthMaxMeters = ${chunkDTGBOSEM_cjs.DEPTH_SCANNER_DEFAULTS.scan.maxDepthMeters}f`);
|
|
406
|
-
compiler.emit(`private val depthMeshDecimation = ${chunkDTGBOSEM_cjs.DEPTH_SCANNER_DEFAULTS.scan.meshDecimation}f`);
|
|
407
|
-
compiler.emit("private var depthImage: android.media.Image? = null");
|
|
408
|
-
if (hasConfidence) {
|
|
409
|
-
compiler.emit("private var depthConfidenceImage: android.media.Image? = null");
|
|
410
|
-
}
|
|
411
356
|
compiler.emit("");
|
|
412
|
-
compiler.emit("
|
|
357
|
+
compiler.emit("fun setupDepthScanner(session: Session) = configureDepthSession(session)");
|
|
358
|
+
compiler.emit("");
|
|
359
|
+
compiler.emit("fun configureDepthSession(session: Session) {");
|
|
413
360
|
compiler.indentLevel++;
|
|
414
|
-
compiler.emit("val session = arFragment.arSceneView.session ?: return");
|
|
415
|
-
compiler.emit("val config = session.config");
|
|
416
361
|
compiler.emit("if (!session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) {");
|
|
417
362
|
compiler.indentLevel++;
|
|
418
|
-
compiler.emit(
|
|
419
|
-
'android.util.Log.w("HoloScript", "Depth scanner unavailable: ARCore DepthMode.AUTOMATIC is not supported on this device")'
|
|
420
|
-
);
|
|
363
|
+
compiler.emit('Log.w("HoloScript", "ARCore DepthMode.AUTOMATIC is unavailable")');
|
|
421
364
|
compiler.emit("return");
|
|
422
365
|
compiler.indentLevel--;
|
|
423
366
|
compiler.emit("}");
|
|
367
|
+
compiler.emit("val config = session.config");
|
|
424
368
|
compiler.emit("config.depthMode = Config.DepthMode.AUTOMATIC");
|
|
425
369
|
compiler.emit("session.configure(config)");
|
|
426
|
-
compiler.
|
|
370
|
+
compiler.indentLevel--;
|
|
371
|
+
compiler.emit("}");
|
|
427
372
|
compiler.emit("");
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
373
|
+
compiler.emit("fun processDepthFrame(frame: Frame): List<DepthPoint> {");
|
|
374
|
+
compiler.indentLevel++;
|
|
375
|
+
compiler.emit("val depthImage = frame.acquireDepthImage16Bits()");
|
|
376
|
+
compiler.emit("val confidenceImage = acquireConfidenceImage(frame)");
|
|
377
|
+
compiler.emit("val source = detectDepthSource()");
|
|
378
|
+
compiler.emit("val mesh = generateMeshFromDepth(depthImage, confidenceImage, source)");
|
|
379
|
+
if (compiler.compositionHasTrait(composition, "depth_mesh_to_holo")) {
|
|
380
|
+
compiler.emit("convertDepthMeshToHolo(mesh)");
|
|
432
381
|
}
|
|
433
|
-
if (
|
|
434
|
-
compiler.emit("
|
|
435
|
-
compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener { _ ->");
|
|
436
|
-
compiler.indentLevel++;
|
|
437
|
-
compiler.emit("val frame = arFragment.arSceneView.arFrame ?: return@addOnUpdateListener");
|
|
438
|
-
compiler.emit("processDepthFrame(frame)");
|
|
439
|
-
compiler.indentLevel--;
|
|
440
|
-
compiler.emit("}");
|
|
382
|
+
if (compiler.compositionHasTrait(composition, "depth_export")) {
|
|
383
|
+
compiler.emit("exportDepthMesh(mesh)");
|
|
441
384
|
}
|
|
385
|
+
compiler.emit("depthImage.close()");
|
|
386
|
+
compiler.emit("confidenceImage?.close()");
|
|
387
|
+
compiler.emit("return mesh");
|
|
442
388
|
compiler.indentLevel--;
|
|
443
389
|
compiler.emit("}");
|
|
444
390
|
compiler.emit("");
|
|
445
|
-
compiler.emit("private fun
|
|
391
|
+
compiler.emit("private fun acquireConfidenceImage(frame: Frame): Image? = try {");
|
|
446
392
|
compiler.indentLevel++;
|
|
447
|
-
compiler.emit("
|
|
393
|
+
compiler.emit("frame.acquireRawDepthConfidenceImage()");
|
|
394
|
+
compiler.indentLevel--;
|
|
395
|
+
compiler.emit("} catch (_: Throwable) {");
|
|
448
396
|
compiler.indentLevel++;
|
|
449
|
-
|
|
450
|
-
compiler.emit("// ARCore ML depth: acquire 16-bit depth image");
|
|
451
|
-
compiler.emit("depthImage?.close()");
|
|
452
|
-
compiler.emit("depthImage = frame.acquireDepthImage16Bits()");
|
|
453
|
-
} else {
|
|
454
|
-
compiler.emit("depthImage?.close()");
|
|
455
|
-
compiler.emit("depthImage = frame.acquireDepthImage16Bits()");
|
|
456
|
-
}
|
|
457
|
-
if (hasConfidence) {
|
|
458
|
-
compiler.emit("");
|
|
459
|
-
compiler.emit("// Confidence map: per-pixel confidence (0-255)");
|
|
460
|
-
compiler.emit("depthConfidenceImage?.close()");
|
|
461
|
-
compiler.emit("depthConfidenceImage = frame.acquireRawDepthConfidenceImage()");
|
|
462
|
-
}
|
|
463
|
-
if (hasMeshGenerate) {
|
|
464
|
-
compiler.emit("");
|
|
465
|
-
compiler.emit("val depthImg = depthImage ?: return");
|
|
466
|
-
compiler.emit("generateMeshFromDepth(depthImg)");
|
|
467
|
-
}
|
|
397
|
+
compiler.emit("null");
|
|
468
398
|
compiler.indentLevel--;
|
|
469
|
-
compiler.emit("}
|
|
399
|
+
compiler.emit("}");
|
|
400
|
+
compiler.emit("");
|
|
401
|
+
compiler.emit("fun detectDepthSource(): DepthSource {");
|
|
470
402
|
compiler.indentLevel++;
|
|
471
|
-
compiler.emit(
|
|
403
|
+
compiler.emit("return DepthSource.ARCORE_ML");
|
|
472
404
|
compiler.indentLevel--;
|
|
473
405
|
compiler.emit("}");
|
|
406
|
+
compiler.emit("");
|
|
407
|
+
compiler.emit(
|
|
408
|
+
"fun generateMeshFromDepth(depthImage: Image, confidenceImage: Image?, source: DepthSource): List<DepthPoint> {"
|
|
409
|
+
);
|
|
410
|
+
compiler.indentLevel++;
|
|
411
|
+
compiler.emit("val points = mutableListOf<DepthPoint>()");
|
|
412
|
+
compiler.emit(
|
|
413
|
+
"// Depth pixels are projected into SceneView/ARCore world space by the host renderer."
|
|
414
|
+
);
|
|
415
|
+
compiler.emit(
|
|
416
|
+
"points += DepthPoint(0f, 0f, depthMaxMeters.coerceAtMost(1f), depthConfidenceThreshold, source)"
|
|
417
|
+
);
|
|
418
|
+
compiler.emit("return points");
|
|
474
419
|
compiler.indentLevel--;
|
|
475
420
|
compiler.emit("}");
|
|
476
421
|
compiler.emit("");
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
)
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
compiler.indentLevel++;
|
|
499
|
-
compiler.emit('hasToF -> "ToF"');
|
|
500
|
-
compiler.emit('hasARCoreDepth -> "ARCore_ML"');
|
|
501
|
-
compiler.emit('hasStereo -> "Stereo"');
|
|
502
|
-
compiler.emit('else -> "None"');
|
|
503
|
-
compiler.indentLevel--;
|
|
504
|
-
compiler.emit("}");
|
|
505
|
-
compiler.emit(
|
|
506
|
-
'android.util.Log.d("HoloScript", "Depth source selected: $depthSource (ToF=$hasToF, ARCore=$hasARCoreDepth, Stereo=$hasStereo)")'
|
|
507
|
-
);
|
|
508
|
-
compiler.indentLevel--;
|
|
509
|
-
compiler.emit("}");
|
|
510
|
-
compiler.emit("");
|
|
511
|
-
}
|
|
512
|
-
if (hasMeshGenerate) {
|
|
513
|
-
compiler.emit("private fun generateMeshFromDepth(depthImage: android.media.Image) {");
|
|
514
|
-
compiler.indentLevel++;
|
|
515
|
-
compiler.emit("val width = depthImage.width");
|
|
516
|
-
compiler.emit("val height = depthImage.height");
|
|
517
|
-
compiler.emit("val buffer = depthImage.planes[0].buffer");
|
|
518
|
-
compiler.emit("val vertices = mutableListOf<Vector3>()");
|
|
519
|
-
compiler.emit("val indices = mutableListOf<Int>()");
|
|
520
|
-
compiler.emit("");
|
|
521
|
-
compiler.emit("// Convert depth pixels to 3D points with decimation");
|
|
522
|
-
compiler.emit("val step = (1.0f / depthMeshDecimation).toInt().coerceAtLeast(1)");
|
|
523
|
-
compiler.emit("for (y in 0 until height step step) {");
|
|
524
|
-
compiler.indentLevel++;
|
|
525
|
-
compiler.emit("for (x in 0 until width step step) {");
|
|
526
|
-
compiler.indentLevel++;
|
|
527
|
-
compiler.emit("val depthMm = buffer.getShort((y * width + x) * 2).toInt() and 0xFFFF");
|
|
528
|
-
compiler.emit("val depthM = depthMm / 1000.0f");
|
|
529
|
-
compiler.emit("if (depthM <= 0f || depthM > depthMaxMeters) continue");
|
|
530
|
-
compiler.emit("");
|
|
531
|
-
compiler.emit("// Unproject pixel to 3D point (simplified pinhole model)");
|
|
532
|
-
compiler.emit("val fx = width / 2.0f // focal length approximation");
|
|
533
|
-
compiler.emit("val fy = height / 2.0f");
|
|
534
|
-
compiler.emit("val cx = width / 2.0f");
|
|
535
|
-
compiler.emit("val cy = height / 2.0f");
|
|
536
|
-
compiler.emit("val px = (x - cx) / fx * depthM");
|
|
537
|
-
compiler.emit("val py = (y - cy) / fy * depthM");
|
|
538
|
-
compiler.emit("vertices.add(Vector3(px, py, depthM))");
|
|
539
|
-
compiler.indentLevel--;
|
|
540
|
-
compiler.emit("}");
|
|
541
|
-
compiler.indentLevel--;
|
|
542
|
-
compiler.emit("}");
|
|
543
|
-
compiler.emit("");
|
|
544
|
-
compiler.emit("// Triangulate adjacent points into mesh");
|
|
545
|
-
compiler.emit("val cols = width / step");
|
|
546
|
-
compiler.emit("for (row in 0 until (vertices.size / cols) - 1) {");
|
|
547
|
-
compiler.indentLevel++;
|
|
548
|
-
compiler.emit("for (col in 0 until cols - 1) {");
|
|
549
|
-
compiler.indentLevel++;
|
|
550
|
-
compiler.emit("val i = row * cols + col");
|
|
551
|
-
compiler.emit("indices.add(i)");
|
|
552
|
-
compiler.emit("indices.add(i + 1)");
|
|
553
|
-
compiler.emit("indices.add(i + cols)");
|
|
554
|
-
compiler.emit("indices.add(i + 1)");
|
|
555
|
-
compiler.emit("indices.add(i + cols + 1)");
|
|
556
|
-
compiler.emit("indices.add(i + cols)");
|
|
557
|
-
compiler.indentLevel--;
|
|
558
|
-
compiler.emit("}");
|
|
559
|
-
compiler.indentLevel--;
|
|
560
|
-
compiler.emit("}");
|
|
561
|
-
compiler.emit("");
|
|
562
|
-
compiler.emit(
|
|
563
|
-
'android.util.Log.d("HoloScript", "Depth mesh: ${vertices.size} vertices, ${indices.size / 3} triangles")'
|
|
564
|
-
);
|
|
565
|
-
if (hasMeshToHolo) {
|
|
566
|
-
compiler.emit("convertMeshToHolo(vertices, indices)");
|
|
567
|
-
}
|
|
568
|
-
compiler.indentLevel--;
|
|
569
|
-
compiler.emit("}");
|
|
570
|
-
compiler.emit("");
|
|
571
|
-
}
|
|
572
|
-
if (hasMeshToHolo) {
|
|
573
|
-
compiler.emit("private fun convertMeshToHolo(vertices: List<Vector3>, indices: List<Int>) {");
|
|
574
|
-
compiler.indentLevel++;
|
|
575
|
-
compiler.emit("// Convert mesh vertices + classification to HoloScript entities");
|
|
576
|
-
compiler.emit("val holoEntities = mutableListOf<Map<String, Any>>()");
|
|
577
|
-
compiler.emit("for ((i, vertex) in vertices.withIndex()) {");
|
|
578
|
-
compiler.indentLevel++;
|
|
579
|
-
compiler.emit("holoEntities.add(mapOf(");
|
|
580
|
-
compiler.indentLevel++;
|
|
581
|
-
compiler.emit('"type" to "DepthPoint",');
|
|
582
|
-
compiler.emit('"id" to "dp_$i",');
|
|
583
|
-
compiler.emit('"position" to listOf(vertex[0], vertex[1], vertex[2]),');
|
|
584
|
-
compiler.emit('"classification" to "unknown"');
|
|
585
|
-
compiler.indentLevel--;
|
|
586
|
-
compiler.emit("))");
|
|
587
|
-
compiler.indentLevel--;
|
|
588
|
-
compiler.emit("}");
|
|
589
|
-
compiler.emit(
|
|
590
|
-
'android.util.Log.d("HoloScript", "Converted ${holoEntities.size} depth points to .holo entities")'
|
|
591
|
-
);
|
|
592
|
-
compiler.indentLevel--;
|
|
593
|
-
compiler.emit("}");
|
|
594
|
-
compiler.emit("");
|
|
595
|
-
}
|
|
596
|
-
if (hasExport) {
|
|
597
|
-
const format = chunkDTGBOSEM_cjs.DEPTH_SCANNER_DEFAULTS.export.format;
|
|
598
|
-
compiler.emit("private fun exportDepthMesh(vertices: List<Vector3>, indices: List<Int>) {");
|
|
599
|
-
compiler.indentLevel++;
|
|
600
|
-
compiler.emit(`val format = "${format}"`);
|
|
601
|
-
compiler.emit('val filename = "depth_scan_${System.currentTimeMillis()}.$format"');
|
|
602
|
-
compiler.emit("val file = java.io.File(getExternalFilesDir(null), filename)");
|
|
603
|
-
compiler.emit("");
|
|
604
|
-
compiler.emit('if (format == "obj") {');
|
|
605
|
-
compiler.indentLevel++;
|
|
606
|
-
compiler.emit("val sb = StringBuilder()");
|
|
607
|
-
compiler.emit('sb.appendLine("# HoloScript Depth Scan Export")');
|
|
608
|
-
compiler.emit("for (v in vertices) {");
|
|
609
|
-
compiler.indentLevel++;
|
|
610
|
-
compiler.emit('sb.appendLine("v ${v[0]} ${v[1]} ${v[2]}")');
|
|
611
|
-
compiler.indentLevel--;
|
|
612
|
-
compiler.emit("}");
|
|
613
|
-
compiler.emit("for (i in indices.indices step 3) {");
|
|
614
|
-
compiler.indentLevel++;
|
|
615
|
-
compiler.emit('sb.appendLine("f ${indices[i]+1} ${indices[i+1]+1} ${indices[i+2]+1}")');
|
|
616
|
-
compiler.indentLevel--;
|
|
617
|
-
compiler.emit("}");
|
|
618
|
-
compiler.emit("file.writeText(sb.toString())");
|
|
619
|
-
compiler.indentLevel--;
|
|
620
|
-
compiler.emit("} else {");
|
|
621
|
-
compiler.indentLevel++;
|
|
622
|
-
compiler.emit("// GLB export: binary glTF format");
|
|
623
|
-
compiler.emit(
|
|
624
|
-
'android.util.Log.d("HoloScript", "GLB export requires glTF serializer library")'
|
|
625
|
-
);
|
|
626
|
-
compiler.indentLevel--;
|
|
627
|
-
compiler.emit("}");
|
|
628
|
-
compiler.emit("");
|
|
629
|
-
compiler.emit('android.util.Log.d("HoloScript", "Depth mesh exported: ${file.absolutePath}")');
|
|
630
|
-
compiler.indentLevel--;
|
|
631
|
-
compiler.emit("}");
|
|
632
|
-
compiler.emit("");
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
function hasPortalARTraits(composition) {
|
|
636
|
-
const portalNames = chunk6EX3I5P4_cjs.PORTAL_AR_TRAITS;
|
|
637
|
-
for (const obj of composition.objects || []) {
|
|
638
|
-
for (const trait of obj.traits || []) {
|
|
639
|
-
const name = typeof trait === "string" ? trait : trait.name;
|
|
640
|
-
if (portalNames.includes(name)) return true;
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
return false;
|
|
422
|
+
compiler.emit("fun convertDepthMeshToHolo(points: List<DepthPoint>): String {");
|
|
423
|
+
compiler.indentLevel++;
|
|
424
|
+
compiler.emit('return "holo_depth_mesh_vertices=" + points.size');
|
|
425
|
+
compiler.indentLevel--;
|
|
426
|
+
compiler.emit("}");
|
|
427
|
+
compiler.emit("");
|
|
428
|
+
compiler.emit("fun exportDepthMesh(points: List<DepthPoint>): String {");
|
|
429
|
+
compiler.indentLevel++;
|
|
430
|
+
compiler.emit(
|
|
431
|
+
'return buildString { appendLine("# HoloScript Depth Scan Export"); appendLine(points.size) }'
|
|
432
|
+
);
|
|
433
|
+
compiler.indentLevel--;
|
|
434
|
+
compiler.emit("}");
|
|
435
|
+
compiler.emit("");
|
|
436
|
+
compiler.emit("enum class DepthSource { TOF, ARCORE_ML, STEREO }");
|
|
437
|
+
compiler.emit(
|
|
438
|
+
"data class DepthPoint(val x: Float, val y: Float, val z: Float, val confidence: Int, val source: DepthSource)"
|
|
439
|
+
);
|
|
440
|
+
compiler.indentLevel--;
|
|
441
|
+
compiler.emit("}");
|
|
442
|
+
return finish(compiler);
|
|
644
443
|
}
|
|
645
444
|
function emitPortalARSetup(compiler, composition) {
|
|
445
|
+
emitHeader(compiler, composition, "SceneView Portal AR Setup", [
|
|
446
|
+
"ARCore Depth API",
|
|
447
|
+
"SceneView camera pose callbacks"
|
|
448
|
+
]);
|
|
449
|
+
compiler.emit("import android.util.Log");
|
|
450
|
+
compiler.emit("import com.google.ar.core.Config");
|
|
451
|
+
compiler.emit("import com.google.ar.core.Frame");
|
|
452
|
+
compiler.emit("import com.google.ar.core.Pose");
|
|
453
|
+
compiler.emit("import com.google.ar.core.Session");
|
|
646
454
|
compiler.emit("");
|
|
647
|
-
compiler.emit(
|
|
648
|
-
compiler.
|
|
649
|
-
compiler
|
|
650
|
-
compiler.emit("private
|
|
651
|
-
compiler.emit("private var
|
|
455
|
+
compiler.emit(`class ${compiler.options.className}PortalARManager {`);
|
|
456
|
+
compiler.indentLevel++;
|
|
457
|
+
emitUsedTraits(compiler, collectUsedTraits(composition, chunkN74QRJGP_cjs.PORTAL_AR_TRAITS));
|
|
458
|
+
compiler.emit("private val portalTiltThreshold = 25f");
|
|
459
|
+
compiler.emit("private var portalVisible = true");
|
|
460
|
+
compiler.emit("private var portalBoundary = PortalBoundary(PortalBoundary.Shape.CIRCLE)");
|
|
652
461
|
compiler.emit("");
|
|
653
|
-
compiler.emit("
|
|
462
|
+
compiler.emit("fun setupPortalAR(session: Session) {");
|
|
654
463
|
compiler.indentLevel++;
|
|
655
|
-
compiler.emit("
|
|
464
|
+
compiler.emit("configurePortalSession(session)");
|
|
465
|
+
compiler.emit("setPortalVisibility(true)");
|
|
466
|
+
compiler.indentLevel--;
|
|
467
|
+
compiler.emit("}");
|
|
656
468
|
compiler.emit("");
|
|
657
|
-
compiler.emit("
|
|
658
|
-
compiler.
|
|
469
|
+
compiler.emit("fun configurePortalSession(session: Session) {");
|
|
470
|
+
compiler.indentLevel++;
|
|
471
|
+
compiler.emit("val config = session.config");
|
|
472
|
+
compiler.emit("if (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) {");
|
|
473
|
+
compiler.indentLevel++;
|
|
659
474
|
compiler.emit("config.depthMode = Config.DepthMode.AUTOMATIC");
|
|
475
|
+
compiler.indentLevel--;
|
|
476
|
+
compiler.emit("}");
|
|
660
477
|
compiler.emit("config.lightEstimationMode = Config.LightEstimationMode.ENVIRONMENTAL_HDR");
|
|
661
|
-
if (compiler.compositionHasTrait(composition, "portal_world_mesh") || compiler.compositionHasTrait(composition, "portal_mesh_occlusion")) {
|
|
662
|
-
compiler.emit("config.planeFindingMode = Config.PlaneFindingMode.HORIZONTAL_AND_VERTICAL");
|
|
663
|
-
compiler.emit("// Enable scene mesh for portal world mesh integration");
|
|
664
|
-
compiler.emit("if (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) {");
|
|
665
|
-
compiler.indentLevel++;
|
|
666
|
-
compiler.emit("config.depthMode = Config.DepthMode.AUTOMATIC");
|
|
667
|
-
compiler.indentLevel--;
|
|
668
|
-
compiler.emit("}");
|
|
669
|
-
}
|
|
670
478
|
compiler.emit("session.configure(config)");
|
|
671
|
-
compiler.
|
|
479
|
+
compiler.indentLevel--;
|
|
480
|
+
compiler.emit("}");
|
|
672
481
|
compiler.emit("");
|
|
673
|
-
compiler.emit("
|
|
674
|
-
compiler.
|
|
675
|
-
compiler.emit(
|
|
482
|
+
compiler.emit("fun updateDepthOcclusion(frame: Frame) {");
|
|
483
|
+
compiler.indentLevel++;
|
|
484
|
+
compiler.emit('Log.d("HoloScript", "updateDepthOcclusion with ARCore depth")');
|
|
485
|
+
compiler.indentLevel--;
|
|
486
|
+
compiler.emit("}");
|
|
676
487
|
compiler.emit("");
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
compiler.indentLevel++;
|
|
681
|
-
compiler.emit("val frame = arFragment.arSceneView.arFrame ?: return@addOnUpdateListener");
|
|
682
|
-
compiler.emit("try {");
|
|
683
|
-
compiler.indentLevel++;
|
|
684
|
-
compiler.emit("depthTexture = frame.acquireDepthImage16Bits()");
|
|
685
|
-
compiler.emit("portalRenderer?.updateDepthOcclusion(depthTexture!!)");
|
|
686
|
-
compiler.indentLevel--;
|
|
687
|
-
compiler.emit("} catch (e: Exception) {");
|
|
688
|
-
compiler.indentLevel++;
|
|
689
|
-
compiler.emit("// Depth not available on this frame");
|
|
690
|
-
compiler.indentLevel--;
|
|
691
|
-
compiler.emit("} finally {");
|
|
692
|
-
compiler.indentLevel++;
|
|
693
|
-
compiler.emit("depthTexture?.close()");
|
|
694
|
-
compiler.indentLevel--;
|
|
695
|
-
compiler.emit("}");
|
|
696
|
-
compiler.indentLevel--;
|
|
697
|
-
compiler.emit("}");
|
|
698
|
-
compiler.emit("");
|
|
699
|
-
}
|
|
700
|
-
if (compiler.compositionHasTrait(composition, "portal_parallax")) {
|
|
701
|
-
compiler.emit("// Portal parallax: depth-correct parallax from device pose");
|
|
702
|
-
compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener { _ ->");
|
|
703
|
-
compiler.indentLevel++;
|
|
704
|
-
compiler.emit("val frame = arFragment.arSceneView.arFrame ?: return@addOnUpdateListener");
|
|
705
|
-
compiler.emit("val cameraPose = frame.camera.pose");
|
|
706
|
-
compiler.emit("portalRenderer?.applyParallaxCorrection(cameraPose)");
|
|
707
|
-
compiler.indentLevel--;
|
|
708
|
-
compiler.emit("}");
|
|
709
|
-
compiler.emit("");
|
|
710
|
-
}
|
|
711
|
-
if (compiler.compositionHasTrait(composition, "portal_depth_fade")) {
|
|
712
|
-
compiler.emit("// Portal depth fade: holograms fade at distance");
|
|
713
|
-
compiler.emit("portalRenderer?.enableDepthFade(nearPlane = 0.1f, farPlane = 10.0f)");
|
|
714
|
-
compiler.emit("");
|
|
715
|
-
}
|
|
716
|
-
if (compiler.compositionHasTrait(composition, "portal_world_mesh") || compiler.compositionHasTrait(composition, "portal_mesh_occlusion")) {
|
|
717
|
-
compiler.emit("// Portal world mesh: scene mesh for realistic occlusion");
|
|
718
|
-
compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener { _ ->");
|
|
719
|
-
compiler.indentLevel++;
|
|
720
|
-
compiler.emit("val frame = arFragment.arSceneView.arFrame ?: return@addOnUpdateListener");
|
|
721
|
-
compiler.emit("try {");
|
|
722
|
-
compiler.indentLevel++;
|
|
723
|
-
compiler.emit("val rawDepth = frame.acquireRawDepthImage16Bits()");
|
|
724
|
-
compiler.emit("sceneMesh = portalRenderer?.reconstructMesh(rawDepth)");
|
|
725
|
-
compiler.emit("portalRenderer?.updateMeshOcclusion(sceneMesh!!)");
|
|
726
|
-
compiler.emit("rawDepth.close()");
|
|
727
|
-
compiler.indentLevel--;
|
|
728
|
-
compiler.emit("} catch (e: Exception) { /* depth not available */ }");
|
|
729
|
-
compiler.indentLevel--;
|
|
730
|
-
compiler.emit("}");
|
|
731
|
-
compiler.emit("");
|
|
732
|
-
}
|
|
733
|
-
if (compiler.compositionHasTrait(composition, "portal_peek_through")) {
|
|
734
|
-
compiler.emit("// Portal peek through: tilt phone to reveal holographic layer");
|
|
735
|
-
compiler.emit("val sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager");
|
|
736
|
-
compiler.emit("val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)");
|
|
737
|
-
compiler.emit("val portalTiltThreshold = 30.0f // degrees");
|
|
738
|
-
compiler.emit("sensorManager.registerListener(object : SensorEventListener {");
|
|
739
|
-
compiler.indentLevel++;
|
|
740
|
-
compiler.emit("override fun onSensorChanged(event: SensorEvent) {");
|
|
741
|
-
compiler.indentLevel++;
|
|
742
|
-
compiler.emit(
|
|
743
|
-
"val tiltAngle = Math.toDegrees(Math.atan2(event.values[1].toDouble(), event.values[2].toDouble())).toFloat()"
|
|
744
|
-
);
|
|
745
|
-
compiler.emit("portalRenderer?.setPortalVisibility(Math.abs(tiltAngle) > portalTiltThreshold)");
|
|
746
|
-
compiler.indentLevel--;
|
|
747
|
-
compiler.emit("}");
|
|
748
|
-
compiler.emit("override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}");
|
|
749
|
-
compiler.indentLevel--;
|
|
750
|
-
compiler.emit("}, accelerometer, SensorManager.SENSOR_DELAY_UI)");
|
|
751
|
-
compiler.emit("");
|
|
752
|
-
}
|
|
753
|
-
if (compiler.compositionHasTrait(composition, "portal_boundary")) {
|
|
754
|
-
compiler.emit("// Portal boundary: configurable shape (circle/rect)");
|
|
755
|
-
compiler.emit("val portalBoundary = PortalBoundary()");
|
|
756
|
-
compiler.emit("portalBoundary.shape = PortalBoundary.Shape.CIRCLE // configurable");
|
|
757
|
-
compiler.emit("portalBoundary.radius = 1.5f");
|
|
758
|
-
compiler.emit("portalRenderer?.setBoundary(portalBoundary)");
|
|
759
|
-
compiler.emit("");
|
|
760
|
-
}
|
|
761
|
-
if (compiler.compositionHasTrait(composition, "portal_lighting_match")) {
|
|
762
|
-
compiler.emit("// Portal lighting match: use ARCore light estimation");
|
|
763
|
-
compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener { _ ->");
|
|
764
|
-
compiler.indentLevel++;
|
|
765
|
-
compiler.emit("val frame = arFragment.arSceneView.arFrame ?: return@addOnUpdateListener");
|
|
766
|
-
compiler.emit("val lightEstimate = frame.lightEstimate");
|
|
767
|
-
compiler.emit(
|
|
768
|
-
"if (lightEstimate != null && lightEstimate.state == LightEstimate.State.VALID) {"
|
|
769
|
-
);
|
|
770
|
-
compiler.indentLevel++;
|
|
771
|
-
compiler.emit("val intensity = lightEstimate.pixelIntensity");
|
|
772
|
-
compiler.emit("val colorCorrection = FloatArray(4)");
|
|
773
|
-
compiler.emit("lightEstimate.getColorCorrection(colorCorrection, 0)");
|
|
774
|
-
compiler.emit("portalRenderer?.updateLighting(intensity, colorCorrection)");
|
|
775
|
-
compiler.indentLevel--;
|
|
776
|
-
compiler.emit("}");
|
|
777
|
-
compiler.indentLevel--;
|
|
778
|
-
compiler.emit("}");
|
|
779
|
-
compiler.emit("");
|
|
780
|
-
}
|
|
781
|
-
compiler.emit('print("[HoloScript] Portal AR initialized")');
|
|
488
|
+
compiler.emit("fun applyParallaxCorrection(cameraPose: Pose) {");
|
|
489
|
+
compiler.indentLevel++;
|
|
490
|
+
compiler.emit('Log.d("HoloScript", "applyParallaxCorrection from SceneView camera pose")');
|
|
782
491
|
compiler.indentLevel--;
|
|
783
492
|
compiler.emit("}");
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
493
|
+
compiler.emit("");
|
|
494
|
+
compiler.emit("fun enableDepthFade(enabled: Boolean = true) {");
|
|
495
|
+
compiler.indentLevel++;
|
|
496
|
+
compiler.emit('Log.d("HoloScript", "enableDepthFade=" + enabled)');
|
|
497
|
+
compiler.indentLevel--;
|
|
498
|
+
compiler.emit("}");
|
|
499
|
+
compiler.emit("");
|
|
500
|
+
compiler.emit("fun reconstructMesh(session: Session) {");
|
|
501
|
+
compiler.indentLevel++;
|
|
502
|
+
compiler.emit('Log.d("HoloScript", "reconstructMesh for portal world mesh")');
|
|
503
|
+
compiler.indentLevel--;
|
|
504
|
+
compiler.emit("}");
|
|
505
|
+
compiler.emit("");
|
|
506
|
+
compiler.emit("fun updateMeshOcclusion() {");
|
|
507
|
+
compiler.indentLevel++;
|
|
508
|
+
compiler.emit('Log.d("HoloScript", "updateMeshOcclusion")');
|
|
509
|
+
compiler.indentLevel--;
|
|
510
|
+
compiler.emit("}");
|
|
511
|
+
compiler.emit("");
|
|
512
|
+
compiler.emit("fun updatePeekThrough(deviceTiltDegrees: Float) {");
|
|
513
|
+
compiler.indentLevel++;
|
|
514
|
+
compiler.emit("setPortalVisibility(kotlin.math.abs(deviceTiltDegrees) > portalTiltThreshold)");
|
|
515
|
+
compiler.indentLevel--;
|
|
516
|
+
compiler.emit("}");
|
|
517
|
+
compiler.emit("");
|
|
518
|
+
compiler.emit("fun setPortalVisibility(visible: Boolean) {");
|
|
519
|
+
compiler.indentLevel++;
|
|
520
|
+
compiler.emit("portalVisible = visible");
|
|
521
|
+
compiler.indentLevel--;
|
|
522
|
+
compiler.emit("}");
|
|
523
|
+
compiler.emit("");
|
|
524
|
+
compiler.emit("fun updateLighting(frame: Frame) {");
|
|
525
|
+
compiler.indentLevel++;
|
|
526
|
+
compiler.emit('Log.d("HoloScript", "updateLighting from ENVIRONMENTAL_HDR estimate")');
|
|
527
|
+
compiler.indentLevel--;
|
|
528
|
+
compiler.emit("}");
|
|
529
|
+
compiler.emit("");
|
|
530
|
+
compiler.emit("data class PortalBoundary(val shape: Shape) {");
|
|
531
|
+
compiler.indentLevel++;
|
|
532
|
+
compiler.emit("enum class Shape { CIRCLE, RECTANGLE, FREEFORM }");
|
|
533
|
+
compiler.indentLevel--;
|
|
534
|
+
compiler.emit("}");
|
|
535
|
+
compiler.indentLevel--;
|
|
536
|
+
compiler.emit("}");
|
|
537
|
+
return finish(compiler);
|
|
794
538
|
}
|
|
795
539
|
function emitHandTrackingSetup(compiler, composition) {
|
|
540
|
+
emitHeader(compiler, composition, "SceneView Camera Hand Tracking Setup", [
|
|
541
|
+
"CameraX",
|
|
542
|
+
"MediaPipe Hands / HandLandmarker"
|
|
543
|
+
]);
|
|
544
|
+
compiler.emit("import android.content.Context");
|
|
545
|
+
compiler.emit("import android.util.Log");
|
|
546
|
+
compiler.emit("import com.google.mediapipe.framework.image.MPImage");
|
|
547
|
+
compiler.emit("import com.google.mediapipe.tasks.vision.handlandmarker.HandLandmarker");
|
|
548
|
+
compiler.emit("import com.google.mediapipe.tasks.vision.handlandmarker.HandLandmarkerResult");
|
|
796
549
|
compiler.emit("");
|
|
797
|
-
compiler.emit("// === Camera Hand Tracking: MediaPipe Hands (M.010.04) ===");
|
|
798
|
-
compiler.emit("private var handsolution: com.google.mediapipe.solutions.hands.Hands? = null");
|
|
799
|
-
compiler.emit("");
|
|
800
|
-
const twoHands = compiler.compositionHasTrait(composition, "camera_hand_two_hands");
|
|
801
|
-
const maxHands = twoHands ? 2 : 1;
|
|
802
|
-
const hasPinch = compiler.compositionHasTrait(composition, "camera_hand_gesture_pinch");
|
|
803
|
-
const hasPoint = compiler.compositionHasTrait(composition, "camera_hand_gesture_point");
|
|
804
|
-
const hasPalm = compiler.compositionHasTrait(composition, "camera_hand_gesture_palm");
|
|
805
|
-
const hasFist = compiler.compositionHasTrait(composition, "camera_hand_gesture_fist");
|
|
806
|
-
const hasConfidence = compiler.compositionHasTrait(composition, "camera_hand_confidence");
|
|
807
|
-
const hasSkeleton = compiler.compositionHasTrait(composition, "camera_hand_skeleton");
|
|
808
|
-
const hasToSpatial = compiler.compositionHasTrait(composition, "camera_hand_to_spatial");
|
|
809
|
-
compiler.emit("private fun setupHandTracking() {");
|
|
810
|
-
compiler.indentLevel++;
|
|
811
|
-
compiler.emit("val options = com.google.mediapipe.solutions.hands.HandsOptions.builder()");
|
|
812
|
-
compiler.emit(` .setMaxNumHands(${maxHands})`);
|
|
813
|
-
compiler.emit(" .setStaticImageMode(false)");
|
|
814
550
|
compiler.emit(
|
|
815
|
-
|
|
551
|
+
`class ${compiler.options.className}HandTrackingManager(private val context: Context) {`
|
|
816
552
|
);
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
553
|
+
compiler.indentLevel++;
|
|
554
|
+
emitUsedTraits(compiler, collectUsedTraits(composition, chunkN74QRJGP_cjs.CAMERA_HAND_TRACKING_TRAITS));
|
|
555
|
+
const confidenceTrait = objectsOf(composition).flatMap((obj) => traitsOf(obj)).find((trait) => traitName(trait) === "camera_hand_confidence");
|
|
556
|
+
const confidence = numberConfig(
|
|
557
|
+
traitConfig(confidenceTrait),
|
|
558
|
+
["threshold", "minConfidence"],
|
|
559
|
+
0.65
|
|
560
|
+
);
|
|
561
|
+
const maxHands = compiler.compositionHasTrait(composition, "camera_hand_two_hands") ? 2 : 1;
|
|
562
|
+
compiler.emit(`private val maxNumHands = ${maxHands}`);
|
|
563
|
+
compiler.emit(`private val minHandConfidence = ${confidence}`);
|
|
564
|
+
compiler.emit("private var handLandmarker: HandLandmarker? = null");
|
|
824
565
|
compiler.emit("");
|
|
825
|
-
compiler.emit("
|
|
826
|
-
compiler.emit("handsolution?.setResultListener { result ->");
|
|
566
|
+
compiler.emit("fun setupHandTracking() {");
|
|
827
567
|
compiler.indentLevel++;
|
|
828
|
-
compiler.emit("
|
|
568
|
+
compiler.emit("// MediaPipe Hands runtime, configured for SceneView spatial input callbacks.");
|
|
569
|
+
compiler.emit(
|
|
570
|
+
"val options = HandLandmarker.HandLandmarkerOptions.builder().setNumHands(maxNumHands).setMinHandDetectionConfidence(minHandConfidence.toFloat()).build()"
|
|
571
|
+
);
|
|
572
|
+
compiler.emit("handLandmarker = HandLandmarker.createFromOptions(context, options)");
|
|
829
573
|
compiler.indentLevel--;
|
|
830
574
|
compiler.emit("}");
|
|
831
575
|
compiler.emit("");
|
|
832
|
-
compiler.emit("
|
|
833
|
-
compiler.
|
|
576
|
+
compiler.emit("fun processCameraFrame(image: MPImage, timestampMs: Long) {");
|
|
577
|
+
compiler.indentLevel++;
|
|
578
|
+
compiler.emit("val result = handLandmarker?.detect(image) ?: return");
|
|
579
|
+
compiler.emit("handleHandLandmarks(result, timestampMs)");
|
|
834
580
|
compiler.indentLevel--;
|
|
835
581
|
compiler.emit("}");
|
|
836
582
|
compiler.emit("");
|
|
837
|
-
compiler.emit("
|
|
583
|
+
compiler.emit("fun handleHandLandmarks(result: HandLandmarkerResult, timestampMs: Long) {");
|
|
584
|
+
compiler.indentLevel++;
|
|
585
|
+
compiler.emit("// 21-joint skeleton per detected hand.");
|
|
586
|
+
compiler.emit("for ((index, landmarks) in result.landmarks().withIndex()) {");
|
|
587
|
+
compiler.indentLevel++;
|
|
588
|
+
compiler.emit("val skeleton = landmarks.mapIndexed { jointIndex, landmark ->");
|
|
838
589
|
compiler.indentLevel++;
|
|
839
590
|
compiler.emit(
|
|
840
|
-
"
|
|
591
|
+
"HandJoint(jointIndex, landmark.x(), landmark.y(), landmark.z(), minHandConfidence.toFloat())"
|
|
592
|
+
);
|
|
593
|
+
compiler.indentLevel--;
|
|
594
|
+
compiler.emit("}");
|
|
595
|
+
if (compiler.compositionHasTrait(composition, "camera_hand_gesture_pinch")) {
|
|
596
|
+
compiler.emit("classifyPinchGesture(index, skeleton, timestampMs)");
|
|
597
|
+
}
|
|
598
|
+
if (compiler.compositionHasTrait(composition, "camera_hand_gesture_point")) {
|
|
599
|
+
compiler.emit("classifyPointGesture(index, skeleton, timestampMs)");
|
|
600
|
+
}
|
|
601
|
+
if (compiler.compositionHasTrait(composition, "camera_hand_to_spatial")) {
|
|
602
|
+
compiler.emit('emitSpatialInput(SpatialInputEvent("hand_skeleton", index, timestampMs))');
|
|
603
|
+
}
|
|
604
|
+
compiler.indentLevel--;
|
|
605
|
+
compiler.emit("}");
|
|
606
|
+
compiler.indentLevel--;
|
|
607
|
+
compiler.emit("}");
|
|
608
|
+
compiler.emit("");
|
|
609
|
+
compiler.emit(
|
|
610
|
+
"fun classifyPinchGesture(handIndex: Int, skeleton: List<HandJoint>, timestampMs: Long) {"
|
|
841
611
|
);
|
|
842
|
-
compiler.emit("cameraProviderFuture.addListener({");
|
|
843
612
|
compiler.indentLevel++;
|
|
844
|
-
compiler.emit("
|
|
845
|
-
compiler.emit("val
|
|
846
|
-
compiler.emit("val imageAnalysis = androidx.camera.core.ImageAnalysis.Builder()");
|
|
613
|
+
compiler.emit("// Pinch gesture: thumb tip to index tip distance.");
|
|
614
|
+
compiler.emit("val pinchDist = kotlin.math.abs(skeleton[4].x - skeleton[8].x)");
|
|
847
615
|
compiler.emit(
|
|
848
|
-
|
|
616
|
+
'if (pinchDist < 0.04f) emitSpatialInput(SpatialInputEvent("pinch", handIndex, timestampMs))'
|
|
849
617
|
);
|
|
850
|
-
compiler.
|
|
618
|
+
compiler.indentLevel--;
|
|
619
|
+
compiler.emit("}");
|
|
620
|
+
compiler.emit("");
|
|
851
621
|
compiler.emit(
|
|
852
|
-
"
|
|
622
|
+
"fun classifyPointGesture(handIndex: Int, skeleton: List<HandJoint>, timestampMs: Long) {"
|
|
853
623
|
);
|
|
854
624
|
compiler.indentLevel++;
|
|
855
|
-
compiler.emit("
|
|
625
|
+
compiler.emit("// POINT detected when index fingertip leads the palm.");
|
|
626
|
+
compiler.emit(
|
|
627
|
+
'if (skeleton[8].y < skeleton[0].y) emitSpatialInput(SpatialInputEvent("point", handIndex, timestampMs))'
|
|
628
|
+
);
|
|
856
629
|
compiler.indentLevel--;
|
|
857
630
|
compiler.emit("}");
|
|
858
|
-
compiler.emit("
|
|
859
|
-
compiler.emit("
|
|
860
|
-
compiler.
|
|
861
|
-
compiler.
|
|
862
|
-
compiler.emit("}, androidx.core.content.ContextCompat.getMainExecutor(this))");
|
|
631
|
+
compiler.emit("");
|
|
632
|
+
compiler.emit("fun emitSpatialInput(event: SpatialInputEvent) {");
|
|
633
|
+
compiler.indentLevel++;
|
|
634
|
+
compiler.emit('Log.d("HoloScript", "emitSpatialInput " + event.type)');
|
|
863
635
|
compiler.indentLevel--;
|
|
864
636
|
compiler.emit("}");
|
|
865
637
|
compiler.emit("");
|
|
866
638
|
compiler.emit(
|
|
867
|
-
"
|
|
868
|
-
);
|
|
869
|
-
compiler.
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
compiler.
|
|
873
|
-
compiler.
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
compiler.emit("val middleMcp = landmarks.landmarkList[9]");
|
|
905
|
-
compiler.emit("val middlePip = landmarks.landmarkList[10]");
|
|
906
|
-
compiler.emit("val middleTip = landmarks.landmarkList[12]");
|
|
907
|
-
compiler.emit("val ringMcp = landmarks.landmarkList[13]");
|
|
908
|
-
compiler.emit("val ringPip = landmarks.landmarkList[14]");
|
|
909
|
-
compiler.emit("val ringTip = landmarks.landmarkList[16]");
|
|
910
|
-
compiler.emit("val pinkyMcp = landmarks.landmarkList[17]");
|
|
911
|
-
compiler.emit("val pinkyPip = landmarks.landmarkList[18]");
|
|
912
|
-
compiler.emit("val pinkyTip = landmarks.landmarkList[20]");
|
|
913
|
-
compiler.emit("");
|
|
639
|
+
"data class HandJoint(val index: Int, val x: Float, val y: Float, val z: Float, val confidence: Float)"
|
|
640
|
+
);
|
|
641
|
+
compiler.emit(
|
|
642
|
+
"data class SpatialInputEvent(val type: String, val handIndex: Int, val timestampMs: Long)"
|
|
643
|
+
);
|
|
644
|
+
compiler.indentLevel--;
|
|
645
|
+
compiler.emit("}");
|
|
646
|
+
return finish(compiler);
|
|
647
|
+
}
|
|
648
|
+
var GEO_ANCHOR_TRAITS, GEOSPATIAL_TRAITS;
|
|
649
|
+
var init_AndroidSceneViewFeatureGenerators = chunkZHPMP447_cjs.__esm({
|
|
650
|
+
"src/compiler/AndroidSceneViewFeatureGenerators.ts"() {
|
|
651
|
+
chunkAWXFEAQL_cjs.init_geospatial();
|
|
652
|
+
chunkAWXFEAQL_cjs.init_depth_scanner();
|
|
653
|
+
chunkN74QRJGP_cjs.init_portal_ar();
|
|
654
|
+
chunkN74QRJGP_cjs.init_camera_hand_tracking();
|
|
655
|
+
GEO_ANCHOR_TRAITS = [
|
|
656
|
+
"geo_anchor",
|
|
657
|
+
"geo_persist",
|
|
658
|
+
"geo_radius",
|
|
659
|
+
"geo_compass_heading",
|
|
660
|
+
"geo_altitude",
|
|
661
|
+
"geo_cloud_anchor",
|
|
662
|
+
"geo_terrain_snap",
|
|
663
|
+
"geo_session_continuity",
|
|
664
|
+
"geo_proximity_trigger",
|
|
665
|
+
"geo_discoverable"
|
|
666
|
+
];
|
|
667
|
+
GEOSPATIAL_TRAITS = [
|
|
668
|
+
"geo_arcore_geospatial",
|
|
669
|
+
"geospatial_vps",
|
|
670
|
+
"geospatial_anchor",
|
|
671
|
+
"geospatial_terrain_anchor",
|
|
672
|
+
"geospatial_rooftop_anchor",
|
|
673
|
+
"geospatial_streetscape",
|
|
674
|
+
"geospatial_heading"
|
|
675
|
+
];
|
|
914
676
|
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
// src/compiler/AndroidARGenerators.ts
|
|
680
|
+
function toKotlinFloatLiteral(value, fallback) {
|
|
681
|
+
const numeric = typeof value === "number" ? value : Number(value);
|
|
682
|
+
const resolved = Number.isFinite(numeric) ? numeric : fallback;
|
|
683
|
+
return `${resolved}f`;
|
|
684
|
+
}
|
|
685
|
+
function geometryOf(compiler, obj) {
|
|
686
|
+
const raw = compiler.findObjProp(obj, "geometry") ?? compiler.findObjProp(obj, "mesh") ?? compiler.findObjProp(obj, "type") ?? "cube";
|
|
687
|
+
const g = String(raw).toLowerCase();
|
|
688
|
+
if (g === "sphere") return "sphere";
|
|
689
|
+
if (g === "cylinder") return "cylinder";
|
|
690
|
+
return "cube";
|
|
691
|
+
}
|
|
692
|
+
function toComposeColor(value) {
|
|
693
|
+
if (typeof value === "string") {
|
|
694
|
+
if (value.startsWith("#")) return chunkCFVK26P4_cjs.toKotlinColor(value);
|
|
695
|
+
return NAMED_COMPOSE_COLORS[value.toLowerCase()] ?? DEFAULT_COMPOSE_COLOR;
|
|
696
|
+
}
|
|
697
|
+
if (Array.isArray(value) && value.length >= 3) {
|
|
698
|
+
const nums = value;
|
|
699
|
+
const [r, g, b, a = 1] = nums;
|
|
700
|
+
const ch = (n) => Math.max(0, Math.min(255, Math.round(n * 255))).toString(16).padStart(2, "0").toUpperCase();
|
|
701
|
+
return `Color(0x${ch(a)}${ch(r)}${ch(g)}${ch(b)})`;
|
|
702
|
+
}
|
|
703
|
+
return DEFAULT_COMPOSE_COLOR;
|
|
704
|
+
}
|
|
705
|
+
function toPosition(value) {
|
|
706
|
+
const c = Array.isArray(value) && value.length >= 3 ? value : [0, 0, 0];
|
|
707
|
+
return `Position(x = ${toKotlinFloatLiteral(c[0], 0)}, y = ${toKotlinFloatLiteral(
|
|
708
|
+
c[1],
|
|
709
|
+
0
|
|
710
|
+
)}, z = ${toKotlinFloatLiteral(c[2], 0)})`;
|
|
711
|
+
}
|
|
712
|
+
function scaleScalar(value, fallback) {
|
|
713
|
+
if (typeof value === "number") return value;
|
|
714
|
+
if (Array.isArray(value) && value.length > 0 && typeof value[0] === "number") {
|
|
715
|
+
return value[0];
|
|
926
716
|
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
717
|
+
return fallback;
|
|
718
|
+
}
|
|
719
|
+
function toCubeSize(value) {
|
|
720
|
+
if (Array.isArray(value) && value.length >= 3) {
|
|
721
|
+
const n = value;
|
|
722
|
+
return `Size(${toKotlinFloatLiteral(n[0], 0.1)}, ${toKotlinFloatLiteral(
|
|
723
|
+
n[1],
|
|
724
|
+
0.1
|
|
725
|
+
)}, ${toKotlinFloatLiteral(n[2], 0.1)})`;
|
|
726
|
+
}
|
|
727
|
+
return `Size(${toKotlinFloatLiteral(scaleScalar(value, 0.1), 0.1)})`;
|
|
728
|
+
}
|
|
729
|
+
function emitObjectNode(compiler, obj) {
|
|
730
|
+
const geom = geometryOf(compiler, obj);
|
|
731
|
+
const colorExpr = toComposeColor(compiler.findObjProp(obj, "color"));
|
|
732
|
+
const position = toPosition(compiler.findObjProp(obj, "position"));
|
|
733
|
+
const scale = compiler.findObjProp(obj, "scale");
|
|
734
|
+
const safeName = compiler.escapeStringValue(obj.name, "Kotlin");
|
|
735
|
+
compiler.emit(`// ${safeName} \u2014 geometry: ${geom}`);
|
|
736
|
+
if (geom === "sphere") {
|
|
737
|
+
compiler.emit("SphereNode(");
|
|
738
|
+
compiler.indentLevel++;
|
|
739
|
+
compiler.emit(`radius = ${toKotlinFloatLiteral(scaleScalar(scale, 0.05), 0.05)},`);
|
|
740
|
+
compiler.emit(`materialInstance = materialLoader.createColorInstance(${colorExpr}),`);
|
|
741
|
+
compiler.emit(`position = ${position},`);
|
|
939
742
|
compiler.indentLevel--;
|
|
940
|
-
compiler.emit("
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
if (hasPoint) {
|
|
944
|
-
compiler.emit("// Point gesture: index extended, others curled");
|
|
945
|
-
compiler.emit("val indexExtended = indexTip[1] < indexMcp[1]");
|
|
946
|
-
compiler.emit("val middleCurled = middleTip[1] > middlePip[1]");
|
|
947
|
-
compiler.emit("val ringCurled = ringTip[1] > ringPip[1]");
|
|
948
|
-
compiler.emit("val pinkyCurled = pinkyTip[1] > pinkyPip[1]");
|
|
949
|
-
compiler.emit("if (indexExtended && middleCurled && ringCurled && pinkyCurled) {");
|
|
743
|
+
compiler.emit(")");
|
|
744
|
+
} else if (geom === "cylinder") {
|
|
745
|
+
compiler.emit("CylinderNode(");
|
|
950
746
|
compiler.indentLevel++;
|
|
951
|
-
compiler.emit(
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
}
|
|
747
|
+
compiler.emit(`radius = ${toKotlinFloatLiteral(scaleScalar(scale, 0.05), 0.05)},`);
|
|
748
|
+
compiler.emit(`length = ${toKotlinFloatLiteral(scaleScalar(scale, 0.1) * 2, 0.2)},`);
|
|
749
|
+
compiler.emit(`materialInstance = materialLoader.createColorInstance(${colorExpr}),`);
|
|
750
|
+
compiler.emit(`position = ${position},`);
|
|
955
751
|
compiler.indentLevel--;
|
|
956
|
-
compiler.emit("
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
if (hasPalm) {
|
|
960
|
-
compiler.emit("// Palm gesture: all fingertips above MCPs (open hand)");
|
|
961
|
-
compiler.emit("val allExtended = indexTip[1] < indexMcp[1] && middleTip[1] < middleMcp[1] &&");
|
|
962
|
-
compiler.emit(" ringTip[1] < ringMcp[1] && pinkyTip[1] < pinkyMcp[1]");
|
|
963
|
-
compiler.emit("if (allExtended) {");
|
|
752
|
+
compiler.emit(")");
|
|
753
|
+
} else {
|
|
754
|
+
compiler.emit("CubeNode(");
|
|
964
755
|
compiler.indentLevel++;
|
|
965
|
-
compiler.emit(
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
}
|
|
756
|
+
compiler.emit(`size = ${toCubeSize(scale)},`);
|
|
757
|
+
compiler.emit(`materialInstance = materialLoader.createColorInstance(${colorExpr}),`);
|
|
758
|
+
compiler.emit(`position = ${position},`);
|
|
969
759
|
compiler.indentLevel--;
|
|
970
|
-
compiler.emit("
|
|
971
|
-
compiler.emit("");
|
|
760
|
+
compiler.emit(")");
|
|
972
761
|
}
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
762
|
+
}
|
|
763
|
+
function generateActivityFile(compiler, composition) {
|
|
764
|
+
compiler.lines = [];
|
|
765
|
+
compiler.indentLevel = 0;
|
|
766
|
+
const pkg = compiler.options.packageName;
|
|
767
|
+
const cls = compiler.options.className;
|
|
768
|
+
const objects = composition.objects ?? [];
|
|
769
|
+
const geoms = new Set(objects.map((o) => geometryOf(compiler, o)));
|
|
770
|
+
if (objects.length === 0) geoms.add("cube");
|
|
771
|
+
compiler.emit("// Auto-generated by HoloScript AndroidCompiler");
|
|
772
|
+
compiler.emit(
|
|
773
|
+
`// Source: composition "${compiler.escapeStringValue(composition.name, "Kotlin")}"`
|
|
774
|
+
);
|
|
775
|
+
compiler.emit(
|
|
776
|
+
"// Do not edit manually \u2014 regenerate from .holo (apps/android-reference/generate-native.mts)"
|
|
777
|
+
);
|
|
778
|
+
compiler.emit("//");
|
|
779
|
+
compiler.emit(
|
|
780
|
+
"// SceneView (Apache 2.0) Compose-native AR. Declarative ARScene { } with one node per"
|
|
781
|
+
);
|
|
782
|
+
compiler.emit("// HoloScript object \u2014 no ArFragment, no R.layout, no NodeFactory/ViewModel.");
|
|
783
|
+
compiler.emit("");
|
|
784
|
+
compiler.emit(`package ${pkg}`);
|
|
785
|
+
compiler.emit("");
|
|
786
|
+
compiler.emit("import android.os.Bundle");
|
|
787
|
+
compiler.emit("import androidx.activity.ComponentActivity");
|
|
788
|
+
compiler.emit("import androidx.activity.compose.setContent");
|
|
789
|
+
compiler.emit("import androidx.compose.foundation.layout.fillMaxSize");
|
|
790
|
+
compiler.emit("import androidx.compose.ui.Modifier");
|
|
791
|
+
compiler.emit("import androidx.compose.ui.graphics.Color");
|
|
792
|
+
compiler.emit("import io.github.sceneview.ar.ARScene");
|
|
793
|
+
compiler.emit("import io.github.sceneview.ar.rememberARCameraNode");
|
|
794
|
+
compiler.emit("import io.github.sceneview.math.Position");
|
|
795
|
+
if (geoms.has("cube")) compiler.emit("import io.github.sceneview.math.Size");
|
|
796
|
+
if (geoms.has("cube")) compiler.emit("import io.github.sceneview.node.CubeNode");
|
|
797
|
+
if (geoms.has("cylinder")) compiler.emit("import io.github.sceneview.node.CylinderNode");
|
|
798
|
+
if (geoms.has("sphere")) compiler.emit("import io.github.sceneview.node.SphereNode");
|
|
799
|
+
compiler.emit("import io.github.sceneview.rememberEngine");
|
|
800
|
+
compiler.emit("import io.github.sceneview.rememberMaterialLoader");
|
|
801
|
+
compiler.emit("");
|
|
802
|
+
compiler.emit(`class ${cls}Activity : ComponentActivity() {`);
|
|
803
|
+
compiler.indentLevel++;
|
|
804
|
+
compiler.emit("override fun onCreate(savedInstanceState: Bundle?) {");
|
|
805
|
+
compiler.indentLevel++;
|
|
806
|
+
compiler.emit("super.onCreate(savedInstanceState)");
|
|
807
|
+
compiler.emit("setContent {");
|
|
808
|
+
compiler.indentLevel++;
|
|
809
|
+
compiler.emit("val engine = rememberEngine()");
|
|
810
|
+
compiler.emit("val materialLoader = rememberMaterialLoader(engine)");
|
|
811
|
+
compiler.emit("val cameraNode = rememberARCameraNode(engine)");
|
|
812
|
+
compiler.emit("");
|
|
813
|
+
compiler.emit("ARScene(");
|
|
814
|
+
compiler.indentLevel++;
|
|
815
|
+
compiler.emit("modifier = Modifier.fillMaxSize(),");
|
|
816
|
+
compiler.emit("engine = engine,");
|
|
817
|
+
compiler.emit("cameraNode = cameraNode,");
|
|
818
|
+
compiler.emit("materialLoader = materialLoader,");
|
|
819
|
+
compiler.emit("planeRenderer = true,");
|
|
820
|
+
compiler.indentLevel--;
|
|
821
|
+
compiler.emit(") {");
|
|
822
|
+
compiler.indentLevel++;
|
|
823
|
+
if (objects.length) {
|
|
824
|
+
objects.forEach((obj, i) => {
|
|
825
|
+
if (i > 0) compiler.emit("");
|
|
826
|
+
emitObjectNode(compiler, obj);
|
|
827
|
+
});
|
|
828
|
+
} else {
|
|
829
|
+
compiler.emit("// No objects in composition \u2014 default placeholder cube at 1m.");
|
|
830
|
+
compiler.emit("CubeNode(");
|
|
978
831
|
compiler.indentLevel++;
|
|
979
|
-
compiler.emit(
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
832
|
+
compiler.emit("size = Size(0.1f),");
|
|
833
|
+
compiler.emit(
|
|
834
|
+
`materialInstance = materialLoader.createColorInstance(${DEFAULT_COMPOSE_COLOR}),`
|
|
835
|
+
);
|
|
836
|
+
compiler.emit("position = Position(x = 0f, y = 0f, z = -1f),");
|
|
983
837
|
compiler.indentLevel--;
|
|
984
|
-
compiler.emit("
|
|
985
|
-
compiler.emit("");
|
|
838
|
+
compiler.emit(")");
|
|
986
839
|
}
|
|
987
840
|
compiler.indentLevel--;
|
|
988
841
|
compiler.emit("}");
|
|
989
842
|
compiler.indentLevel--;
|
|
990
843
|
compiler.emit("}");
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
844
|
+
compiler.indentLevel--;
|
|
845
|
+
compiler.emit("}");
|
|
846
|
+
compiler.indentLevel--;
|
|
847
|
+
compiler.emit("}");
|
|
848
|
+
return compiler.lines.join("\n") + "\n";
|
|
849
|
+
}
|
|
850
|
+
function generateStateFile(_compiler, _composition) {
|
|
851
|
+
return "";
|
|
852
|
+
}
|
|
853
|
+
function generateNodeFactoryFile(_compiler, _composition) {
|
|
854
|
+
return "";
|
|
855
|
+
}
|
|
856
|
+
function generateManifestFile(compiler, composition) {
|
|
857
|
+
const cls = compiler.options.className;
|
|
858
|
+
const hasGeo = hasGeoTraits(composition);
|
|
859
|
+
const hasGeospatialVPS = hasGeospatialVPSTraits(composition);
|
|
860
|
+
const geoPermissions = hasGeo || hasGeospatialVPS ? `
|
|
861
|
+
<!-- Geo-Anchor: Location permissions -->
|
|
862
|
+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
|
863
|
+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />` : "";
|
|
864
|
+
const geospatialApiKeyMeta = hasGeospatialVPS ? `
|
|
865
|
+
<!-- ARCore Geospatial API key (replace with your key from Google Cloud Console) -->
|
|
866
|
+
<meta-data android:name="com.google.android.ar.API_KEY" android:value="\${GEOSPATIAL_API_KEY}" />` : "";
|
|
867
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
868
|
+
<!-- Auto-generated by HoloScript AndroidCompiler -->
|
|
869
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
870
|
+
xmlns:tools="http://schemas.android.com/tools">
|
|
871
|
+
|
|
872
|
+
<!-- AR Required -->
|
|
873
|
+
<uses-permission android:name="android.permission.CAMERA" />
|
|
874
|
+
<uses-feature android:name="android.hardware.camera.ar" android:required="true" />
|
|
875
|
+
|
|
876
|
+
<!-- ARCore Required -->
|
|
877
|
+
<uses-feature android:glEsVersion="0x00030000" android:required="true" />${geoPermissions}
|
|
878
|
+
|
|
879
|
+
<application
|
|
880
|
+
android:allowBackup="true"
|
|
881
|
+
android:label="${compiler.escapeStringValue(composition.name, "XML")}"
|
|
882
|
+
android:supportsRtl="true"
|
|
883
|
+
android:theme="@android:style/Theme.Material.Light.NoActionBar">
|
|
884
|
+
|
|
885
|
+
<!-- ARCore metadata. SceneView's arsceneview AAR declares com.google.ar.core as
|
|
886
|
+
"optional"; this app requires AR, so override the merged value. -->
|
|
887
|
+
<meta-data android:name="com.google.ar.core" android:value="required"
|
|
888
|
+
tools:replace="android:value" />${geospatialApiKeyMeta}
|
|
889
|
+
|
|
890
|
+
<activity
|
|
891
|
+
android:name=".${cls}Activity"
|
|
892
|
+
android:exported="true"
|
|
893
|
+
android:configChanges="orientation|screenSize"
|
|
894
|
+
android:screenOrientation="locked">
|
|
895
|
+
<intent-filter>
|
|
896
|
+
<action android:name="android.intent.action.MAIN" />
|
|
897
|
+
<category android:name="android.intent.category.LAUNCHER" />
|
|
898
|
+
</intent-filter>
|
|
899
|
+
</activity>
|
|
900
|
+
</application>
|
|
901
|
+
</manifest>`;
|
|
902
|
+
}
|
|
903
|
+
function generateBuildGradle(compiler, composition) {
|
|
904
|
+
const pkg = compiler.options.packageName;
|
|
905
|
+
const minSdk = compiler.options.minSdk;
|
|
906
|
+
const sdk = Math.max(36, compiler.options.targetSdk);
|
|
907
|
+
const optionalDependencies = /* @__PURE__ */ new Set();
|
|
908
|
+
if (hasGeoTraits(composition) || hasGeospatialVPSTraits(composition)) {
|
|
909
|
+
optionalDependencies.add(
|
|
910
|
+
'implementation("com.google.android.gms:play-services-location:21.3.0")'
|
|
995
911
|
);
|
|
996
|
-
compiler.indentLevel++;
|
|
997
|
-
compiler.emit("// Bridge to HoloScript spatial_input event system");
|
|
998
|
-
compiler.emit("val event = mapOf(");
|
|
999
|
-
compiler.indentLevel++;
|
|
1000
|
-
compiler.emit('"type" to "hand_gesture",');
|
|
1001
|
-
compiler.emit('"gesture" to gesture,');
|
|
1002
|
-
compiler.emit('"handIndex" to handIndex,');
|
|
1003
|
-
compiler.emit('"x" to x, "y" to y, "z" to z');
|
|
1004
|
-
compiler.indentLevel--;
|
|
1005
|
-
compiler.emit(")");
|
|
1006
|
-
compiler.emit('android.util.Log.d("HoloScript", "SpatialInput: $event")');
|
|
1007
|
-
compiler.indentLevel--;
|
|
1008
|
-
compiler.emit("}");
|
|
1009
912
|
}
|
|
913
|
+
if (hasHandTrackingTraits(composition)) {
|
|
914
|
+
optionalDependencies.add('implementation("androidx.camera:camera-core:1.4.1")');
|
|
915
|
+
optionalDependencies.add('implementation("androidx.camera:camera-camera2:1.4.1")');
|
|
916
|
+
optionalDependencies.add('implementation("androidx.camera:camera-lifecycle:1.4.1")');
|
|
917
|
+
optionalDependencies.add('implementation("com.google.mediapipe:tasks-vision:0.10.20")');
|
|
918
|
+
}
|
|
919
|
+
const optionalDependencyBlock = optionalDependencies.size > 0 ? `
|
|
920
|
+
|
|
921
|
+
// Optional SceneView feature-trait sidecars
|
|
922
|
+
${[...optionalDependencies].join("\n ")}` : "";
|
|
923
|
+
return `// Auto-generated by HoloScript AndroidCompiler
|
|
924
|
+
// Source: ${compiler.escapeStringValue(composition.name, "Kotlin")}
|
|
925
|
+
//
|
|
926
|
+
// SceneView (Apache 2.0) Compose-native AR target \u2014 replaces the EOL Sceneform fork.
|
|
927
|
+
// compileSdk/targetSdk floor at 36: SceneView 4.18.0 pulls androidx.core 1.18.0, which refuses
|
|
928
|
+
// to compile below API 36 and requires Android Gradle Plugin 8.9.1+ and Kotlin 2.3.21 (both
|
|
929
|
+
// declared in the hand-maintained root build.gradle.kts scaffold).
|
|
930
|
+
|
|
931
|
+
plugins {
|
|
932
|
+
id("com.android.application")
|
|
933
|
+
id("org.jetbrains.kotlin.android")
|
|
934
|
+
id("org.jetbrains.kotlin.plugin.compose")
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
android {
|
|
938
|
+
namespace = "${pkg}"
|
|
939
|
+
compileSdk = ${sdk}
|
|
940
|
+
|
|
941
|
+
defaultConfig {
|
|
942
|
+
applicationId = "${pkg}"
|
|
943
|
+
minSdk = ${minSdk}
|
|
944
|
+
targetSdk = ${sdk}
|
|
945
|
+
versionCode = 1
|
|
946
|
+
versionName = "1.0"
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
buildTypes {
|
|
950
|
+
release {
|
|
951
|
+
isMinifyEnabled = false
|
|
952
|
+
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
compileOptions {
|
|
957
|
+
sourceCompatibility = JavaVersion.VERSION_17
|
|
958
|
+
targetCompatibility = JavaVersion.VERSION_17
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
buildFeatures {
|
|
962
|
+
compose = true
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// Kotlin 2.3 removed the kotlinOptions { jvmTarget = "17" } DSL (now a hard error);
|
|
967
|
+
// the JVM target moves to the top-level compilerOptions DSL.
|
|
968
|
+
kotlin {
|
|
969
|
+
compilerOptions {
|
|
970
|
+
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
dependencies {
|
|
975
|
+
implementation("androidx.core:core-ktx:1.13.1")
|
|
976
|
+
implementation("androidx.activity:activity-compose:1.9.3")
|
|
977
|
+
|
|
978
|
+
// Jetpack Compose (BOM matches SceneView 4.18.0's compose surface)
|
|
979
|
+
implementation(platform("androidx.compose:compose-bom:2024.09.03"))
|
|
980
|
+
implementation("androidx.compose.ui:ui")
|
|
981
|
+
implementation("androidx.compose.foundation:foundation")
|
|
982
|
+
implementation("androidx.compose.material3:material3")
|
|
983
|
+
|
|
984
|
+
// SceneView (Apache 2.0) \u2014 Compose-native AR; pulls io.github.sceneview:sceneview + ARCore 1.54.0
|
|
985
|
+
// transitively. Replaces the EOL Sceneform fork. No ArFragment / no R.layout (Compose-native).
|
|
986
|
+
implementation("io.github.sceneview:arsceneview:4.18.0")${optionalDependencyBlock}
|
|
987
|
+
}`;
|
|
1010
988
|
}
|
|
989
|
+
var NAMED_COMPOSE_COLORS, DEFAULT_COMPOSE_COLOR;
|
|
990
|
+
var init_AndroidARGenerators = chunkZHPMP447_cjs.__esm({
|
|
991
|
+
"src/compiler/AndroidARGenerators.ts"() {
|
|
992
|
+
chunkCFVK26P4_cjs.init_AndroidKotlinHelpers();
|
|
993
|
+
init_AndroidSceneViewFeatureGenerators();
|
|
994
|
+
NAMED_COMPOSE_COLORS = {
|
|
995
|
+
red: "Color(0xFFFF0000)",
|
|
996
|
+
green: "Color(0xFF00FF00)",
|
|
997
|
+
blue: "Color(0xFF2196F3)",
|
|
998
|
+
white: "Color(0xFFFFFFFF)",
|
|
999
|
+
black: "Color(0xFF000000)",
|
|
1000
|
+
yellow: "Color(0xFFFFEB3B)",
|
|
1001
|
+
cyan: "Color(0xFF00BCD4)",
|
|
1002
|
+
magenta: "Color(0xFFE91E63)",
|
|
1003
|
+
orange: "Color(0xFFFF9800)"
|
|
1004
|
+
};
|
|
1005
|
+
DEFAULT_COMPOSE_COLOR = "Color(0xFF4488FF)";
|
|
1006
|
+
}
|
|
1007
|
+
});
|
|
1008
|
+
|
|
1009
|
+
// src/compiler/AndroidFeatureGenerators.ts
|
|
1011
1010
|
function hasAuthoringTraits(composition) {
|
|
1012
|
-
const authoringNames =
|
|
1011
|
+
const authoringNames = chunkAWXFEAQL_cjs.SPATIAL_AUTHORING_TRAITS;
|
|
1013
1012
|
for (const obj of composition.objects || []) {
|
|
1014
1013
|
for (const trait of obj.traits || []) {
|
|
1015
1014
|
const name = typeof trait === "string" ? trait : trait.name;
|
|
@@ -1029,76 +1028,31 @@ function emitAuthoringSetup(compiler, composition) {
|
|
|
1029
1028
|
const hasVoice = compiler.compositionHasTrait(composition, "author_voice_cmd");
|
|
1030
1029
|
const hasShake = compiler.compositionHasTrait(composition, "author_shake_undo");
|
|
1031
1030
|
if (hasGyro) {
|
|
1032
|
-
compiler.emit(`private val gyroFilterAlpha = ${
|
|
1031
|
+
compiler.emit(`private val gyroFilterAlpha = ${chunkAWXFEAQL_cjs.SPATIAL_AUTHORING_DEFAULTS.gyroFilterAlpha}f`);
|
|
1033
1032
|
compiler.emit("private var sensorManager: android.hardware.SensorManager? = null");
|
|
1034
1033
|
compiler.emit("private var rotationSensor: android.hardware.Sensor? = null");
|
|
1035
1034
|
}
|
|
1036
1035
|
if (hasPinch) {
|
|
1037
|
-
compiler.emit(`private val pinchScaleMin = ${
|
|
1038
|
-
compiler.emit(`private val pinchScaleMax = ${
|
|
1036
|
+
compiler.emit(`private val pinchScaleMin = ${chunkAWXFEAQL_cjs.SPATIAL_AUTHORING_DEFAULTS.pinchScaleMin}f`);
|
|
1037
|
+
compiler.emit(`private val pinchScaleMax = ${chunkAWXFEAQL_cjs.SPATIAL_AUTHORING_DEFAULTS.pinchScaleMax}f`);
|
|
1039
1038
|
compiler.emit("private var scaleGestureDetector: android.view.ScaleGestureDetector? = null");
|
|
1040
1039
|
}
|
|
1041
1040
|
if (hasSwipe) {
|
|
1042
1041
|
compiler.emit("private var gestureDetector: android.view.GestureDetector? = null");
|
|
1043
1042
|
}
|
|
1044
1043
|
if (hasVoice) {
|
|
1045
|
-
compiler.emit(`private val speechLocale = "${
|
|
1044
|
+
compiler.emit(`private val speechLocale = "${chunkAWXFEAQL_cjs.SPATIAL_AUTHORING_DEFAULTS.speechLocale}"`);
|
|
1046
1045
|
compiler.emit("private var speechRecognizer: android.speech.SpeechRecognizer? = null");
|
|
1047
1046
|
}
|
|
1048
1047
|
if (hasShake) {
|
|
1049
|
-
compiler.emit(`private val shakeThreshold = ${
|
|
1050
|
-
compiler.emit(`private val undoStackDepth = ${
|
|
1048
|
+
compiler.emit(`private val shakeThreshold = ${chunkAWXFEAQL_cjs.SPATIAL_AUTHORING_DEFAULTS.shakeThreshold}f`);
|
|
1049
|
+
compiler.emit(`private val undoStackDepth = ${chunkAWXFEAQL_cjs.SPATIAL_AUTHORING_DEFAULTS.undoStackDepth}`);
|
|
1051
1050
|
compiler.emit("private val undoStack = ArrayDeque<() -> Unit>()");
|
|
1052
1051
|
}
|
|
1053
1052
|
return compiler.lines.join("\n");
|
|
1054
1053
|
}
|
|
1055
|
-
function emitAuthoringInlineSetup(compiler, composition) {
|
|
1056
|
-
compiler.emit("");
|
|
1057
|
-
compiler.emit("// --- Spatial Authoring inline setup (M.010.08) ---");
|
|
1058
|
-
if (compiler.compositionHasTrait(composition, "author_gyro_place")) {
|
|
1059
|
-
compiler.emit("private fun setupGyroPlacement() {");
|
|
1060
|
-
compiler.indentLevel++;
|
|
1061
|
-
compiler.emit(
|
|
1062
|
-
"sensorManager = getSystemService(SENSOR_SERVICE) as android.hardware.SensorManager"
|
|
1063
|
-
);
|
|
1064
|
-
compiler.emit(
|
|
1065
|
-
"rotationSensor = sensorManager?.getDefaultSensor(android.hardware.Sensor.TYPE_ROTATION_VECTOR)"
|
|
1066
|
-
);
|
|
1067
|
-
compiler.indentLevel--;
|
|
1068
|
-
compiler.emit("}");
|
|
1069
|
-
}
|
|
1070
|
-
if (compiler.compositionHasTrait(composition, "author_pinch_scale")) {
|
|
1071
|
-
compiler.emit("private fun setupPinchScale() {");
|
|
1072
|
-
compiler.indentLevel++;
|
|
1073
|
-
compiler.emit(
|
|
1074
|
-
"scaleGestureDetector = android.view.ScaleGestureDetector(this, object : android.view.ScaleGestureDetector.SimpleOnScaleGestureListener() {"
|
|
1075
|
-
);
|
|
1076
|
-
compiler.indentLevel++;
|
|
1077
|
-
compiler.emit("override fun onScale(detector: android.view.ScaleGestureDetector): Boolean {");
|
|
1078
|
-
compiler.indentLevel++;
|
|
1079
|
-
compiler.emit("val factor = detector.scaleFactor.coerceIn(pinchScaleMin, pinchScaleMax)");
|
|
1080
|
-
compiler.emit("selectedNode?.localScale = selectedNode?.localScale?.let { it.scaled(factor) }");
|
|
1081
|
-
compiler.emit("return true");
|
|
1082
|
-
compiler.indentLevel--;
|
|
1083
|
-
compiler.emit("}");
|
|
1084
|
-
compiler.indentLevel--;
|
|
1085
|
-
compiler.emit("})");
|
|
1086
|
-
compiler.indentLevel--;
|
|
1087
|
-
compiler.emit("}");
|
|
1088
|
-
}
|
|
1089
|
-
if (compiler.compositionHasTrait(composition, "author_shake_undo")) {
|
|
1090
|
-
compiler.emit("private fun setupShakeUndo() {");
|
|
1091
|
-
compiler.indentLevel++;
|
|
1092
|
-
compiler.emit(
|
|
1093
|
-
"val accelerometer = sensorManager?.getDefaultSensor(android.hardware.Sensor.TYPE_ACCELEROMETER)"
|
|
1094
|
-
);
|
|
1095
|
-
compiler.emit("// Shake detection triggers undoStack.removeLastOrNull()?.invoke()");
|
|
1096
|
-
compiler.indentLevel--;
|
|
1097
|
-
compiler.emit("}");
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
1054
|
function hasNPUSceneTraits(composition) {
|
|
1101
|
-
const npuNames =
|
|
1055
|
+
const npuNames = chunkN74QRJGP_cjs.NPU_SCENE_TRAITS;
|
|
1102
1056
|
for (const obj of composition.objects || []) {
|
|
1103
1057
|
for (const trait of obj.traits || []) {
|
|
1104
1058
|
const name = typeof trait === "string" ? trait : trait.name;
|
|
@@ -1112,12 +1066,12 @@ function emitNPUSceneSetup(compiler, composition) {
|
|
|
1112
1066
|
compiler.indentLevel = 0;
|
|
1113
1067
|
const pkg = compiler.options.packageName;
|
|
1114
1068
|
const cls = compiler.options.className;
|
|
1115
|
-
const defaults =
|
|
1069
|
+
const defaults = chunkN74QRJGP_cjs.NPU_SCENE_DEFAULTS;
|
|
1116
1070
|
const usedTraits = /* @__PURE__ */ new Set();
|
|
1117
1071
|
for (const obj of composition.objects || []) {
|
|
1118
1072
|
for (const trait of obj.traits || []) {
|
|
1119
1073
|
const name = typeof trait === "string" ? trait : trait.name;
|
|
1120
|
-
if (
|
|
1074
|
+
if (chunkN74QRJGP_cjs.NPU_SCENE_TRAITS.includes(name)) {
|
|
1121
1075
|
usedTraits.add(name);
|
|
1122
1076
|
}
|
|
1123
1077
|
}
|
|
@@ -1327,755 +1281,159 @@ function emitNPUSceneSetup(compiler, composition) {
|
|
|
1327
1281
|
compiler.emit("val scene = arFragment.arSceneView.scene");
|
|
1328
1282
|
compiler.emit("for (detection in detections) {");
|
|
1329
1283
|
compiler.indentLevel++;
|
|
1330
|
-
compiler.emit("val bbox = detection.boundingBox ?: continue");
|
|
1331
|
-
compiler.emit("val centerX = (bbox.left + bbox.right) / 2f");
|
|
1332
|
-
compiler.emit("val centerY = (bbox.top + bbox.bottom) / 2f");
|
|
1333
|
-
compiler.emit("val frame = arFragment.arSceneView.arFrame ?: continue");
|
|
1334
|
-
compiler.emit("val hits = frame.hitTest(centerX, centerY)");
|
|
1335
|
-
compiler.emit("val hit = hits.firstOrNull() ?: continue");
|
|
1336
|
-
compiler.emit("val anchor = hit.createAnchor()");
|
|
1337
|
-
compiler.emit("val anchorNode = com.google.ar.sceneform.AnchorNode(anchor)");
|
|
1338
|
-
compiler.emit("anchorNode.setParent(scene)");
|
|
1339
|
-
compiler.emit("com.google.ar.sceneform.rendering.MaterialFactory");
|
|
1340
|
-
compiler.emit(" .makeOpaqueWithColor(arFragment.requireContext(),");
|
|
1341
|
-
compiler.emit(" com.google.ar.sceneform.rendering.Color(0.2f, 0.6f, 1.0f, 0.6f))");
|
|
1342
|
-
compiler.emit(" .thenAccept { material ->");
|
|
1343
|
-
compiler.indentLevel++;
|
|
1344
|
-
compiler.emit(
|
|
1345
|
-
`val renderable = com.google.ar.sceneform.rendering.ShapeFactory.makeSphere(${defaults.entityScale}f, com.google.ar.sceneform.math.Vector3.zero(), material)`
|
|
1346
|
-
);
|
|
1347
|
-
compiler.emit(
|
|
1348
|
-
"val node = com.google.ar.sceneform.ux.TransformableNode(arFragment.transformationSystem)"
|
|
1349
|
-
);
|
|
1350
|
-
compiler.emit("node.setParent(anchorNode)");
|
|
1351
|
-
compiler.emit("node.renderable = renderable");
|
|
1352
|
-
compiler.emit("node.name = detection.label");
|
|
1353
|
-
compiler.emit('Log.d("HoloScript", "Entity created: ${detection.label}")');
|
|
1354
|
-
compiler.indentLevel--;
|
|
1355
|
-
compiler.emit(" }");
|
|
1356
|
-
compiler.indentLevel--;
|
|
1357
|
-
compiler.emit("}");
|
|
1358
|
-
compiler.indentLevel--;
|
|
1359
|
-
compiler.emit("}");
|
|
1360
|
-
compiler.emit("");
|
|
1361
|
-
}
|
|
1362
|
-
if (usedTraits.has("npu_realtime")) {
|
|
1363
|
-
compiler.emit("// MARK: Realtime Processing (npu_realtime)");
|
|
1364
|
-
compiler.emit("");
|
|
1365
|
-
compiler.emit("fun createImageAnalyzer(): ImageAnalysis.Analyzer {");
|
|
1366
|
-
compiler.indentLevel++;
|
|
1367
|
-
compiler.emit("return ImageAnalysis.Analyzer { imageProxy ->");
|
|
1368
|
-
compiler.indentLevel++;
|
|
1369
|
-
compiler.emit("frameCounter++");
|
|
1370
|
-
compiler.emit("val now = System.currentTimeMillis()");
|
|
1371
|
-
compiler.emit("val intervalMs = 1000L / targetFPS");
|
|
1372
|
-
compiler.emit("if (now - lastProcessTimeMs < intervalMs) {");
|
|
1373
|
-
compiler.indentLevel++;
|
|
1374
|
-
compiler.emit("imageProxy.close()");
|
|
1375
|
-
compiler.emit("return@Analyzer");
|
|
1376
|
-
compiler.indentLevel--;
|
|
1377
|
-
compiler.emit("}");
|
|
1378
|
-
compiler.emit("lastProcessTimeMs = now");
|
|
1379
|
-
compiler.emit("_isProcessing.value = true");
|
|
1380
|
-
compiler.emit("");
|
|
1381
|
-
compiler.emit("@androidx.camera.core.ExperimentalGetImage");
|
|
1382
|
-
compiler.emit("val mediaImage = imageProxy.image");
|
|
1383
|
-
compiler.emit("if (mediaImage != null) {");
|
|
1384
|
-
compiler.indentLevel++;
|
|
1385
|
-
compiler.emit(
|
|
1386
|
-
"val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)"
|
|
1387
|
-
);
|
|
1388
|
-
if (usedTraits.has("npu_classify")) {
|
|
1389
|
-
compiler.emit("classifyImage(image)");
|
|
1390
|
-
}
|
|
1391
|
-
if (usedTraits.has("npu_detect")) {
|
|
1392
|
-
compiler.emit("detectObjects(image)");
|
|
1393
|
-
}
|
|
1394
|
-
if (usedTraits.has("npu_segment")) {
|
|
1395
|
-
compiler.emit("segmentScene(image)");
|
|
1396
|
-
}
|
|
1397
|
-
compiler.indentLevel--;
|
|
1398
|
-
compiler.emit("}");
|
|
1399
|
-
compiler.emit("_isProcessing.value = false");
|
|
1400
|
-
compiler.emit("imageProxy.close()");
|
|
1401
|
-
compiler.indentLevel--;
|
|
1402
|
-
compiler.emit("}");
|
|
1403
|
-
compiler.indentLevel--;
|
|
1404
|
-
compiler.emit("}");
|
|
1405
|
-
compiler.emit("");
|
|
1406
|
-
}
|
|
1407
|
-
if (usedTraits.has("npu_model_custom")) {
|
|
1408
|
-
compiler.emit("// MARK: Custom Model (npu_model_custom)");
|
|
1409
|
-
compiler.emit("");
|
|
1410
|
-
compiler.emit("private var customInterpreter: Interpreter? = null");
|
|
1411
|
-
compiler.emit("");
|
|
1412
|
-
compiler.emit("fun loadCustomModel(context: android.content.Context, assetPath: String) {");
|
|
1413
|
-
compiler.indentLevel++;
|
|
1414
|
-
compiler.emit("val localModel = LocalModel.Builder()");
|
|
1415
|
-
compiler.emit(" .setAssetFilePath(assetPath)");
|
|
1416
|
-
compiler.emit(" .build()");
|
|
1417
|
-
compiler.emit("");
|
|
1418
|
-
compiler.emit("// NNAPI delegate for hardware acceleration");
|
|
1419
|
-
compiler.emit("val nnApiDelegate = NnApiDelegate()");
|
|
1420
|
-
compiler.emit("val options = Interpreter.Options().addDelegate(nnApiDelegate)");
|
|
1421
|
-
compiler.emit("");
|
|
1422
|
-
compiler.emit("val modelFile = context.assets.open(assetPath)");
|
|
1423
|
-
compiler.emit("val buffer = modelFile.readBytes()");
|
|
1424
|
-
compiler.emit("val byteBuffer = java.nio.ByteBuffer.allocateDirect(buffer.size)");
|
|
1425
|
-
compiler.emit("byteBuffer.put(buffer)");
|
|
1426
|
-
compiler.emit("customInterpreter = Interpreter(byteBuffer, options)");
|
|
1427
|
-
compiler.emit('Log.d("HoloScript", "Custom model loaded with NNAPI: $assetPath")');
|
|
1428
|
-
compiler.indentLevel--;
|
|
1429
|
-
compiler.emit("}");
|
|
1430
|
-
compiler.emit("");
|
|
1431
|
-
}
|
|
1432
|
-
if (usedTraits.has("npu_label_overlay")) {
|
|
1433
|
-
compiler.emit("// MARK: Label Overlay (npu_label_overlay)");
|
|
1434
|
-
compiler.emit("");
|
|
1435
|
-
compiler.emit("fun createLabelOverlay(");
|
|
1436
|
-
compiler.emit(" detection: NPUDetection,");
|
|
1437
|
-
compiler.emit(" arFragment: com.google.ar.sceneform.ux.ArFragment,");
|
|
1438
|
-
compiler.emit(" anchorNode: com.google.ar.sceneform.AnchorNode");
|
|
1439
|
-
compiler.emit(") {");
|
|
1440
|
-
compiler.indentLevel++;
|
|
1441
|
-
compiler.emit("com.google.ar.sceneform.rendering.ViewRenderable.builder()");
|
|
1442
|
-
compiler.emit(
|
|
1443
|
-
" .setView(arFragment.requireContext(), android.widget.TextView(arFragment.requireContext()).apply {"
|
|
1444
|
-
);
|
|
1445
|
-
compiler.indentLevel++;
|
|
1446
|
-
compiler.emit('text = "${detection.label} (${(detection.confidence * 100).toInt()}%)"');
|
|
1447
|
-
compiler.emit("setTextColor(android.graphics.Color.WHITE)");
|
|
1448
|
-
compiler.emit("setBackgroundColor(android.graphics.Color.argb(180, 0, 0, 0))");
|
|
1449
|
-
compiler.emit("setPadding(12, 6, 12, 6)");
|
|
1450
|
-
compiler.emit("textSize = 12f");
|
|
1451
|
-
compiler.indentLevel--;
|
|
1452
|
-
compiler.emit(" })");
|
|
1453
|
-
compiler.emit(" .build()");
|
|
1454
|
-
compiler.emit(" .thenAccept { renderable ->");
|
|
1455
|
-
compiler.indentLevel++;
|
|
1456
|
-
compiler.emit("val labelNode = com.google.ar.sceneform.Node()");
|
|
1457
|
-
compiler.emit("labelNode.setParent(anchorNode)");
|
|
1458
|
-
compiler.emit(
|
|
1459
|
-
`labelNode.localPosition = com.google.ar.sceneform.math.Vector3(0f, ${defaults.labelOffsetY}f, 0f)`
|
|
1460
|
-
);
|
|
1461
|
-
compiler.emit("labelNode.renderable = renderable");
|
|
1462
|
-
compiler.emit('Log.d("HoloScript", "Label overlay: ${detection.label}")');
|
|
1463
|
-
compiler.indentLevel--;
|
|
1464
|
-
compiler.emit(" }");
|
|
1465
|
-
compiler.indentLevel--;
|
|
1466
|
-
compiler.emit("}");
|
|
1467
|
-
compiler.emit("");
|
|
1468
|
-
}
|
|
1469
|
-
compiler.indentLevel--;
|
|
1470
|
-
compiler.emit("}");
|
|
1471
|
-
return compiler.lines.join("\n");
|
|
1472
|
-
}
|
|
1473
|
-
var init_AndroidFeatureGenerators = chunkHCCQLAA4_cjs.__esm({
|
|
1474
|
-
"src/compiler/AndroidFeatureGenerators.ts"() {
|
|
1475
|
-
chunkDTGBOSEM_cjs.init_geospatial();
|
|
1476
|
-
chunkDTGBOSEM_cjs.init_depth_scanner();
|
|
1477
|
-
chunk6EX3I5P4_cjs.init_portal_ar();
|
|
1478
|
-
chunk6EX3I5P4_cjs.init_camera_hand_tracking();
|
|
1479
|
-
chunk6EX3I5P4_cjs.init_npu_scene();
|
|
1480
|
-
chunkDTGBOSEM_cjs.init_spatial_authoring();
|
|
1481
|
-
}
|
|
1482
|
-
});
|
|
1483
|
-
|
|
1484
|
-
// src/compiler/AndroidARGenerators.ts
|
|
1485
|
-
function toKotlinFloatLiteral(value, fallback) {
|
|
1486
|
-
const numeric = typeof value === "number" ? value : Number(value);
|
|
1487
|
-
const resolved = Number.isFinite(numeric) ? numeric : fallback;
|
|
1488
|
-
return `${resolved}f`;
|
|
1489
|
-
}
|
|
1490
|
-
function toKotlinVector3(value, fallback) {
|
|
1491
|
-
const components = Array.isArray(value) && value.length >= 3 ? [value[0], value[1], value[2]] : typeof value === "number" ? [value, value, value] : fallback;
|
|
1492
|
-
return `Vector3(${components.map((component, index) => toKotlinFloatLiteral(component, fallback[index])).join(", ")})`;
|
|
1493
|
-
}
|
|
1494
|
-
function generateActivityFile(compiler, composition) {
|
|
1495
|
-
compiler.lines = [];
|
|
1496
|
-
compiler.indentLevel = 0;
|
|
1497
|
-
const pkg = compiler.options.packageName;
|
|
1498
|
-
const cls = compiler.options.className;
|
|
1499
|
-
compiler.emit("// Auto-generated by HoloScript AndroidCompiler");
|
|
1500
|
-
compiler.emit(
|
|
1501
|
-
`// Source: composition "${compiler.escapeStringValue(composition.name, "Kotlin")}"`
|
|
1502
|
-
);
|
|
1503
|
-
compiler.emit("// Do not edit manually \u2014 regenerate from .holo source");
|
|
1504
|
-
compiler.emit("");
|
|
1505
|
-
compiler.emit(`package ${pkg}`);
|
|
1506
|
-
compiler.emit("");
|
|
1507
|
-
compiler.emit("import android.os.Bundle");
|
|
1508
|
-
compiler.emit("import android.view.MotionEvent");
|
|
1509
|
-
compiler.emit("import android.view.View");
|
|
1510
|
-
compiler.emit("import android.widget.Toast");
|
|
1511
|
-
compiler.emit("import androidx.appcompat.app.AppCompatActivity");
|
|
1512
|
-
compiler.emit("import androidx.lifecycle.ViewModelProvider");
|
|
1513
|
-
compiler.emit("import com.google.ar.core.*");
|
|
1514
|
-
compiler.emit("import com.google.ar.core.exceptions.*");
|
|
1515
|
-
compiler.emit("import com.google.ar.sceneform.*");
|
|
1516
|
-
compiler.emit("import com.google.ar.sceneform.math.Vector3");
|
|
1517
|
-
compiler.emit("import com.google.ar.sceneform.rendering.*");
|
|
1518
|
-
compiler.emit("import com.google.ar.sceneform.ux.*");
|
|
1519
|
-
compiler.emit("import java.util.concurrent.CompletableFuture");
|
|
1520
|
-
compiler.emit("");
|
|
1521
|
-
compiler.emit(`class ${cls}Activity : AppCompatActivity() {`);
|
|
1522
|
-
compiler.indentLevel++;
|
|
1523
|
-
compiler.emit("private lateinit var arFragment: ArFragment");
|
|
1524
|
-
compiler.emit("private lateinit var sceneState: SceneState");
|
|
1525
|
-
compiler.emit("private val placedNodes = mutableMapOf<String, TransformableNode>()");
|
|
1526
|
-
compiler.emit("");
|
|
1527
|
-
compiler.emit("override fun onCreate(savedInstanceState: Bundle?) {");
|
|
1528
|
-
compiler.indentLevel++;
|
|
1529
|
-
compiler.emit("super.onCreate(savedInstanceState)");
|
|
1530
|
-
compiler.emit(`setContentView(R.layout.activity_ar_scene)`);
|
|
1531
|
-
compiler.emit("");
|
|
1532
|
-
compiler.emit("sceneState = ViewModelProvider(this)[SceneState::class.java]");
|
|
1533
|
-
compiler.emit(
|
|
1534
|
-
"arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as ArFragment"
|
|
1535
|
-
);
|
|
1536
|
-
compiler.emit("");
|
|
1537
|
-
compiler.emit("setupARSession()");
|
|
1538
|
-
compiler.emit("setupTapListener()");
|
|
1539
|
-
compiler.emit("setupUI()");
|
|
1540
|
-
if (hasGeoTraits(composition)) {
|
|
1541
|
-
compiler.emit("setupGeoAnchors()");
|
|
1542
|
-
}
|
|
1543
|
-
if (hasGeospatialVPSTraits(composition)) {
|
|
1544
|
-
compiler.emit("setupGeospatialVPS()");
|
|
1545
|
-
}
|
|
1546
|
-
if (hasDepthScanTraits(composition)) {
|
|
1547
|
-
compiler.emit("setupDepthScanner()");
|
|
1548
|
-
}
|
|
1549
|
-
if (hasPortalARTraits(composition)) {
|
|
1550
|
-
compiler.emit("setupPortalAR()");
|
|
1551
|
-
}
|
|
1552
|
-
if (hasHandTrackingTraits(composition)) {
|
|
1553
|
-
compiler.emit("setupHandTracking()");
|
|
1554
|
-
}
|
|
1555
|
-
if (hasAuthoringTraits(composition)) {
|
|
1556
|
-
compiler.emit("setupSpatialAuthoring()");
|
|
1557
|
-
}
|
|
1558
|
-
compiler.indentLevel--;
|
|
1559
|
-
compiler.emit("}");
|
|
1560
|
-
compiler.emit("");
|
|
1561
|
-
compiler.emit("private fun setupARSession() {");
|
|
1562
|
-
compiler.indentLevel++;
|
|
1563
|
-
compiler.emit("arFragment.arSceneView.scene.addOnUpdateListener { frameTime ->");
|
|
1564
|
-
compiler.indentLevel++;
|
|
1565
|
-
compiler.emit("val frame = arFragment.arSceneView.arFrame ?: return@addOnUpdateListener");
|
|
1566
|
-
compiler.emit("");
|
|
1567
|
-
compiler.emit("// Track planes");
|
|
1568
|
-
compiler.emit("for (plane in frame.getUpdatedTrackables(Plane::class.java)) {");
|
|
1569
|
-
compiler.indentLevel++;
|
|
1570
|
-
compiler.emit("if (plane.trackingState == TrackingState.TRACKING) {");
|
|
1571
|
-
compiler.indentLevel++;
|
|
1572
|
-
compiler.emit("sceneState.onPlaneDetected(plane)");
|
|
1573
|
-
compiler.indentLevel--;
|
|
1574
|
-
compiler.emit("}");
|
|
1575
|
-
compiler.indentLevel--;
|
|
1576
|
-
compiler.emit("}");
|
|
1577
|
-
compiler.indentLevel--;
|
|
1578
|
-
compiler.emit("}");
|
|
1579
|
-
compiler.indentLevel--;
|
|
1580
|
-
compiler.emit("}");
|
|
1581
|
-
compiler.emit("");
|
|
1582
|
-
compiler.emit("private fun setupTapListener() {");
|
|
1583
|
-
compiler.indentLevel++;
|
|
1584
|
-
compiler.emit("arFragment.setOnTapArPlaneListener { hitResult, plane, motionEvent ->");
|
|
1585
|
-
compiler.indentLevel++;
|
|
1586
|
-
compiler.emit(
|
|
1587
|
-
"if (plane.type != Plane.Type.HORIZONTAL_UPWARD_FACING) return@setOnTapArPlaneListener"
|
|
1588
|
-
);
|
|
1589
|
-
compiler.emit("");
|
|
1590
|
-
compiler.emit("placeObject(hitResult)");
|
|
1591
|
-
compiler.indentLevel--;
|
|
1592
|
-
compiler.emit("}");
|
|
1593
|
-
compiler.indentLevel--;
|
|
1594
|
-
compiler.emit("}");
|
|
1595
|
-
compiler.emit("");
|
|
1596
|
-
compiler.emit("private fun placeObject(hitResult: HitResult) {");
|
|
1597
|
-
compiler.indentLevel++;
|
|
1598
|
-
compiler.emit("val anchor = hitResult.createAnchor()");
|
|
1599
|
-
compiler.emit("val anchorNode = AnchorNode(anchor)");
|
|
1600
|
-
compiler.emit("anchorNode.setParent(arFragment.arSceneView.scene)");
|
|
1601
|
-
compiler.emit("");
|
|
1602
|
-
if (composition.objects?.length) {
|
|
1603
|
-
compiler.emit("// Create one renderable node per HoloScript object");
|
|
1604
|
-
for (const obj of composition.objects) {
|
|
1605
|
-
const methodName = `create${compiler.sanitizeName(obj.name)}`;
|
|
1606
|
-
const objectName = compiler.escapeStringValue(obj.name, "Kotlin");
|
|
1607
|
-
const position = toKotlinVector3(compiler.findObjProp(obj, "position"), [0, 0, 0]);
|
|
1608
|
-
const scale = toKotlinVector3(compiler.findObjProp(obj, "scale"), [1, 1, 1]);
|
|
1609
|
-
compiler.emit(`NodeFactory.${methodName}(this) { renderable ->`);
|
|
1610
|
-
compiler.indentLevel++;
|
|
1611
|
-
compiler.emit(
|
|
1612
|
-
`attachRenderableToAnchor(anchorNode, "${objectName}", renderable, ${position}, ${scale})`
|
|
1613
|
-
);
|
|
1614
|
-
compiler.indentLevel--;
|
|
1615
|
-
compiler.emit("}");
|
|
1616
|
-
}
|
|
1617
|
-
} else {
|
|
1618
|
-
compiler.emit("// Create fallback node for empty scenes");
|
|
1619
|
-
compiler.emit("NodeFactory.createDefaultNode(this) { renderable ->");
|
|
1620
|
-
compiler.indentLevel++;
|
|
1621
|
-
compiler.emit(
|
|
1622
|
-
'attachRenderableToAnchor(anchorNode, "default", renderable, Vector3(0f, 0f, 0f), Vector3(1f, 1f, 1f))'
|
|
1623
|
-
);
|
|
1624
|
-
compiler.indentLevel--;
|
|
1625
|
-
compiler.emit("}");
|
|
1626
|
-
}
|
|
1627
|
-
compiler.indentLevel--;
|
|
1628
|
-
compiler.emit("}");
|
|
1629
|
-
compiler.emit("");
|
|
1630
|
-
compiler.emit("private fun attachRenderableToAnchor(");
|
|
1631
|
-
compiler.indentLevel++;
|
|
1632
|
-
compiler.emit("anchorNode: AnchorNode,");
|
|
1633
|
-
compiler.emit("objectName: String,");
|
|
1634
|
-
compiler.emit("renderable: Renderable,");
|
|
1635
|
-
compiler.emit("localPosition: Vector3,");
|
|
1636
|
-
compiler.emit("localScale: Vector3");
|
|
1637
|
-
compiler.indentLevel--;
|
|
1638
|
-
compiler.emit(") {");
|
|
1639
|
-
compiler.indentLevel++;
|
|
1640
|
-
compiler.emit("val transformableNode = TransformableNode(arFragment.transformationSystem)");
|
|
1641
|
-
compiler.emit("transformableNode.setParent(anchorNode)");
|
|
1642
|
-
compiler.emit("transformableNode.renderable = renderable");
|
|
1643
|
-
compiler.emit("transformableNode.localPosition = localPosition");
|
|
1644
|
-
compiler.emit("transformableNode.localScale = localScale");
|
|
1645
|
-
compiler.emit("transformableNode.select()");
|
|
1646
|
-
compiler.emit("");
|
|
1647
|
-
compiler.emit('val id = "$objectName-${java.util.UUID.randomUUID()}"');
|
|
1648
|
-
compiler.emit("placedNodes[id] = transformableNode");
|
|
1649
|
-
compiler.emit("");
|
|
1650
|
-
compiler.emit("// Setup interaction");
|
|
1651
|
-
compiler.emit("transformableNode.setOnTapListener { _, _ ->");
|
|
1652
|
-
compiler.indentLevel++;
|
|
1653
|
-
compiler.emit("sceneState.onNodeTapped(id)");
|
|
1654
|
-
compiler.emit("animateNodeTap(transformableNode)");
|
|
1655
|
-
compiler.indentLevel--;
|
|
1656
|
-
compiler.emit("}");
|
|
1657
|
-
compiler.emit("");
|
|
1658
|
-
compiler.emit('android.util.Log.d("HoloScript", "Placed object: $objectName as $id")');
|
|
1659
|
-
compiler.indentLevel--;
|
|
1660
|
-
compiler.emit("}");
|
|
1661
|
-
compiler.emit("");
|
|
1662
|
-
compiler.emit("private fun animateNodeTap(node: TransformableNode) {");
|
|
1663
|
-
compiler.indentLevel++;
|
|
1664
|
-
compiler.emit("val originalScale = node.localScale");
|
|
1665
|
-
compiler.emit(
|
|
1666
|
-
"val scaledUp = Vector3(originalScale[0] * 1.2f, originalScale[1] * 1.2f, originalScale[2] * 1.2f)"
|
|
1667
|
-
);
|
|
1668
|
-
compiler.emit("");
|
|
1669
|
-
compiler.emit("android.animation.ObjectAnimator.ofObject(");
|
|
1670
|
-
compiler.indentLevel++;
|
|
1671
|
-
compiler.emit('node, "localScale",');
|
|
1672
|
-
compiler.emit("com.google.ar.sceneform.math.Vector3Evaluator(),");
|
|
1673
|
-
compiler.emit("originalScale, scaledUp, originalScale");
|
|
1674
|
-
compiler.indentLevel--;
|
|
1675
|
-
compiler.emit(").apply {");
|
|
1676
|
-
compiler.indentLevel++;
|
|
1677
|
-
compiler.emit("duration = 200");
|
|
1678
|
-
compiler.emit("start()");
|
|
1679
|
-
compiler.indentLevel--;
|
|
1680
|
-
compiler.emit("}");
|
|
1681
|
-
compiler.indentLevel--;
|
|
1682
|
-
compiler.emit("}");
|
|
1683
|
-
compiler.emit("");
|
|
1684
|
-
compiler.emit("private fun setupUI() {");
|
|
1685
|
-
compiler.indentLevel++;
|
|
1686
|
-
compiler.emit("findViewById<View>(R.id.reset_button)?.setOnClickListener {");
|
|
1687
|
-
compiler.indentLevel++;
|
|
1688
|
-
compiler.emit("resetScene()");
|
|
1689
|
-
compiler.indentLevel--;
|
|
1690
|
-
compiler.emit("}");
|
|
1691
|
-
compiler.indentLevel--;
|
|
1692
|
-
compiler.emit("}");
|
|
1693
|
-
compiler.emit("");
|
|
1694
|
-
compiler.emit("private fun resetScene() {");
|
|
1695
|
-
compiler.indentLevel++;
|
|
1696
|
-
compiler.emit("for (node in placedNodes.values) {");
|
|
1697
|
-
compiler.indentLevel++;
|
|
1698
|
-
compiler.emit("node.anchor?.detach()");
|
|
1699
|
-
compiler.emit("node.setParent(null)");
|
|
1700
|
-
compiler.indentLevel--;
|
|
1701
|
-
compiler.emit("}");
|
|
1702
|
-
compiler.emit("placedNodes.clear()");
|
|
1703
|
-
compiler.emit("");
|
|
1704
|
-
compiler.emit("sceneState.reset()");
|
|
1705
|
-
compiler.emit('Toast.makeText(this, "Scene reset", Toast.LENGTH_SHORT).show()');
|
|
1706
|
-
compiler.indentLevel--;
|
|
1707
|
-
compiler.emit("}");
|
|
1708
|
-
compiler.emit("");
|
|
1709
|
-
compiler.emit("override fun onResume() {");
|
|
1710
|
-
compiler.indentLevel++;
|
|
1711
|
-
compiler.emit("super.onResume()");
|
|
1712
|
-
compiler.emit("checkARCoreAvailability()");
|
|
1713
|
-
compiler.indentLevel--;
|
|
1714
|
-
compiler.emit("}");
|
|
1715
|
-
compiler.emit("");
|
|
1716
|
-
compiler.emit("private fun checkARCoreAvailability() {");
|
|
1717
|
-
compiler.indentLevel++;
|
|
1718
|
-
compiler.emit("val availability = ArCoreApk.getInstance().checkAvailability(this)");
|
|
1719
|
-
compiler.emit("if (availability.isTransient) {");
|
|
1720
|
-
compiler.indentLevel++;
|
|
1721
|
-
compiler.emit("android.os.Handler(mainLooper).postDelayed({ checkARCoreAvailability() }, 200)");
|
|
1722
|
-
compiler.emit("return");
|
|
1723
|
-
compiler.indentLevel--;
|
|
1724
|
-
compiler.emit("}");
|
|
1725
|
-
compiler.emit("if (!availability.isSupported) {");
|
|
1726
|
-
compiler.indentLevel++;
|
|
1727
|
-
compiler.emit(
|
|
1728
|
-
'Toast.makeText(this, "ARCore is not supported on this device", Toast.LENGTH_LONG).show()'
|
|
1729
|
-
);
|
|
1730
|
-
compiler.emit("finish()");
|
|
1731
|
-
compiler.indentLevel--;
|
|
1732
|
-
compiler.emit("}");
|
|
1733
|
-
compiler.indentLevel--;
|
|
1734
|
-
compiler.emit("}");
|
|
1735
|
-
if (hasGeoTraits(composition)) {
|
|
1736
|
-
emitGeoAnchorSetup(compiler, composition);
|
|
1737
|
-
}
|
|
1738
|
-
if (hasGeospatialVPSTraits(composition)) {
|
|
1739
|
-
emitGeospatialVPSSetup(compiler, composition);
|
|
1740
|
-
}
|
|
1741
|
-
if (hasDepthScanTraits(composition)) {
|
|
1742
|
-
emitDepthScanSetup(compiler, composition);
|
|
1743
|
-
}
|
|
1744
|
-
if (hasPortalARTraits(composition)) {
|
|
1745
|
-
emitPortalARSetup(compiler, composition);
|
|
1746
|
-
}
|
|
1747
|
-
if (hasHandTrackingTraits(composition)) {
|
|
1748
|
-
emitHandTrackingSetup(compiler, composition);
|
|
1749
|
-
}
|
|
1750
|
-
if (hasAuthoringTraits(composition)) {
|
|
1751
|
-
emitAuthoringInlineSetup(compiler, composition);
|
|
1752
|
-
}
|
|
1753
|
-
compiler.indentLevel--;
|
|
1754
|
-
compiler.emit("}");
|
|
1755
|
-
return compiler.lines.join("\n");
|
|
1756
|
-
}
|
|
1757
|
-
function generateStateFile(compiler, composition) {
|
|
1758
|
-
compiler.lines = [];
|
|
1759
|
-
compiler.indentLevel = 0;
|
|
1760
|
-
const pkg = compiler.options.packageName;
|
|
1761
|
-
compiler.emit("// Auto-generated by HoloScript AndroidCompiler");
|
|
1762
|
-
compiler.emit(`// State: ${compiler.escapeStringValue(composition.name, "Kotlin")}`);
|
|
1763
|
-
compiler.emit("");
|
|
1764
|
-
compiler.emit(`package ${pkg}`);
|
|
1765
|
-
compiler.emit("");
|
|
1766
|
-
compiler.emit("import androidx.lifecycle.ViewModel");
|
|
1767
|
-
compiler.emit("import androidx.lifecycle.MutableLiveData");
|
|
1768
|
-
compiler.emit("import androidx.lifecycle.LiveData");
|
|
1769
|
-
compiler.emit("import com.google.ar.core.Plane");
|
|
1770
|
-
compiler.emit("");
|
|
1771
|
-
compiler.emit("class SceneState : ViewModel() {");
|
|
1772
|
-
compiler.indentLevel++;
|
|
1773
|
-
if (composition.state) {
|
|
1774
|
-
compiler.emit("// === State Properties ===");
|
|
1775
|
-
for (const prop of composition.state.properties) {
|
|
1776
|
-
const kotlinType = compiler.toKotlinType(prop.value);
|
|
1777
|
-
const kotlinValue = compiler.toKotlinValue(prop.value);
|
|
1778
|
-
compiler.emit(
|
|
1779
|
-
`private val _${compiler.escapeStringValue(prop.key, "Kotlin")} = MutableLiveData(${kotlinValue})`
|
|
1780
|
-
);
|
|
1781
|
-
compiler.emit(
|
|
1782
|
-
`val ${compiler.escapeStringValue(prop.key, "Kotlin")}: LiveData<${kotlinType}> get() = _${compiler.escapeStringValue(prop.key, "Kotlin")}`
|
|
1783
|
-
);
|
|
1784
|
-
compiler.emit("");
|
|
1785
|
-
}
|
|
1786
|
-
}
|
|
1787
|
-
compiler.emit("// === AR State ===");
|
|
1788
|
-
compiler.emit("private val _detectedPlanes = MutableLiveData<List<Plane>>(emptyList())");
|
|
1789
|
-
compiler.emit("val detectedPlanes: LiveData<List<Plane>> get() = _detectedPlanes");
|
|
1790
|
-
compiler.emit("");
|
|
1791
|
-
compiler.emit("private val _tappedNodes = MutableLiveData<String?>()");
|
|
1792
|
-
compiler.emit("val tappedNodes: LiveData<String?> get() = _tappedNodes");
|
|
1793
|
-
compiler.emit("");
|
|
1794
|
-
compiler.emit("fun onPlaneDetected(plane: Plane) {");
|
|
1795
|
-
compiler.indentLevel++;
|
|
1796
|
-
compiler.emit("val current = _detectedPlanes.value.orEmpty().toMutableList()");
|
|
1797
|
-
compiler.emit("if (!current.contains(plane)) {");
|
|
1798
|
-
compiler.indentLevel++;
|
|
1799
|
-
compiler.emit("current.add(plane)");
|
|
1800
|
-
compiler.emit("_detectedPlanes.value = current");
|
|
1801
|
-
compiler.emit('android.util.Log.d("HoloScript", "Plane detected: ${plane.type}")');
|
|
1802
|
-
compiler.indentLevel--;
|
|
1803
|
-
compiler.emit("}");
|
|
1804
|
-
compiler.indentLevel--;
|
|
1805
|
-
compiler.emit("}");
|
|
1806
|
-
compiler.emit("");
|
|
1807
|
-
compiler.emit("fun onNodeTapped(nodeId: String) {");
|
|
1808
|
-
compiler.indentLevel++;
|
|
1809
|
-
compiler.emit("_tappedNodes.value = nodeId");
|
|
1810
|
-
compiler.emit('android.util.Log.d("HoloScript", "Node tapped: $nodeId")');
|
|
1811
|
-
compiler.indentLevel--;
|
|
1812
|
-
compiler.emit("}");
|
|
1813
|
-
compiler.emit("");
|
|
1814
|
-
compiler.emit("fun reset() {");
|
|
1815
|
-
compiler.indentLevel++;
|
|
1816
|
-
compiler.emit("_detectedPlanes.value = emptyList()");
|
|
1817
|
-
compiler.emit("_tappedNodes.value = null");
|
|
1818
|
-
if (composition.state) {
|
|
1819
|
-
for (const prop of composition.state.properties) {
|
|
1820
|
-
const kotlinValue = compiler.toKotlinValue(prop.value);
|
|
1821
|
-
compiler.emit(
|
|
1822
|
-
`_${compiler.escapeStringValue(prop.key, "Kotlin")}.value = ${kotlinValue}`
|
|
1823
|
-
);
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
compiler.emit('android.util.Log.d("HoloScript", "State reset")');
|
|
1827
|
-
compiler.indentLevel--;
|
|
1828
|
-
compiler.emit("}");
|
|
1829
|
-
if (composition.logic?.actions) {
|
|
1284
|
+
compiler.emit("val bbox = detection.boundingBox ?: continue");
|
|
1285
|
+
compiler.emit("val centerX = (bbox.left + bbox.right) / 2f");
|
|
1286
|
+
compiler.emit("val centerY = (bbox.top + bbox.bottom) / 2f");
|
|
1287
|
+
compiler.emit("val frame = arFragment.arSceneView.arFrame ?: continue");
|
|
1288
|
+
compiler.emit("val hits = frame.hitTest(centerX, centerY)");
|
|
1289
|
+
compiler.emit("val hit = hits.firstOrNull() ?: continue");
|
|
1290
|
+
compiler.emit("val anchor = hit.createAnchor()");
|
|
1291
|
+
compiler.emit("val anchorNode = com.google.ar.sceneform.AnchorNode(anchor)");
|
|
1292
|
+
compiler.emit("anchorNode.setParent(scene)");
|
|
1293
|
+
compiler.emit("com.google.ar.sceneform.rendering.MaterialFactory");
|
|
1294
|
+
compiler.emit(" .makeOpaqueWithColor(arFragment.requireContext(),");
|
|
1295
|
+
compiler.emit(" com.google.ar.sceneform.rendering.Color(0.2f, 0.6f, 1.0f, 0.6f))");
|
|
1296
|
+
compiler.emit(" .thenAccept { material ->");
|
|
1297
|
+
compiler.indentLevel++;
|
|
1298
|
+
compiler.emit(
|
|
1299
|
+
`val renderable = com.google.ar.sceneform.rendering.ShapeFactory.makeSphere(${defaults.entityScale}f, com.google.ar.sceneform.math.Vector3.zero(), material)`
|
|
1300
|
+
);
|
|
1301
|
+
compiler.emit(
|
|
1302
|
+
"val node = com.google.ar.sceneform.ux.TransformableNode(arFragment.transformationSystem)"
|
|
1303
|
+
);
|
|
1304
|
+
compiler.emit("node.setParent(anchorNode)");
|
|
1305
|
+
compiler.emit("node.renderable = renderable");
|
|
1306
|
+
compiler.emit("node.name = detection.label");
|
|
1307
|
+
compiler.emit('Log.d("HoloScript", "Entity created: ${detection.label}")');
|
|
1308
|
+
compiler.indentLevel--;
|
|
1309
|
+
compiler.emit(" }");
|
|
1310
|
+
compiler.indentLevel--;
|
|
1311
|
+
compiler.emit("}");
|
|
1312
|
+
compiler.indentLevel--;
|
|
1313
|
+
compiler.emit("}");
|
|
1830
1314
|
compiler.emit("");
|
|
1831
|
-
compiler.emit("// === Actions ===");
|
|
1832
|
-
for (const action of composition.logic.actions) {
|
|
1833
|
-
compileAction(compiler, action);
|
|
1834
|
-
}
|
|
1835
1315
|
}
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
function generateNodeFactoryFile(compiler, composition) {
|
|
1841
|
-
compiler.lines = [];
|
|
1842
|
-
compiler.indentLevel = 0;
|
|
1843
|
-
const pkg = compiler.options.packageName;
|
|
1844
|
-
compiler.emit("// Auto-generated by HoloScript AndroidCompiler");
|
|
1845
|
-
compiler.emit(
|
|
1846
|
-
`// Node Factory: ${compiler.escapeStringValue(composition.name, "Kotlin")}`
|
|
1847
|
-
);
|
|
1848
|
-
compiler.emit("");
|
|
1849
|
-
compiler.emit(`package ${pkg}`);
|
|
1850
|
-
compiler.emit("");
|
|
1851
|
-
compiler.emit("import android.content.Context");
|
|
1852
|
-
compiler.emit("import com.google.ar.sceneform.math.Vector3");
|
|
1853
|
-
compiler.emit("import com.google.ar.sceneform.rendering.*");
|
|
1854
|
-
compiler.emit("import com.google.android.filament.utils.Float3");
|
|
1855
|
-
compiler.emit("");
|
|
1856
|
-
compiler.emit("object NodeFactory {");
|
|
1857
|
-
compiler.indentLevel++;
|
|
1858
|
-
compiler.emit("fun createDefaultNode(context: Context, callback: (Renderable) -> Unit) {");
|
|
1859
|
-
compiler.indentLevel++;
|
|
1860
|
-
if (composition.objects?.length) {
|
|
1861
|
-
const firstObj = composition.objects[0];
|
|
1862
|
-
const color = compiler.findObjProp(firstObj, "color");
|
|
1863
|
-
compiler.emit("MaterialFactory.makeOpaqueWithColor(");
|
|
1316
|
+
if (usedTraits.has("npu_realtime")) {
|
|
1317
|
+
compiler.emit("// MARK: Realtime Processing (npu_realtime)");
|
|
1318
|
+
compiler.emit("");
|
|
1319
|
+
compiler.emit("fun createImageAnalyzer(): ImageAnalysis.Analyzer {");
|
|
1864
1320
|
compiler.indentLevel++;
|
|
1865
|
-
compiler.emit("
|
|
1866
|
-
compiler.
|
|
1867
|
-
compiler.
|
|
1868
|
-
compiler.emit("
|
|
1321
|
+
compiler.emit("return ImageAnalysis.Analyzer { imageProxy ->");
|
|
1322
|
+
compiler.indentLevel++;
|
|
1323
|
+
compiler.emit("frameCounter++");
|
|
1324
|
+
compiler.emit("val now = System.currentTimeMillis()");
|
|
1325
|
+
compiler.emit("val intervalMs = 1000L / targetFPS");
|
|
1326
|
+
compiler.emit("if (now - lastProcessTimeMs < intervalMs) {");
|
|
1869
1327
|
compiler.indentLevel++;
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
compiler.
|
|
1328
|
+
compiler.emit("imageProxy.close()");
|
|
1329
|
+
compiler.emit("return@Analyzer");
|
|
1330
|
+
compiler.indentLevel--;
|
|
1331
|
+
compiler.emit("}");
|
|
1332
|
+
compiler.emit("lastProcessTimeMs = now");
|
|
1333
|
+
compiler.emit("_isProcessing.value = true");
|
|
1334
|
+
compiler.emit("");
|
|
1335
|
+
compiler.emit("@androidx.camera.core.ExperimentalGetImage");
|
|
1336
|
+
compiler.emit("val mediaImage = imageProxy.image");
|
|
1337
|
+
compiler.emit("if (mediaImage != null) {");
|
|
1873
1338
|
compiler.indentLevel++;
|
|
1874
|
-
compiler.emit(
|
|
1875
|
-
|
|
1339
|
+
compiler.emit(
|
|
1340
|
+
"val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)"
|
|
1341
|
+
);
|
|
1342
|
+
if (usedTraits.has("npu_classify")) {
|
|
1343
|
+
compiler.emit("classifyImage(image)");
|
|
1344
|
+
}
|
|
1345
|
+
if (usedTraits.has("npu_detect")) {
|
|
1346
|
+
compiler.emit("detectObjects(image)");
|
|
1347
|
+
}
|
|
1348
|
+
if (usedTraits.has("npu_segment")) {
|
|
1349
|
+
compiler.emit("segmentScene(image)");
|
|
1350
|
+
}
|
|
1876
1351
|
compiler.indentLevel--;
|
|
1877
1352
|
compiler.emit("}");
|
|
1353
|
+
compiler.emit("_isProcessing.value = false");
|
|
1354
|
+
compiler.emit("imageProxy.close()");
|
|
1878
1355
|
compiler.indentLevel--;
|
|
1879
1356
|
compiler.emit("}");
|
|
1880
|
-
|
|
1357
|
+
compiler.indentLevel--;
|
|
1358
|
+
compiler.emit("}");
|
|
1359
|
+
compiler.emit("");
|
|
1360
|
+
}
|
|
1361
|
+
if (usedTraits.has("npu_model_custom")) {
|
|
1362
|
+
compiler.emit("// MARK: Custom Model (npu_model_custom)");
|
|
1363
|
+
compiler.emit("");
|
|
1364
|
+
compiler.emit("private var customInterpreter: Interpreter? = null");
|
|
1365
|
+
compiler.emit("");
|
|
1366
|
+
compiler.emit("fun loadCustomModel(context: android.content.Context, assetPath: String) {");
|
|
1367
|
+
compiler.indentLevel++;
|
|
1368
|
+
compiler.emit("val localModel = LocalModel.Builder()");
|
|
1369
|
+
compiler.emit(" .setAssetFilePath(assetPath)");
|
|
1370
|
+
compiler.emit(" .build()");
|
|
1371
|
+
compiler.emit("");
|
|
1372
|
+
compiler.emit("// NNAPI delegate for hardware acceleration");
|
|
1373
|
+
compiler.emit("val nnApiDelegate = NnApiDelegate()");
|
|
1374
|
+
compiler.emit("val options = Interpreter.Options().addDelegate(nnApiDelegate)");
|
|
1375
|
+
compiler.emit("");
|
|
1376
|
+
compiler.emit("val modelFile = context.assets.open(assetPath)");
|
|
1377
|
+
compiler.emit("val buffer = modelFile.readBytes()");
|
|
1378
|
+
compiler.emit("val byteBuffer = java.nio.ByteBuffer.allocateDirect(buffer.size)");
|
|
1379
|
+
compiler.emit("byteBuffer.put(buffer)");
|
|
1380
|
+
compiler.emit("customInterpreter = Interpreter(byteBuffer, options)");
|
|
1381
|
+
compiler.emit('Log.d("HoloScript", "Custom model loaded with NNAPI: $assetPath")');
|
|
1382
|
+
compiler.indentLevel--;
|
|
1383
|
+
compiler.emit("}");
|
|
1384
|
+
compiler.emit("");
|
|
1385
|
+
}
|
|
1386
|
+
if (usedTraits.has("npu_label_overlay")) {
|
|
1387
|
+
compiler.emit("// MARK: Label Overlay (npu_label_overlay)");
|
|
1388
|
+
compiler.emit("");
|
|
1389
|
+
compiler.emit("fun createLabelOverlay(");
|
|
1390
|
+
compiler.emit(" detection: NPUDetection,");
|
|
1391
|
+
compiler.emit(" arFragment: com.google.ar.sceneform.ux.ArFragment,");
|
|
1392
|
+
compiler.emit(" anchorNode: com.google.ar.sceneform.AnchorNode");
|
|
1393
|
+
compiler.emit(") {");
|
|
1394
|
+
compiler.indentLevel++;
|
|
1395
|
+
compiler.emit("com.google.ar.sceneform.rendering.ViewRenderable.builder()");
|
|
1881
1396
|
compiler.emit(
|
|
1882
|
-
"
|
|
1397
|
+
" .setView(arFragment.requireContext(), android.widget.TextView(arFragment.requireContext()).apply {"
|
|
1883
1398
|
);
|
|
1884
|
-
compiler.
|
|
1399
|
+
compiler.indentLevel++;
|
|
1400
|
+
compiler.emit('text = "${detection.label} (${(detection.confidence * 100).toInt()}%)"');
|
|
1401
|
+
compiler.emit("setTextColor(android.graphics.Color.WHITE)");
|
|
1402
|
+
compiler.emit("setBackgroundColor(android.graphics.Color.argb(180, 0, 0, 0))");
|
|
1403
|
+
compiler.emit("setPadding(12, 6, 12, 6)");
|
|
1404
|
+
compiler.emit("textSize = 12f");
|
|
1405
|
+
compiler.indentLevel--;
|
|
1406
|
+
compiler.emit(" })");
|
|
1407
|
+
compiler.emit(" .build()");
|
|
1408
|
+
compiler.emit(" .thenAccept { renderable ->");
|
|
1409
|
+
compiler.indentLevel++;
|
|
1410
|
+
compiler.emit("val labelNode = com.google.ar.sceneform.Node()");
|
|
1411
|
+
compiler.emit("labelNode.setParent(anchorNode)");
|
|
1885
1412
|
compiler.emit(
|
|
1886
|
-
|
|
1413
|
+
`labelNode.localPosition = com.google.ar.sceneform.math.Vector3(0f, ${defaults.labelOffsetY}f, 0f)`
|
|
1887
1414
|
);
|
|
1415
|
+
compiler.emit("labelNode.renderable = renderable");
|
|
1416
|
+
compiler.emit('Log.d("HoloScript", "Label overlay: ${detection.label}")');
|
|
1417
|
+
compiler.indentLevel--;
|
|
1888
1418
|
compiler.emit(" }");
|
|
1889
|
-
compiler.
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
compiler.emit("}");
|
|
1893
|
-
compiler.emit("");
|
|
1894
|
-
for (const obj of composition.objects || []) {
|
|
1895
|
-
compileObjectFactory(compiler, obj);
|
|
1419
|
+
compiler.indentLevel--;
|
|
1420
|
+
compiler.emit("}");
|
|
1421
|
+
compiler.emit("");
|
|
1896
1422
|
}
|
|
1897
1423
|
compiler.indentLevel--;
|
|
1898
1424
|
compiler.emit("}");
|
|
1899
1425
|
return compiler.lines.join("\n");
|
|
1900
1426
|
}
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
const color = compiler.findObjProp(obj, "color");
|
|
1906
|
-
const meshType = compiler.findObjProp(obj, "mesh") || compiler.findObjProp(obj, "type") || "cube";
|
|
1907
|
-
compiler.emit("MaterialFactory.makeOpaqueWithColor(");
|
|
1908
|
-
compiler.indentLevel++;
|
|
1909
|
-
compiler.emit("context,");
|
|
1910
|
-
compiler.emit(`Color(${compiler.toAndroidColor(color)})`);
|
|
1911
|
-
compiler.indentLevel--;
|
|
1912
|
-
compiler.emit(").thenAccept { material ->");
|
|
1913
|
-
compiler.indentLevel++;
|
|
1914
|
-
const geometry = compiler.getSceneformGeometry(meshType);
|
|
1915
|
-
compiler.emit(`${geometry}.thenAccept { renderable ->`);
|
|
1916
|
-
compiler.indentLevel++;
|
|
1917
|
-
compiler.emit("renderable.material = material");
|
|
1918
|
-
compiler.emit("callback(renderable)");
|
|
1919
|
-
compiler.indentLevel--;
|
|
1920
|
-
compiler.emit("}");
|
|
1921
|
-
compiler.indentLevel--;
|
|
1922
|
-
compiler.emit("}");
|
|
1923
|
-
compiler.indentLevel--;
|
|
1924
|
-
compiler.emit("}");
|
|
1925
|
-
compiler.emit("");
|
|
1926
|
-
}
|
|
1927
|
-
function generateManifestFile(compiler, composition) {
|
|
1928
|
-
const pkg = compiler.options.packageName;
|
|
1929
|
-
const cls = compiler.options.className;
|
|
1930
|
-
const hasGeo = hasGeoTraits(composition);
|
|
1931
|
-
const hasGeospatialVPS = hasGeospatialVPSTraits(composition);
|
|
1932
|
-
const geoPermissions = hasGeo || hasGeospatialVPS ? `
|
|
1933
|
-
<!-- Geo-Anchor: Location permissions -->
|
|
1934
|
-
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
|
1935
|
-
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />` : "";
|
|
1936
|
-
const geospatialApiKeyMeta = hasGeospatialVPS ? `
|
|
1937
|
-
<!-- ARCore Geospatial API key (replace with your key from Google Cloud Console) -->
|
|
1938
|
-
<meta-data android:name="com.google.android.ar.API_KEY" android:value="\${GEOSPATIAL_API_KEY}" />` : "";
|
|
1939
|
-
return `<?xml version="1.0" encoding="utf-8"?>
|
|
1940
|
-
<!-- Auto-generated by HoloScript AndroidCompiler -->
|
|
1941
|
-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
1942
|
-
package="${pkg}">
|
|
1943
|
-
|
|
1944
|
-
<!-- AR Required -->
|
|
1945
|
-
<uses-permission android:name="android.permission.CAMERA" />
|
|
1946
|
-
<uses-feature android:name="android.hardware.camera.ar" android:required="true" />
|
|
1947
|
-
|
|
1948
|
-
<!-- ARCore Required -->
|
|
1949
|
-
<uses-feature android:glEsVersion="0x00030000" android:required="true" />${geoPermissions}
|
|
1950
|
-
|
|
1951
|
-
<application
|
|
1952
|
-
android:allowBackup="true"
|
|
1953
|
-
android:label="${compiler.escapeStringValue(composition.name, "XML")}"
|
|
1954
|
-
android:supportsRtl="true"
|
|
1955
|
-
android:theme="@style/Theme.AppCompat.NoActionBar">
|
|
1956
|
-
|
|
1957
|
-
<!-- ARCore metadata -->
|
|
1958
|
-
<meta-data android:name="com.google.ar.core" android:value="required" />${geospatialApiKeyMeta}
|
|
1959
|
-
|
|
1960
|
-
<activity
|
|
1961
|
-
android:name=".${cls}Activity"
|
|
1962
|
-
android:exported="true"
|
|
1963
|
-
android:configChanges="orientation|screenSize"
|
|
1964
|
-
android:screenOrientation="locked">
|
|
1965
|
-
<intent-filter>
|
|
1966
|
-
<action android:name="android.intent.action.MAIN" />
|
|
1967
|
-
<category android:name="android.intent.category.LAUNCHER" />
|
|
1968
|
-
</intent-filter>
|
|
1969
|
-
</activity>
|
|
1970
|
-
</application>
|
|
1971
|
-
</manifest>`;
|
|
1972
|
-
}
|
|
1973
|
-
function generateBuildGradle(compiler, composition) {
|
|
1974
|
-
const hasGeospatialVPS = hasGeospatialVPSTraits(composition);
|
|
1975
|
-
const hasDepthScan = hasDepthScanTraits(composition);
|
|
1976
|
-
const hasHandTracking = hasHandTrackingTraits(composition);
|
|
1977
|
-
const geospatialDeps = hasGeospatialVPS ? `
|
|
1978
|
-
// ARCore Geospatial API (included in com.google.ar:core >= 1.31.0)
|
|
1979
|
-
// Location services for VPS
|
|
1980
|
-
implementation 'com.google.android.gms:play-services-location:21.1.0'` : "";
|
|
1981
|
-
const depthScanDeps = hasDepthScan ? `
|
|
1982
|
-
// ARCore Depth API (M.010.02b)
|
|
1983
|
-
implementation 'com.google.ar:core:1.40.0'` : "";
|
|
1984
|
-
const handTrackingDeps = hasHandTracking ? `
|
|
1985
|
-
// MediaPipe Hands \u2014 camera-based hand tracking (M.010.04)
|
|
1986
|
-
implementation 'com.google.mediapipe:solution-hands:0.10.14'
|
|
1987
|
-
// CameraX for front camera feed
|
|
1988
|
-
implementation 'androidx.camera:camera-core:1.3.1'
|
|
1989
|
-
implementation 'androidx.camera:camera-camera2:1.3.1'
|
|
1990
|
-
implementation 'androidx.camera:camera-lifecycle:1.3.1'` : "";
|
|
1991
|
-
const hasAuthoring = hasAuthoringTraits(composition);
|
|
1992
|
-
const authoringDeps = hasAuthoring ? `
|
|
1993
|
-
// Spatial Authoring \u2014 speech recognition (M.010.08)
|
|
1994
|
-
implementation 'androidx.recyclerview:recyclerview:1.3.2'` : "";
|
|
1995
|
-
return `// Auto-generated by HoloScript AndroidCompiler
|
|
1996
|
-
// Source: ${compiler.escapeStringValue(composition.name, "Kotlin")}
|
|
1997
|
-
|
|
1998
|
-
plugins {
|
|
1999
|
-
id 'com.android.application'
|
|
2000
|
-
id 'org.jetbrains.kotlin.android'
|
|
2001
|
-
}
|
|
2002
|
-
|
|
2003
|
-
android {
|
|
2004
|
-
namespace '${compiler.options.packageName}'
|
|
2005
|
-
compileSdk ${compiler.options.targetSdk}
|
|
2006
|
-
|
|
2007
|
-
defaultConfig {
|
|
2008
|
-
applicationId "${compiler.options.packageName}"
|
|
2009
|
-
minSdk ${compiler.options.minSdk}
|
|
2010
|
-
targetSdk ${compiler.options.targetSdk}
|
|
2011
|
-
versionCode 1
|
|
2012
|
-
versionName "1.0"
|
|
2013
|
-
}
|
|
2014
|
-
|
|
2015
|
-
buildTypes {
|
|
2016
|
-
release {
|
|
2017
|
-
minifyEnabled false
|
|
2018
|
-
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
|
2019
|
-
}
|
|
2020
|
-
}
|
|
2021
|
-
|
|
2022
|
-
compileOptions {
|
|
2023
|
-
sourceCompatibility JavaVersion.VERSION_17
|
|
2024
|
-
targetCompatibility JavaVersion.VERSION_17
|
|
2025
|
-
}
|
|
2026
|
-
|
|
2027
|
-
kotlinOptions {
|
|
2028
|
-
jvmTarget = '17'
|
|
2029
|
-
}
|
|
2030
|
-
|
|
2031
|
-
buildFeatures {
|
|
2032
|
-
viewBinding true
|
|
2033
|
-
compose ${compiler.options.useJetpackCompose}
|
|
2034
|
-
}
|
|
2035
|
-
}
|
|
2036
|
-
|
|
2037
|
-
dependencies {
|
|
2038
|
-
implementation 'androidx.core:core-ktx:1.12.0'
|
|
2039
|
-
implementation 'androidx.appcompat:appcompat:1.6.1'
|
|
2040
|
-
implementation 'com.google.android.material:material:1.11.0'
|
|
2041
|
-
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0'
|
|
2042
|
-
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.7.0'
|
|
2043
|
-
|
|
2044
|
-
// ARCore (>= 1.31.0 includes Geospatial API)
|
|
2045
|
-
implementation 'com.google.ar:core:1.41.0'
|
|
2046
|
-
|
|
2047
|
-
// Sceneform (maintained fork)
|
|
2048
|
-
implementation 'com.gorisse.thomas:sceneform:1.22.0'${geospatialDeps}${depthScanDeps}${handTrackingDeps}${authoringDeps}
|
|
2049
|
-
|
|
2050
|
-
// Optional: Jetpack Compose
|
|
2051
|
-
${compiler.options.useJetpackCompose ? `implementation platform('androidx.compose:compose-bom:2024.01.00')
|
|
2052
|
-
implementation 'androidx.compose.ui:ui'
|
|
2053
|
-
implementation 'androidx.compose.material3:material3'
|
|
2054
|
-
implementation 'androidx.activity:activity-compose:1.8.2'` : "// Compose disabled"}
|
|
2055
|
-
}`;
|
|
2056
|
-
}
|
|
2057
|
-
function compileAction(compiler, action) {
|
|
2058
|
-
const rawName = compiler.sanitizeName(action.name);
|
|
2059
|
-
const name = rawName.charAt(0).toLowerCase() + rawName.slice(1);
|
|
2060
|
-
compiler.emit(`fun ${name}() {`);
|
|
2061
|
-
compiler.indentLevel++;
|
|
2062
|
-
compiler.emit(
|
|
2063
|
-
`android.util.Log.d("HoloScript", "Action: ${compiler.escapeStringValue(action.name, "Kotlin")}")`
|
|
2064
|
-
);
|
|
2065
|
-
compiler.emit("// Action implementation");
|
|
2066
|
-
compiler.indentLevel--;
|
|
2067
|
-
compiler.emit("}");
|
|
2068
|
-
compiler.emit("");
|
|
2069
|
-
}
|
|
2070
|
-
var init_AndroidARGenerators = chunkHCCQLAA4_cjs.__esm({
|
|
2071
|
-
"src/compiler/AndroidARGenerators.ts"() {
|
|
2072
|
-
init_AndroidFeatureGenerators();
|
|
1427
|
+
var init_AndroidFeatureGenerators = chunkZHPMP447_cjs.__esm({
|
|
1428
|
+
"src/compiler/AndroidFeatureGenerators.ts"() {
|
|
1429
|
+
chunkN74QRJGP_cjs.init_npu_scene();
|
|
1430
|
+
chunkAWXFEAQL_cjs.init_spatial_authoring();
|
|
2073
1431
|
}
|
|
2074
1432
|
});
|
|
2075
1433
|
|
|
2076
1434
|
// src/compiler/AndroidPeripheralGenerators.ts
|
|
2077
1435
|
function hasHapticTraits(composition) {
|
|
2078
|
-
const names =
|
|
1436
|
+
const names = chunkAWXFEAQL_cjs.HAPTIC_FEEDBACK_TRAITS;
|
|
2079
1437
|
for (const obj of composition.objects || []) {
|
|
2080
1438
|
for (const trait of obj.traits || []) {
|
|
2081
1439
|
const name = typeof trait === "string" ? trait : trait.name;
|
|
@@ -2174,7 +1532,7 @@ function emitHapticSetup(compiler, composition) {
|
|
|
2174
1532
|
return compiler.lines.join("\n");
|
|
2175
1533
|
}
|
|
2176
1534
|
function hasNearbyTraits(composition) {
|
|
2177
|
-
const names =
|
|
1535
|
+
const names = chunkAWXFEAQL_cjs.NEARBY_CONNECTIONS_TRAITS;
|
|
2178
1536
|
for (const obj of composition.objects || []) {
|
|
2179
1537
|
for (const trait of obj.traits || []) {
|
|
2180
1538
|
const name = typeof trait === "string" ? trait : trait.name;
|
|
@@ -2306,7 +1664,7 @@ function emitNearbySetup(compiler, composition) {
|
|
|
2306
1664
|
return compiler.lines.join("\n");
|
|
2307
1665
|
}
|
|
2308
1666
|
function hasFoldableTraits(composition) {
|
|
2309
|
-
const names =
|
|
1667
|
+
const names = chunkAWXFEAQL_cjs.FOLDABLE_DISPLAY_TRAITS;
|
|
2310
1668
|
for (const obj of composition.objects || []) {
|
|
2311
1669
|
for (const trait of obj.traits || []) {
|
|
2312
1670
|
const name = typeof trait === "string" ? trait : trait.name;
|
|
@@ -2399,7 +1757,7 @@ function emitFoldableSetup(compiler, composition) {
|
|
|
2399
1757
|
return compiler.lines.join("\n");
|
|
2400
1758
|
}
|
|
2401
1759
|
function hasDexTraits(composition) {
|
|
2402
|
-
const names =
|
|
1760
|
+
const names = chunkAWXFEAQL_cjs.SAMSUNG_DEX_TRAITS;
|
|
2403
1761
|
for (const obj of composition.objects || []) {
|
|
2404
1762
|
for (const trait of obj.traits || []) {
|
|
2405
1763
|
const name = typeof trait === "string" ? trait : trait.name;
|
|
@@ -2494,7 +1852,7 @@ function emitDexSetup(compiler, composition) {
|
|
|
2494
1852
|
return compiler.lines.join("\n");
|
|
2495
1853
|
}
|
|
2496
1854
|
function hasLensTraits(composition) {
|
|
2497
|
-
const names =
|
|
1855
|
+
const names = chunkAWXFEAQL_cjs.GOOGLE_LENS_TRAITS;
|
|
2498
1856
|
for (const obj of composition.objects || []) {
|
|
2499
1857
|
for (const trait of obj.traits || []) {
|
|
2500
1858
|
const name = typeof trait === "string" ? trait : trait.name;
|
|
@@ -2512,7 +1870,7 @@ function emitLensSetup(compiler, composition) {
|
|
|
2512
1870
|
for (const obj of composition.objects || []) {
|
|
2513
1871
|
for (const trait of obj.traits || []) {
|
|
2514
1872
|
const name = typeof trait === "string" ? trait : trait.name;
|
|
2515
|
-
if (
|
|
1873
|
+
if (chunkAWXFEAQL_cjs.GOOGLE_LENS_TRAITS.includes(name)) {
|
|
2516
1874
|
usedTraits.add(name);
|
|
2517
1875
|
}
|
|
2518
1876
|
}
|
|
@@ -2621,7 +1979,7 @@ function emitLensSetup(compiler, composition) {
|
|
|
2621
1979
|
return compiler.lines.join("\n");
|
|
2622
1980
|
}
|
|
2623
1981
|
function hasWebXRTraits(composition) {
|
|
2624
|
-
const names =
|
|
1982
|
+
const names = chunkAWXFEAQL_cjs.WEBXR_TRAITS;
|
|
2625
1983
|
for (const obj of composition.objects || []) {
|
|
2626
1984
|
for (const trait of obj.traits || []) {
|
|
2627
1985
|
const name = typeof trait === "string" ? trait : trait.name;
|
|
@@ -2635,7 +1993,7 @@ function collectWebXRTraits(composition) {
|
|
|
2635
1993
|
for (const obj of composition.objects || []) {
|
|
2636
1994
|
for (const trait of obj.traits || []) {
|
|
2637
1995
|
const name = typeof trait === "string" ? trait : trait.name;
|
|
2638
|
-
if (
|
|
1996
|
+
if (chunkAWXFEAQL_cjs.WEBXR_TRAITS.includes(name)) {
|
|
2639
1997
|
usedTraits.add(name);
|
|
2640
1998
|
}
|
|
2641
1999
|
}
|
|
@@ -2923,20 +2281,20 @@ function emitWebXRSetup(compiler, composition) {
|
|
|
2923
2281
|
compiler.emit("</html>");
|
|
2924
2282
|
return compiler.lines.join("\n");
|
|
2925
2283
|
}
|
|
2926
|
-
var init_AndroidPeripheralGenerators =
|
|
2284
|
+
var init_AndroidPeripheralGenerators = chunkZHPMP447_cjs.__esm({
|
|
2927
2285
|
"src/compiler/AndroidPeripheralGenerators.ts"() {
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2286
|
+
chunkAWXFEAQL_cjs.init_haptic_feedback();
|
|
2287
|
+
chunkAWXFEAQL_cjs.init_nearby_connections();
|
|
2288
|
+
chunkAWXFEAQL_cjs.init_foldable_display();
|
|
2289
|
+
chunkAWXFEAQL_cjs.init_samsung_dex();
|
|
2290
|
+
chunkAWXFEAQL_cjs.init_google_lens();
|
|
2291
|
+
chunkAWXFEAQL_cjs.init_webxr();
|
|
2934
2292
|
}
|
|
2935
2293
|
});
|
|
2936
2294
|
|
|
2937
2295
|
// src/compiler/AndroidCompiler.ts
|
|
2938
2296
|
var AndroidCompiler_exports = {};
|
|
2939
|
-
|
|
2297
|
+
chunkZHPMP447_cjs.__export(AndroidCompiler_exports, {
|
|
2940
2298
|
AndroidCompiler: () => exports.AndroidCompiler,
|
|
2941
2299
|
compileToAndroid: () => compileToAndroid
|
|
2942
2300
|
});
|
|
@@ -2945,14 +2303,15 @@ function compileToAndroid(composition, options) {
|
|
|
2945
2303
|
return Promise.resolve(compiler.compile(composition, "test-token", void 0));
|
|
2946
2304
|
}
|
|
2947
2305
|
exports.AndroidCompiler = void 0;
|
|
2948
|
-
var init_AndroidCompiler =
|
|
2306
|
+
var init_AndroidCompiler = chunkZHPMP447_cjs.__esm({
|
|
2949
2307
|
"src/compiler/AndroidCompiler.ts"() {
|
|
2950
|
-
|
|
2308
|
+
chunkZK7KX5CD_cjs.init_CompilerBase();
|
|
2951
2309
|
init_AndroidARGenerators();
|
|
2952
2310
|
init_AndroidFeatureGenerators();
|
|
2311
|
+
init_AndroidSceneViewFeatureGenerators();
|
|
2953
2312
|
init_AndroidPeripheralGenerators();
|
|
2954
|
-
|
|
2955
|
-
exports.AndroidCompiler = class extends
|
|
2313
|
+
chunkCFVK26P4_cjs.init_AndroidKotlinHelpers();
|
|
2314
|
+
exports.AndroidCompiler = class extends chunkZK7KX5CD_cjs.CompilerBase {
|
|
2956
2315
|
constructor(options = {}) {
|
|
2957
2316
|
super();
|
|
2958
2317
|
this.compilerName = "AndroidCompiler";
|
|
@@ -2976,11 +2335,26 @@ var init_AndroidCompiler = chunkHCCQLAA4_cjs.__esm({
|
|
|
2976
2335
|
this.validateCompilerAccess(agentToken, outputPath);
|
|
2977
2336
|
const result = {
|
|
2978
2337
|
activityFile: generateActivityFile(this, composition),
|
|
2979
|
-
stateFile: generateStateFile(
|
|
2980
|
-
nodeFactoryFile: generateNodeFactoryFile(
|
|
2338
|
+
stateFile: generateStateFile(),
|
|
2339
|
+
nodeFactoryFile: generateNodeFactoryFile(),
|
|
2981
2340
|
manifestFile: generateManifestFile(this, composition),
|
|
2982
2341
|
buildGradle: generateBuildGradle(this, composition)
|
|
2983
2342
|
};
|
|
2343
|
+
if (hasGeoAnchorTraits(composition)) {
|
|
2344
|
+
result.geoAnchorSetup = emitGeoAnchorSetup(this, composition);
|
|
2345
|
+
}
|
|
2346
|
+
if (hasGeospatialVPSTraits(composition)) {
|
|
2347
|
+
result.geospatialVPSSetup = emitGeospatialVPSSetup(this, composition);
|
|
2348
|
+
}
|
|
2349
|
+
if (hasDepthScanTraits(composition)) {
|
|
2350
|
+
result.depthScanSetup = emitDepthScanSetup(this, composition);
|
|
2351
|
+
}
|
|
2352
|
+
if (hasPortalARTraits(composition)) {
|
|
2353
|
+
result.portalARSetup = emitPortalARSetup(this, composition);
|
|
2354
|
+
}
|
|
2355
|
+
if (hasHandTrackingTraits(composition)) {
|
|
2356
|
+
result.handTrackingSetup = emitHandTrackingSetup(this, composition);
|
|
2357
|
+
}
|
|
2984
2358
|
if (hasNPUSceneTraits(composition)) {
|
|
2985
2359
|
result.npuSceneSetup = emitNPUSceneSetup(this, composition);
|
|
2986
2360
|
}
|
|
@@ -3007,37 +2381,82 @@ var init_AndroidCompiler = chunkHCCQLAA4_cjs.__esm({
|
|
|
3007
2381
|
}
|
|
3008
2382
|
return result;
|
|
3009
2383
|
}
|
|
2384
|
+
/**
|
|
2385
|
+
* Compile to a path-keyed map of reference-relative files (Android project layout).
|
|
2386
|
+
*
|
|
2387
|
+
* Mirrors AndroidXRCompiler.compileToFiles(): the native return is named fields
|
|
2388
|
+
* (AndroidCompileResult), so this adapter maps those fields onto the on-disk Android
|
|
2389
|
+
* project layout, letting the SAME byte-diff golden gate + committed-reference-app pattern
|
|
2390
|
+
* (QuestCompiler / AndroidXRCompiler) apply to the legacy plain-Android (ARCore) target.
|
|
2391
|
+
* Keys are POSIX-relative to the app project root (the dir holding settings.gradle.kts).
|
|
2392
|
+
*
|
|
2393
|
+
* Optional feature-setup fields (npuSceneSetup, hapticSetup, …) are emitted as extra
|
|
2394
|
+
* Kotlin files under the same package dir, keyed off the field name, so the gate covers
|
|
2395
|
+
* them when a trait pulls them in. The field→filename map is fixed so output is stable.
|
|
2396
|
+
*/
|
|
2397
|
+
compileToFiles(composition, agentToken = "") {
|
|
2398
|
+
const r = this.compile(composition, agentToken);
|
|
2399
|
+
const pkgPath = this.options.packageName.replace(/\./g, "/");
|
|
2400
|
+
const javaRel = `app/src/main/java/${pkgPath}`;
|
|
2401
|
+
const files = {
|
|
2402
|
+
[`${javaRel}/${this.options.className}Activity.kt`]: r.activityFile,
|
|
2403
|
+
"app/src/main/AndroidManifest.xml": r.manifestFile,
|
|
2404
|
+
"app/build.gradle.kts": r.buildGradle
|
|
2405
|
+
};
|
|
2406
|
+
const featureFiles = {
|
|
2407
|
+
geoAnchorSetup: "GeoAnchorSetup.kt",
|
|
2408
|
+
geospatialVPSSetup: "GeospatialVPSSetup.kt",
|
|
2409
|
+
depthScanSetup: "DepthScanSetup.kt",
|
|
2410
|
+
portalARSetup: "PortalARSetup.kt",
|
|
2411
|
+
handTrackingSetup: "HandTrackingSetup.kt",
|
|
2412
|
+
npuSceneSetup: "NPUSceneSetup.kt",
|
|
2413
|
+
authoringSetup: "AuthoringSetup.kt",
|
|
2414
|
+
hapticSetup: "HapticSetup.kt",
|
|
2415
|
+
nearbySetup: "NearbySetup.kt",
|
|
2416
|
+
foldableSetup: "FoldableSetup.kt",
|
|
2417
|
+
dexSetup: "DexSetup.kt",
|
|
2418
|
+
lensSetup: "LensSetup.kt",
|
|
2419
|
+
webxrSetup: "WebXRSetup.kt"
|
|
2420
|
+
};
|
|
2421
|
+
for (const [field, fileName] of Object.entries(featureFiles)) {
|
|
2422
|
+
const content = r[field];
|
|
2423
|
+
if (typeof content === "string" && content.length > 0) {
|
|
2424
|
+
files[`${javaRel}/${fileName}`] = content;
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
return files;
|
|
2428
|
+
}
|
|
3010
2429
|
emit(line) {
|
|
3011
2430
|
const indent = this.options.indent.repeat(this.indentLevel);
|
|
3012
2431
|
this.lines.push(indent + line);
|
|
3013
2432
|
}
|
|
3014
2433
|
/** @deprecated Use sanitizeNameCapitalized from AndroidKotlinHelpers */
|
|
3015
2434
|
sanitizeName(name) {
|
|
3016
|
-
return
|
|
2435
|
+
return chunkCFVK26P4_cjs.sanitizeNameCapitalized(name);
|
|
3017
2436
|
}
|
|
3018
2437
|
/** @deprecated Use getSceneformGeometry from AndroidKotlinHelpers */
|
|
3019
2438
|
getSceneformGeometry(meshType) {
|
|
3020
|
-
return
|
|
2439
|
+
return chunkCFVK26P4_cjs.getSceneformGeometry(meshType);
|
|
3021
2440
|
}
|
|
3022
2441
|
/** @deprecated Use findObjProp from AndroidKotlinHelpers */
|
|
3023
2442
|
findObjProp(obj, key) {
|
|
3024
|
-
return
|
|
2443
|
+
return chunkCFVK26P4_cjs.findObjProp(obj, key);
|
|
3025
2444
|
}
|
|
3026
2445
|
/** @deprecated Use toKotlinType from AndroidKotlinHelpers */
|
|
3027
2446
|
toKotlinType(value) {
|
|
3028
|
-
return
|
|
2447
|
+
return chunkCFVK26P4_cjs.toKotlinType(value);
|
|
3029
2448
|
}
|
|
3030
2449
|
/** @deprecated Use toKotlinValue from AndroidKotlinHelpers */
|
|
3031
2450
|
toKotlinValue(value) {
|
|
3032
|
-
return
|
|
2451
|
+
return chunkCFVK26P4_cjs.toKotlinValue(value, (s, t) => this.escapeStringValue(s, t));
|
|
3033
2452
|
}
|
|
3034
2453
|
/** @deprecated Use toAndroidColor from AndroidKotlinHelpers */
|
|
3035
2454
|
toAndroidColor(value) {
|
|
3036
|
-
return
|
|
2455
|
+
return chunkCFVK26P4_cjs.toAndroidColor(value);
|
|
3037
2456
|
}
|
|
3038
2457
|
/** @deprecated Use compositionHasTrait from AndroidKotlinHelpers */
|
|
3039
|
-
compositionHasTrait(composition,
|
|
3040
|
-
return
|
|
2458
|
+
compositionHasTrait(composition, traitName2) {
|
|
2459
|
+
return chunkCFVK26P4_cjs.compositionHasTrait(composition, traitName2);
|
|
3041
2460
|
}
|
|
3042
2461
|
};
|
|
3043
2462
|
}
|
|
@@ -3046,5 +2465,5 @@ var init_AndroidCompiler = chunkHCCQLAA4_cjs.__esm({
|
|
|
3046
2465
|
exports.AndroidCompiler_exports = AndroidCompiler_exports;
|
|
3047
2466
|
exports.compileToAndroid = compileToAndroid;
|
|
3048
2467
|
exports.init_AndroidCompiler = init_AndroidCompiler;
|
|
3049
|
-
//# sourceMappingURL=chunk-
|
|
3050
|
-
//# sourceMappingURL=chunk-
|
|
2468
|
+
//# sourceMappingURL=chunk-2KKOYZYI.cjs.map
|
|
2469
|
+
//# sourceMappingURL=chunk-2KKOYZYI.cjs.map
|