From 0443bdb019ecba7ec2c0127084c275f3fee95cba Mon Sep 17 00:00:00 2001 From: Blair MacIntyre Date: Fri, 27 Dec 2019 16:40:15 -0500 Subject: [PATCH 1/7] small fix to XRSession.end() typo: this.immersive should be this[PRIVATE].immersive --- build/webxr-polyfill.js | 13 +++++++++---- build/webxr-polyfill.min.js | 2 +- build/webxr-polyfill.module.js | 13 +++++++++---- src/api/XRSession.js | 2 +- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/build/webxr-polyfill.js b/build/webxr-polyfill.js index af60dbb..3fd4b81 100644 --- a/build/webxr-polyfill.js +++ b/build/webxr-polyfill.js @@ -1646,7 +1646,7 @@ class XRSession$1 extends EventTarget { if (this[PRIVATE$15].ended) { return; } - if (this.immersive) { + if (this[PRIVATE$15].immersive) { this[PRIVATE$15].ended = true; this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/vr-present-start', this[PRIVATE$15].onPresentationStart); @@ -3495,8 +3495,8 @@ function CardboardViewer(params) { } DeviceInfo.Viewers = Viewers; var format = 1; -var last_updated = "2018-12-10T17:01:42Z"; -var devices = [{"type":"android","rules":[{"mdmh":"asus/*/Nexus 7/*"},{"ua":"Nexus 7"}],"dpi":[320.8,323],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_Z00AD/*"},{"ua":"ASUS_Z00AD"}],"dpi":[403,404.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2 XL/*"},{"ua":"Pixel 2 XL"}],"dpi":537.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3 XL/*"},{"ua":"Pixel 3 XL"}],"dpi":[558.5,553.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel XL/*"},{"ua":"Pixel XL"}],"dpi":[537.9,533],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3/*"},{"ua":"Pixel 3"}],"dpi":442.4,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2/*"},{"ua":"Pixel 2"}],"dpi":441,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Google/*/Pixel/*"},{"ua":"Pixel"}],"dpi":[432.6,436.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC6435LVW/*"},{"ua":"HTC6435LVW"}],"dpi":[449.7,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One XL/*"},{"ua":"HTC One XL"}],"dpi":[315.3,314.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"htc/*/Nexus 9/*"},{"ua":"Nexus 9"}],"dpi":289,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One M9/*"},{"ua":"HTC One M9"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One_M8/*"},{"ua":"HTC One_M8"}],"dpi":[449.7,447.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One/*"},{"ua":"HTC One"}],"dpi":472.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/Nexus 6P/*"},{"ua":"Nexus 6P"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/BLN-L24/*"},{"ua":"HONORBLN-L24"}],"dpi":480,"bw":4,"ac":500},{"type":"android","rules":[{"mdmh":"Huawei/*/BKL-L09/*"},{"ua":"BKL-L09"}],"dpi":403,"bw":3.47,"ac":500},{"type":"android","rules":[{"mdmh":"LENOVO/*/Lenovo PB2-690Y/*"},{"ua":"Lenovo PB2-690Y"}],"dpi":[457.2,454.713],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5X/*"},{"ua":"Nexus 5X"}],"dpi":[422,419.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS345/*"},{"ua":"LGMS345"}],"dpi":[221.7,219.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D800/*"},{"ua":"LG-D800"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D850/*"},{"ua":"LG-D850"}],"dpi":[537.9,541.9],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/VS985 4G/*"},{"ua":"VS985 4G"}],"dpi":[537.9,535.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5/*"},{"ua":"Nexus 5 B"}],"dpi":[442.4,444.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 4/*"},{"ua":"Nexus 4"}],"dpi":[319.8,318.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LG-P769/*"},{"ua":"LG-P769"}],"dpi":[240.6,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS323/*"},{"ua":"LGMS323"}],"dpi":[206.6,204.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGLS996/*"},{"ua":"LGLS996"}],"dpi":[403.4,401.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/4560MMX/*"},{"ua":"4560MMX"}],"dpi":[240,219.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/A250/*"},{"ua":"Micromax A250"}],"dpi":[480,446.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/Micromax AQ4501/*"},{"ua":"Micromax AQ4501"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/G5/*"},{"ua":"Moto G (5) Plus"}],"dpi":[403.4,403],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/DROID RAZR/*"},{"ua":"DROID RAZR"}],"dpi":[368.1,256.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT830C/*"},{"ua":"XT830C"}],"dpi":[254,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1021/*"},{"ua":"XT1021"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1023/*"},{"ua":"XT1023"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1028/*"},{"ua":"XT1028"}],"dpi":[326.6,327.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1034/*"},{"ua":"XT1034"}],"dpi":[326.6,328.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1053/*"},{"ua":"XT1053"}],"dpi":[315.3,316.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1562/*"},{"ua":"XT1562"}],"dpi":[403.4,402.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/Nexus 6/*"},{"ua":"Nexus 6 B"}],"dpi":[494.3,489.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1063/*"},{"ua":"XT1063"}],"dpi":[295,296.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1064/*"},{"ua":"XT1064"}],"dpi":[295,295.6],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1092/*"},{"ua":"XT1092"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1095/*"},{"ua":"XT1095"}],"dpi":[422,423.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/G4/*"},{"ua":"Moto G (4)"}],"dpi":401,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/A0001/*"},{"ua":"A0001"}],"dpi":[403.4,401],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1005/*"},{"ua":"ONE E1005"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2005/*"},{"ua":"ONE A2005"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A5000/*"},{"ua":"ONEPLUS A5000 "}],"dpi":[403.411,399.737],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A5010/*"},{"ua":"ONEPLUS A5010"}],"dpi":[403,400],"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"OPPO/*/X909/*"},{"ua":"X909"}],"dpi":[442.4,444.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9082/*"},{"ua":"GT-I9082"}],"dpi":[184.7,185.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G360P/*"},{"ua":"SM-G360P"}],"dpi":[196.7,205.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Nexus S/*"},{"ua":"Nexus S"}],"dpi":[234.5,229.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[304.8,303.9],"bw":5,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T230NU/*"},{"ua":"SM-T230NU"}],"dpi":216,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-T399/*"},{"ua":"SGH-T399"}],"dpi":[217.7,231.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-M919/*"},{"ua":"SGH-M919"}],"dpi":[440.8,437.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N9005/*"},{"ua":"SM-N9005"}],"dpi":[386.4,387],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SM-N900A/*"},{"ua":"SAMSUNG-SM-N900A"}],"dpi":[386.4,387.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9500/*"},{"ua":"GT-I9500"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9505/*"},{"ua":"GT-I9505"}],"dpi":439.4,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900F/*"},{"ua":"SM-G900F"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900M/*"},{"ua":"SM-G900M"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G800F/*"},{"ua":"SM-G800F"}],"dpi":326.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G906S/*"},{"ua":"SM-G906S"}],"dpi":[562.7,572.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[306.7,304.8],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T535/*"},{"ua":"SM-T535"}],"dpi":[142.6,136.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920C/*"},{"ua":"SM-N920C"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920P/*"},{"ua":"SM-N920P"}],"dpi":[386.3655,390.144],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920W8/*"},{"ua":"SM-N920W8"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300I/*"},{"ua":"GT-I9300I"}],"dpi":[304.8,305.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9195/*"},{"ua":"GT-I9195"}],"dpi":[249.4,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-L520/*"},{"ua":"SPH-L520"}],"dpi":[249.4,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SGH-I717/*"},{"ua":"SAMSUNG-SGH-I717"}],"dpi":285.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-D710/*"},{"ua":"SPH-D710"}],"dpi":[217.7,204.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-N7100/*"},{"ua":"GT-N7100"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SCH-I605/*"},{"ua":"SCH-I605"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Galaxy Nexus/*"},{"ua":"Galaxy Nexus"}],"dpi":[315.3,314.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910H/*"},{"ua":"SM-N910H"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910C/*"},{"ua":"SM-N910C"}],"dpi":[515.2,520.2],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G130M/*"},{"ua":"SM-G130M"}],"dpi":[165.9,164.8],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G928I/*"},{"ua":"SM-G928I"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920F/*"},{"ua":"SM-G920F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920P/*"},{"ua":"SM-G920P"}],"dpi":[522.5,577],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925F/*"},{"ua":"SM-G925F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925V/*"},{"ua":"SM-G925V"}],"dpi":[522.5,576.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G930F/*"},{"ua":"SM-G930F"}],"dpi":576.6,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G935F/*"},{"ua":"SM-G935F"}],"dpi":533,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G950F/*"},{"ua":"SM-G950F"}],"dpi":[562.707,565.293],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955U/*"},{"ua":"SM-G955U"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955F/*"},{"ua":"SM-G955F"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/C6903/*"},{"ua":"C6903"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/D6653/*"},{"ua":"D6653"}],"dpi":[428.6,427.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6653/*"},{"ua":"E6653"}],"dpi":[428.6,425.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6853/*"},{"ua":"E6853"}],"dpi":[403.4,401.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/SGP321/*"},{"ua":"SGP321"}],"dpi":[224.7,224.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{"ua":"ALCATEL ONE TOUCH Fierce"}],"dpi":[240,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"THL/*/thl 5000/*"},{"ua":"thl 5000"}],"dpi":[480,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Fly/*/IQ4412/*"},{"ua":"IQ4412"}],"dpi":307.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"ZTE/*/ZTE Blade L2/*"},{"ua":"ZTE Blade L2"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"BENEVE/*/VR518/*"},{"ua":"VR518"}],"dpi":480,"bw":3,"ac":500},{"type":"ios","rules":[{"res":[640,960]}],"dpi":[325.1,328.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[640,1136]}],"dpi":[317.1,320.2],"bw":3,"ac":1000},{"type":"ios","rules":[{"res":[750,1334]}],"dpi":326.4,"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1242,2208]}],"dpi":[453.6,458.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2001]}],"dpi":[410.9,415.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2436]}],"dpi":458,"bw":4,"ac":1000}]; +var last_updated = "2019-11-09T17:36:14Z"; +var devices = [{"type":"android","rules":[{"mdmh":"asus/*/Nexus 7/*"},{"ua":"Nexus 7"}],"dpi":[320.8,323],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_X00PD/*"},{"ua":"ASUS_X00PD"}],"dpi":245,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_X008D/*"},{"ua":"ASUS_X008D"}],"dpi":282,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_Z00AD/*"},{"ua":"ASUS_Z00AD"}],"dpi":[403,404.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2 XL/*"},{"ua":"Pixel 2 XL"}],"dpi":537.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3 XL/*"},{"ua":"Pixel 3 XL"}],"dpi":[558.5,553.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel XL/*"},{"ua":"Pixel XL"}],"dpi":[537.9,533],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3/*"},{"ua":"Pixel 3"}],"dpi":442.4,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2/*"},{"ua":"Pixel 2"}],"dpi":441,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Google/*/Pixel/*"},{"ua":"Pixel"}],"dpi":[432.6,436.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC6435LVW/*"},{"ua":"HTC6435LVW"}],"dpi":[449.7,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One XL/*"},{"ua":"HTC One XL"}],"dpi":[315.3,314.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"htc/*/Nexus 9/*"},{"ua":"Nexus 9"}],"dpi":289,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One M9/*"},{"ua":"HTC One M9"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One_M8/*"},{"ua":"HTC One_M8"}],"dpi":[449.7,447.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One/*"},{"ua":"HTC One"}],"dpi":472.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/Nexus 6P/*"},{"ua":"Nexus 6P"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/BLN-L24/*"},{"ua":"HONORBLN-L24"}],"dpi":480,"bw":4,"ac":500},{"type":"android","rules":[{"mdmh":"Huawei/*/BKL-L09/*"},{"ua":"BKL-L09"}],"dpi":403,"bw":3.47,"ac":500},{"type":"android","rules":[{"mdmh":"LENOVO/*/Lenovo PB2-690Y/*"},{"ua":"Lenovo PB2-690Y"}],"dpi":[457.2,454.713],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5X/*"},{"ua":"Nexus 5X"}],"dpi":[422,419.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS345/*"},{"ua":"LGMS345"}],"dpi":[221.7,219.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D800/*"},{"ua":"LG-D800"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D850/*"},{"ua":"LG-D850"}],"dpi":[537.9,541.9],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/VS985 4G/*"},{"ua":"VS985 4G"}],"dpi":[537.9,535.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5/*"},{"ua":"Nexus 5 B"}],"dpi":[442.4,444.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 4/*"},{"ua":"Nexus 4"}],"dpi":[319.8,318.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LG-P769/*"},{"ua":"LG-P769"}],"dpi":[240.6,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS323/*"},{"ua":"LGMS323"}],"dpi":[206.6,204.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGLS996/*"},{"ua":"LGLS996"}],"dpi":[403.4,401.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/4560MMX/*"},{"ua":"4560MMX"}],"dpi":[240,219.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/A250/*"},{"ua":"Micromax A250"}],"dpi":[480,446.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/Micromax AQ4501/*"},{"ua":"Micromax AQ4501"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/G5/*"},{"ua":"Moto G (5) Plus"}],"dpi":[403.4,403],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/DROID RAZR/*"},{"ua":"DROID RAZR"}],"dpi":[368.1,256.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT830C/*"},{"ua":"XT830C"}],"dpi":[254,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1021/*"},{"ua":"XT1021"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1023/*"},{"ua":"XT1023"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1028/*"},{"ua":"XT1028"}],"dpi":[326.6,327.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1034/*"},{"ua":"XT1034"}],"dpi":[326.6,328.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1053/*"},{"ua":"XT1053"}],"dpi":[315.3,316.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1562/*"},{"ua":"XT1562"}],"dpi":[403.4,402.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/Nexus 6/*"},{"ua":"Nexus 6 B"}],"dpi":[494.3,489.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1063/*"},{"ua":"XT1063"}],"dpi":[295,296.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1064/*"},{"ua":"XT1064"}],"dpi":[295,295.6],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1092/*"},{"ua":"XT1092"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1095/*"},{"ua":"XT1095"}],"dpi":[422,423.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/G4/*"},{"ua":"Moto G (4)"}],"dpi":401,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/A0001/*"},{"ua":"A0001"}],"dpi":[403.4,401],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1001/*"},{"ua":"ONE E1001"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1003/*"},{"ua":"ONE E1003"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1005/*"},{"ua":"ONE E1005"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2001/*"},{"ua":"ONE A2001"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2003/*"},{"ua":"ONE A2003"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2005/*"},{"ua":"ONE A2005"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A3000/*"},{"ua":"ONEPLUS A3000"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A3003/*"},{"ua":"ONEPLUS A3003"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A3010/*"},{"ua":"ONEPLUS A3010"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A5000/*"},{"ua":"ONEPLUS A5000 "}],"dpi":[403.411,399.737],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A5010/*"},{"ua":"ONEPLUS A5010"}],"dpi":[403,400],"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6000/*"},{"ua":"ONEPLUS A6000"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6003/*"},{"ua":"ONEPLUS A6003"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6010/*"},{"ua":"ONEPLUS A6010"}],"dpi":401,"bw":2,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6013/*"},{"ua":"ONEPLUS A6013"}],"dpi":401,"bw":2,"ac":500},{"type":"android","rules":[{"mdmh":"OPPO/*/X909/*"},{"ua":"X909"}],"dpi":[442.4,444.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9082/*"},{"ua":"GT-I9082"}],"dpi":[184.7,185.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G360P/*"},{"ua":"SM-G360P"}],"dpi":[196.7,205.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Nexus S/*"},{"ua":"Nexus S"}],"dpi":[234.5,229.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[304.8,303.9],"bw":5,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T230NU/*"},{"ua":"SM-T230NU"}],"dpi":216,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-T399/*"},{"ua":"SGH-T399"}],"dpi":[217.7,231.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-M919/*"},{"ua":"SGH-M919"}],"dpi":[440.8,437.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N9005/*"},{"ua":"SM-N9005"}],"dpi":[386.4,387],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SM-N900A/*"},{"ua":"SAMSUNG-SM-N900A"}],"dpi":[386.4,387.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9500/*"},{"ua":"GT-I9500"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9505/*"},{"ua":"GT-I9505"}],"dpi":439.4,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900F/*"},{"ua":"SM-G900F"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900M/*"},{"ua":"SM-G900M"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G800F/*"},{"ua":"SM-G800F"}],"dpi":326.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G906S/*"},{"ua":"SM-G906S"}],"dpi":[562.7,572.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[306.7,304.8],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T535/*"},{"ua":"SM-T535"}],"dpi":[142.6,136.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920C/*"},{"ua":"SM-N920C"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920P/*"},{"ua":"SM-N920P"}],"dpi":[386.3655,390.144],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920W8/*"},{"ua":"SM-N920W8"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300I/*"},{"ua":"GT-I9300I"}],"dpi":[304.8,305.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9195/*"},{"ua":"GT-I9195"}],"dpi":[249.4,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-L520/*"},{"ua":"SPH-L520"}],"dpi":[249.4,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SGH-I717/*"},{"ua":"SAMSUNG-SGH-I717"}],"dpi":285.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-D710/*"},{"ua":"SPH-D710"}],"dpi":[217.7,204.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-N7100/*"},{"ua":"GT-N7100"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SCH-I605/*"},{"ua":"SCH-I605"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Galaxy Nexus/*"},{"ua":"Galaxy Nexus"}],"dpi":[315.3,314.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910H/*"},{"ua":"SM-N910H"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910C/*"},{"ua":"SM-N910C"}],"dpi":[515.2,520.2],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G130M/*"},{"ua":"SM-G130M"}],"dpi":[165.9,164.8],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G928I/*"},{"ua":"SM-G928I"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920F/*"},{"ua":"SM-G920F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920P/*"},{"ua":"SM-G920P"}],"dpi":[522.5,577],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925F/*"},{"ua":"SM-G925F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925V/*"},{"ua":"SM-G925V"}],"dpi":[522.5,576.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G930F/*"},{"ua":"SM-G930F"}],"dpi":576.6,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G935F/*"},{"ua":"SM-G935F"}],"dpi":533,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G950F/*"},{"ua":"SM-G950F"}],"dpi":[562.707,565.293],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955U/*"},{"ua":"SM-G955U"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955F/*"},{"ua":"SM-G955F"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960F/*"},{"ua":"SM-G960F"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G9600/*"},{"ua":"SM-G9600"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960T/*"},{"ua":"SM-G960T"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960N/*"},{"ua":"SM-G960N"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960U/*"},{"ua":"SM-G960U"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G9608/*"},{"ua":"SM-G9608"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960FD/*"},{"ua":"SM-G960FD"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960W/*"},{"ua":"SM-G960W"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G965F/*"},{"ua":"SM-G965F"}],"dpi":529,"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/C6903/*"},{"ua":"C6903"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/D6653/*"},{"ua":"D6653"}],"dpi":[428.6,427.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6653/*"},{"ua":"E6653"}],"dpi":[428.6,425.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6853/*"},{"ua":"E6853"}],"dpi":[403.4,401.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/SGP321/*"},{"ua":"SGP321"}],"dpi":[224.7,224.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{"ua":"ALCATEL ONE TOUCH Fierce"}],"dpi":[240,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"THL/*/thl 5000/*"},{"ua":"thl 5000"}],"dpi":[480,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Fly/*/IQ4412/*"},{"ua":"IQ4412"}],"dpi":307.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"ZTE/*/ZTE Blade L2/*"},{"ua":"ZTE Blade L2"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"BENEVE/*/VR518/*"},{"ua":"VR518"}],"dpi":480,"bw":3,"ac":500},{"type":"ios","rules":[{"res":[640,960]}],"dpi":[325.1,328.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[640,1136]}],"dpi":[317.1,320.2],"bw":3,"ac":1000},{"type":"ios","rules":[{"res":[750,1334]}],"dpi":326.4,"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1242,2208]}],"dpi":[453.6,458.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2001]}],"dpi":[410.9,415.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2436]}],"dpi":458,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/EML-L29/*"},{"ua":"EML-L29"}],"dpi":428,"bw":3.45,"ac":500},{"type":"android","rules":[{"mdmh":"Nokia/*/Nokia 7.1/*"},{"ua":"Nokia 7.1"}],"dpi":[432,431.9],"bw":3,"ac":500},{"type":"ios","rules":[{"res":[1242,2688]}],"dpi":458,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G570M/*"},{"ua":"SM-G570M"}],"dpi":320,"bw":3.684,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G970F/*"},{"ua":"SM-G970F"}],"dpi":438,"bw":2.281,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G973F/*"},{"ua":"SM-G973F"}],"dpi":550,"bw":2.002,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G975F/*"},{"ua":"SM-G975F"}],"dpi":522,"bw":2.054,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G977F/*"},{"ua":"SM-G977F"}],"dpi":505,"bw":2.334,"ac":500},{"type":"ios","rules":[{"res":[828,1792]}],"dpi":326,"bw":5,"ac":500}]; var DPDB_CACHE = { format: format, last_updated: last_updated, @@ -4924,7 +4924,10 @@ CardboardVRDisplay.prototype.submitFrame = function (pose) { this.updateBounds_(); this.distorter_.submitFrame(); } else if (this.cardboardUI_ && this.layer_) { - var canvas = this.layer_.source.getContext('webgl').canvas; + var gl = this.layer_.source.getContext('webgl'); + if (!gl) gl = this.layer_.source.getContext('experimental-webgl'); + if (!gl) gl = this.layer_.source.getContext('webgl2'); + var canvas = gl.canvas; if (canvas.width != this.lastWidth || canvas.height != this.lastHeight) { this.cardboardUI_.onResize(); } @@ -4943,6 +4946,8 @@ CardboardVRDisplay.prototype.onOrientationChange_ = function (e) { CardboardVRDisplay.prototype.onResize_ = function (e) { if (this.layer_) { var gl = this.layer_.source.getContext('webgl'); + if (!gl) gl = this.layer_.source.getContext('experimental-webgl'); + if (!gl) gl = this.layer_.source.getContext('webgl2'); var cssProperties = ['position: absolute', 'top: 0', 'left: 0', 'width: 100vw', 'height: 100vh', 'border: 0', 'margin: 0', 'padding: 0px', 'box-sizing: content-box']; diff --git a/build/webxr-polyfill.min.js b/build/webxr-polyfill.min.js index ff4b6e1..8031aa7 100644 --- a/build/webxr-polyfill.min.js +++ b/build/webxr-polyfill.min.js @@ -92,4 +92,4 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.WebXRPolyfill=t()}(this,function(){"use strict";const e="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},t=Symbol("@@webxr-polyfill/EventTarget");class i{constructor(){this[t]={listeners:new Map}}addEventListener(e,i){if("string"!=typeof e)throw new Error("`type` must be a string");if("function"!=typeof i)throw new Error("`listener` must be a function");const r=this[t].listeners.get(e)||[];r.push(i),this[t].listeners.set(e,r)}removeEventListener(e,i){if("string"!=typeof e)throw new Error("`type` must be a string");if("function"!=typeof i)throw new Error("`listener` must be a function");const r=this[t].listeners.get(e)||[];for(let e=r.length;e>=0;e--)r[e]===i&&r.pop()}dispatchEvent(e,i){const r=this[t].listeners.get(e)||[],s=[];for(let e=0;e0?(r=2*Math.sqrt(i+1),e[3]=.25*r,e[0]=(t[6]-t[9])/r,e[1]=(t[8]-t[2])/r,e[2]=(t[1]-t[4])/r):t[0]>t[5]&&t[0]>t[10]?(r=2*Math.sqrt(1+t[0]-t[5]-t[10]),e[3]=(t[6]-t[9])/r,e[0]=.25*r,e[1]=(t[1]+t[4])/r,e[2]=(t[8]+t[2])/r):t[5]>t[10]?(r=2*Math.sqrt(1+t[5]-t[0]-t[10]),e[3]=(t[8]-t[2])/r,e[0]=(t[1]+t[4])/r,e[1]=.25*r,e[2]=(t[6]+t[9])/r):(r=2*Math.sqrt(1+t[10]-t[0]-t[5]),e[3]=(t[1]-t[4])/r,e[0]=(t[8]+t[2])/r,e[1]=(t[6]+t[9])/r,e[2]=.25*r),e}function d(e,t,i,r,s){let n,a=1/Math.tan(t/2);return e[0]=a/i,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=a,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[11]=-1,e[12]=0,e[13]=0,e[15]=0,null!=s&&s!==1/0?(n=1/(r-s),e[10]=(s+r)*n,e[14]=2*s*r*n):(e[10]=-1,e[14]=-2*r),e}function u(){let e=new s(3);return s!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e}function p(e){var t=new s(3);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t}function f(e,t,i){let r=new s(3);return r[0]=e,r[1]=t,r[2]=i,r}function m(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e}function g(e,t,i){return e[0]=t[0]+i[0],e[1]=t[1]+i[1],e[2]=t[2]+i[2],e}function v(e,t,i){return e[0]=t[0]*i,e[1]=t[1]*i,e[2]=t[2]*i,e}function w(e,t){let i=t[0],r=t[1],s=t[2],n=i*i+r*r+s*s;return n>0&&(n=1/Math.sqrt(n),e[0]=t[0]*n,e[1]=t[1]*n,e[2]=t[2]*n),e}function y(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]}function b(e,t,i){let r=t[0],s=t[1],n=t[2],a=i[0],o=i[1],l=i[2];return e[0]=s*l-n*o,e[1]=n*a-r*l,e[2]=r*o-s*a,e}function E(e,t,i){let r=i[0],s=i[1],n=i[2],a=i[3],o=t[0],l=t[1],A=t[2],h=s*A-n*l,c=n*o-r*A,d=r*l-s*o,u=s*d-n*c,p=n*h-r*d,f=r*c-s*h,m=2*a;return h*=m,c*=m,d*=m,u*=2,p*=2,f*=2,e[0]=o+h+u,e[1]=l+c+p,e[2]=A+d+f,e}const S=function(e){let t=e[0],i=e[1],r=e[2];return Math.sqrt(t*t+i*i+r*r)};!function(){let e=u()}();!function(){let e=function(){let e=new s(4);return s!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0,e[3]=0),e}()}();function M(){let e=new s(4);return s!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e[3]=1,e}function x(e,t,i){let r=t[0],s=t[1],n=t[2],a=t[3],o=i[0],l=i[1],A=i[2],h=i[3];return e[0]=r*h+a*o+s*A-n*l,e[1]=s*h+a*l+n*o-r*A,e[2]=n*h+a*A+r*l-s*o,e[3]=a*h-r*o-s*l-n*A,e}function _(e,t,i,s){let n,a,o,l,A,h=t[0],c=t[1],d=t[2],u=t[3],p=i[0],f=i[1],m=i[2],g=i[3];return(a=h*p+c*f+d*m+u*g)<0&&(a=-a,p=-p,f=-f,m=-m,g=-g),1-a>r?(n=Math.acos(a),o=Math.sin(n),l=Math.sin((1-s)*n)/o,A=Math.sin(s*n)/o):(l=1-s,A=s),e[0]=l*h+A*p,e[1]=l*c+A*f,e[2]=l*d+A*m,e[3]=l*u+A*g,e}function F(e,t){let i=t[0],r=t[1],s=t[2],n=t[3],a=i*i+r*r+s*s+n*n,o=a?1/a:0;return e[0]=-i*o,e[1]=-r*o,e[2]=-s*o,e[3]=n*o,e}const R=function(e){let t=new s(4);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},T=function(e,t,i,r){let n=new s(4);return n[0]=e,n[1]=t,n[2]=i,n[3]=r,n},B=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e},C=function(e,t){let i=t[0],r=t[1],s=t[2],n=t[3],a=i*i+r*r+s*s+n*n;return a>0&&(a=1/Math.sqrt(a),e[0]=i*a,e[1]=r*a,e[2]=s*a,e[3]=n*a),e},D=(function(){let e=u(),t=f(1,0,0),i=f(0,1,0)}(),function(){let e=M(),t=M()}(),function(){let e=function(){let e=new s(9);return s!=Float32Array&&(e[1]=0,e[2]=0,e[3]=0,e[5]=0,e[6]=0,e[7]=0),e[0]=1,e[4]=1,e[8]=1,e}()}(),Symbol("@@webxr-polyfill/XRRigidTransform"));class P{constructor(){if(this[D]={matrix:null,position:null,orientation:null,inverse:null},0===arguments.length)this[D].matrix=a(new Float32Array(16));else if(1===arguments.length)arguments[0]instanceof Float32Array?this[D].matrix=arguments[0]:(this[D].position=this._getPoint(arguments[0]),this[D].orientation=DOMPointReadOnly.fromPoint({x:0,y:0,z:0,w:1}));else{if(2!==arguments.length)throw new Error("Too many arguments!");this[D].position=this._getPoint(arguments[0]),this[D].orientation=this._getPoint(arguments[1])}if(this[D].matrix){let e=u();h(e,this[D].matrix),this[D].position=DOMPointReadOnly.fromPoint({x:e[0],y:e[1],z:e[2]});let t=M();c(t,this[D].matrix),this[D].orientation=DOMPointReadOnly.fromPoint({x:t[0],y:t[1],z:t[2],w:t[3]})}else this[D].matrix=a(new Float32Array(16)),A(this[D].matrix,T(this[D].orientation.x,this[D].orientation.y,this[D].orientation.z,this[D].orientation.w),f(this[D].position.x,this[D].position.y,this[D].position.z))}_getPoint(e){return e instanceof DOMPointReadOnly?e:DOMPointReadOnly.fromPoint(e)}get matrix(){return this[D].matrix}get position(){return this[D].position}get orientation(){return this[D].orientation}get inverse(){if(null===this[D].inverse){let e=a(new Float32Array(16));o(e,this[D].matrix),this[D].inverse=new P(e),this[D].inverse[D].inverse=this}return this[D].inverse}}const I=Symbol("@@webxr-polyfill/XRSpace");class L{constructor(e=null,t=null){this[I]={specialType:e,inputSource:t,baseMatrix:null,inverseBaseMatrix:null,lastFrameId:-1}}get _specialType(){return this[I].specialType}get _inputSource(){return this[I].inputSource}_ensurePoseUpdated(e,t){t!=this[I].lastFrameId&&(this[I].lastFrameId=t,this._onPoseUpdate(e))}_onPoseUpdate(e){"viewer"==this[I].specialType&&(this._baseMatrix=e.getBasePoseMatrix())}set _baseMatrix(e){this[I].baseMatrix=e,this[I].inverseBaseMatrix=null}get _baseMatrix(){return this[I].baseMatrix||this[I].inverseBaseMatrix&&(this[I].baseMatrix=new Float32Array(16),o(this[I].baseMatrix,this[I].inverseBaseMatrix)),this[I].baseMatrix}set _inverseBaseMatrix(e){this[I].inverseBaseMatrix=e,this[I].baseMatrix=null}get _inverseBaseMatrix(){return this[I].inverseBaseMatrix||this[I].baseMatrix&&(this[I].inverseBaseMatrix=new Float32Array(16),o(this[I].inverseBaseMatrix,this[I].baseMatrix)),this[I].inverseBaseMatrix}_getSpaceRelativeTransform(e){if(!this._inverseBaseMatrix||!e._baseMatrix)return null;let t=new Float32Array(16);return l(t,this._inverseBaseMatrix,e._baseMatrix),new P(t)}}const O=1.6,N=Symbol("@@webxr-polyfill/XRReferenceSpace"),Q=["viewer","local","local-floor","bounded-floor","unbounded"];class G extends L{constructor(e,t=null){if(!Q.includes(e))throw new Error(`XRReferenceSpaceType must be one of ${Q}`);if(super(e),"bounded-floor"===e&&!t)throw new Error("XRReferenceSpace cannot use 'bounded-floor' type if the platform does not provide the floor level");(function(e){return"bounded-floor"===e||"local-floor"===e})(e)&&!t&&((t=a(new Float32Array(16)))[13]=O),this._inverseBaseMatrix=t||a(new Float32Array(16)),this[N]={type:e,transform:t,originOffset:a(new Float32Array(16))}}_transformBasePoseMatrix(e,t){l(e,this._inverseBaseMatrix,t)}_originOffsetMatrix(){return this[N].originOffset}_adjustForOriginOffset(e){let t=new Float32Array(16);o(t,this[N].originOffset),l(e,t,e)}_getSpaceRelativeTransform(e){let t=super._getSpaceRelativeTransform(e);return this._adjustForOriginOffset(t.matrix),new XRRigidTransform(t.matrix)}getOffsetReferenceSpace(e){let t=new G(this[N].type,this[N].transform,this[N].bounds);return l(t[N].originOffset,this[N].originOffset,e.matrix),t}}const k=Symbol("@@webxr-polyfill/XR"),z=["inline","immersive-vr","immersive-ar"],V={inline:{requiredFeatures:["viewer"],optionalFeatures:[]},"immersive-vr":{requiredFeatures:["viewer","local"],optionalFeatures:[]},"immersive-ar":{requiredFeatures:["viewer","local"],optionalFeatures:[]}},U="Polyfill Error: Must call navigator.xr.isSessionSupported() with any XRSessionMode\nor navigator.xr.requestSession('inline') prior to requesting an immersive\nsession. This is a limitation specific to the WebXR Polyfill and does not apply\nto native implementations of the API.";let H;if("performance"in e==!1){let e=Date.now();H=(()=>Date.now()-e)}else H=(()=>performance.now());var X=H;const W=Symbol("@@webxr-polyfill/XRPose");class j{constructor(e,t){this[W]={transform:e,emulatedPosition:t}}get transform(){return this[W].transform}get emulatedPosition(){return this[W].emulatedPosition}}const q=Symbol("@@webxr-polyfill/XRViewerPose");class Y extends j{constructor(e,t,i=!1){super(e,i),this[q]={views:t}}get views(){return this[q].views}}const Z=Symbol("@@webxr-polyfill/XRViewport");class J{constructor(e){this[Z]={target:e}}get x(){return this[Z].target.x}get y(){return this[Z].target.y}get width(){return this[Z].target.width}get height(){return this[Z].target.height}}const K=["left","right","none"],$=Symbol("@@webxr-polyfill/XRView");class ee{constructor(e,t,i,r){if(!K.includes(i))throw new Error(`XREye must be one of: ${K}`);const s=Object.create(null),n=new J(s);this[$]={device:e,eye:i,viewport:n,temp:s,sessionId:r,transform:t}}get eye(){return this[$].eye}get projectionMatrix(){return this[$].device.getProjectionMatrix(this.eye)}get transform(){return this[$].transform}_getViewport(e){if(this[$].device.getViewport(this[$].sessionId,this.eye,e,this[$].temp))return this[$].viewport}}const te=Symbol("@@webxr-polyfill/XRFrame"),ie="XRFrame access outside the callback that produced it is invalid.",re="getViewerPose can only be called on XRFrame objects passed to XRSession.requestAnimationFrame callbacks.";let se=0;class ne{constructor(e,t,i){this[te]={id:++se,active:!1,animationFrame:!1,device:e,session:t,sessionId:i}}get session(){return this[te].session}getViewerPose(e){if(!this[te].animationFrame)throw new DOMException(re,"InvalidStateError");if(!this[te].active)throw new DOMException(ie,"InvalidStateError");const t=this[te].device,i=this[te].session;i[we].viewerSpace._ensurePoseUpdated(t,this[te].id),e._ensurePoseUpdated(t,this[te].id);let r=e._getSpaceRelativeTransform(i[we].viewerSpace);const s=[];for(let r of i[we].viewSpaces){r._ensurePoseUpdated(t,this[te].id);let i=e._getSpaceRelativeTransform(r),n=new ee(t,i,r.eye,this[te].sessionId);s.push(n)}return new Y(r,s,!1)}getPose(e,t){if(!this[te].active)throw new DOMException(ie,"InvalidStateError");const i=this[te].device;if("target-ray"===e._specialType||"grip"===e._specialType)return i.getInputPose(e._inputSource,t,e._specialType);{e._ensurePoseUpdated(i,this[te].id),t._ensurePoseUpdated(i,this[te].id);let r=t._getSpaceRelativeTransform(e);return r?new XRPose(r,!1):null}}}const ae=Symbol("@@webxr-polyfill/XRRenderState"),oe=Object.freeze({depthNear:.1,depthFar:1e3,inlineVerticalFieldOfView:null,baseLayer:null});class le{constructor(e={}){const t=Object.assign({},oe,e);this[ae]={config:t}}get depthNear(){return this[ae].config.depthNear}get depthFar(){return this[ae].config.depthFar}get inlineVerticalFieldOfView(){return this[ae].config.inlineVerticalFieldOfView}get baseLayer(){return this[ae].config.baseLayer}}const Ae=Symbol("@@webxr-polyfill/polyfilled-xr-compatible"),he=Symbol("@@webxr-polyfill/xr-compatible"),ce=Symbol("@@webxr-polyfill/XRWebGLLayer"),de=Object.freeze({antialias:!0,depth:!1,stencil:!1,alpha:!0,multiview:!1,ignoreDepthValues:!1,framebufferScaleFactor:1});const ue=Symbol("@@webxr-polyfill/XRInputSourceEvent");class pe extends Event{constructor(e,t){super(e,t),this[ue]={frame:t.frame,inputSource:t.inputSource}}get frame(){return this[ue].frame}get inputSource(){return this[ue].inputSource}}const fe=Symbol("@@webxr-polyfill/XRSessionEvent");class me extends Event{constructor(e,t){super(e,t),this[fe]={session:t.session}}get session(){return this[fe].session}}const ge=Symbol("@@webxr-polyfill/XRInputSourcesChangeEvent");class ve extends Event{constructor(e,t){super(e,t),this[ge]={session:t.session,added:t.added,removed:t.removed}}get session(){return this[ge].session}get added(){return this[ge].added}get removed(){return this[ge].removed}}const we=Symbol("@@webxr-polyfill/XRSession");class ye extends L{constructor(e){super(e)}get eye(){return this._specialType}_onPoseUpdate(e){this._inverseBaseMatrix=e.getBaseViewMatrix(this._specialType)}}class be extends i{constructor(e,t,i){super();let r="inline"!=t,s=new le({inlineVerticalFieldOfView:r?null:.5*Math.PI});this[we]={device:e,mode:t,immersive:r,ended:!1,suspended:!1,frameCallbacks:[],currentFrameCallbacks:null,frameHandle:0,deviceFrameHandle:null,id:i,activeRenderState:s,pendingRenderState:null,viewerSpace:new G("viewer"),viewSpaces:[],currentInputSources:[]},r?this[we].viewSpaces.push(new ye("left"),new ye("right")):this[we].viewSpaces.push(new ye("none")),this[we].onDeviceFrame=(()=>{if(this[we].ended||this[we].suspended)return;if(this[we].deviceFrameHandle=null,this[we].startDeviceFrameLoop(),null!==this[we].pendingRenderState&&(this[we].activeRenderState=new le(this[we].pendingRenderState),this[we].pendingRenderState=null,this[we].activeRenderState.baseLayer&&this[we].device.onBaseLayerSet(this[we].id,this[we].activeRenderState.baseLayer)),null===this[we].activeRenderState.baseLayer)return;const t=new ne(e,this,this[we].id),i=this[we].currentFrameCallbacks=this[we].frameCallbacks;this[we].frameCallbacks=[],t[te].active=!0,t[te].animationFrame=!0,this[we].device.onFrameStart(this[we].id,this[we].activeRenderState),this._checkInputSourcesChange();const r=X();for(let e=0;e{null===this[we].deviceFrameHandle&&(this[we].deviceFrameHandle=this[we].device.requestAnimationFrame(this[we].onDeviceFrame))}),this[we].stopDeviceFrameLoop=(()=>{const e=this[we].deviceFrameHandle;null!==e&&(this[we].device.cancelAnimationFrame(e),this[we].deviceFrameHandle=null)}),this[we].onPresentationEnd=(t=>{if(t!==this[we].id)return this[we].suspended=!1,this[we].startDeviceFrameLoop(),void this.dispatchEvent("focus",{session:this});this[we].ended=!0,this[we].stopDeviceFrameLoop(),e.removeEventListener("@webvr-polyfill/vr-present-end",this[we].onPresentationEnd),e.removeEventListener("@webvr-polyfill/vr-present-start",this[we].onPresentationStart),e.removeEventListener("@@webvr-polyfill/input-select-start",this[we].onSelectStart),e.removeEventListener("@@webvr-polyfill/input-select-end",this[we].onSelectEnd),this.dispatchEvent("end",new me("end",{session:this}))}),e.addEventListener("@@webxr-polyfill/vr-present-end",this[we].onPresentationEnd),this[we].onPresentationStart=(e=>{e!==this[we].id&&(this[we].suspended=!0,this[we].stopDeviceFrameLoop(),this.dispatchEvent("blur",{session:this}))}),e.addEventListener("@@webxr-polyfill/vr-present-start",this[we].onPresentationStart),this[we].onSelectStart=(e=>{e.sessionId===this[we].id&&this[we].dispatchInputSourceEvent("selectstart",e.inputSource)}),e.addEventListener("@@webxr-polyfill/input-select-start",this[we].onSelectStart),this[we].onSelectEnd=(e=>{e.sessionId===this[we].id&&(this[we].dispatchInputSourceEvent("selectend",e.inputSource),this[we].dispatchInputSourceEvent("select",e.inputSource))}),e.addEventListener("@@webxr-polyfill/input-select-end",this[we].onSelectEnd),this[we].onSqueezeStart=(e=>{e.sessionId===this[we].id&&this[we].dispatchInputSourceEvent("squeezestart",e.inputSource)}),e.addEventListener("@@webxr-polyfill/input-squeeze-start",this[we].onSqueezeStart),this[we].onSqueezeEnd=(e=>{e.sessionId===this[we].id&&(this[we].dispatchInputSourceEvent("squeezeend",e.inputSource),this[we].dispatchInputSourceEvent("squeeze",e.inputSource))}),e.addEventListener("@@webxr-polyfill/input-squeeze-end",this[we].onSqueezeEnd),this[we].dispatchInputSourceEvent=((t,i)=>{const r=new ne(e,this,this[we].id),s=new pe(t,{frame:r,inputSource:i});r[te].active=!0,this.dispatchEvent(t,s),r[te].active=!1}),this[we].startDeviceFrameLoop(),this.onblur=void 0,this.onfocus=void 0,this.onresetpose=void 0,this.onend=void 0,this.onselect=void 0,this.onselectstart=void 0,this.onselectend=void 0}get renderState(){return this[we].activeRenderState}get environmentBlendMode(){return this[we].device.environmentBlendMode||"opaque"}async requestReferenceSpace(e){if(this[we].ended)return;if(!Q.includes(e))throw new TypeError(`XRReferenceSpaceType must be one of ${Q}`);if(!this[we].device.doesSessionSupportReferenceSpace(this[we].id,e))throw new DOMException(`The ${e} reference space is not supported by this session.`,"NotSupportedError");if("viewer"===e)return this[we].viewerSpace;let t=await this[we].device.requestFrameOfReferenceTransform(e);if("bounded-floor"===e){if(!t)throw new DOMException(`${e} XRReferenceSpace not supported by this device.`,"NotSupportedError");if(!this[we].device.requestStageBounds())throw new DOMException(`${e} XRReferenceSpace not supported by this device.`,"NotSupportedError");throw new DOMException(`The WebXR polyfill does not support the ${e} reference space yet.`,"NotSupportedError")}return new G(e,t)}requestAnimationFrame(e){if(this[we].ended)return;const t=++this[we].frameHandle;return this[we].frameCallbacks.push({handle:t,callback:e,cancelled:!1}),t}cancelAnimationFrame(e){let t=this[we].frameCallbacks,i=t.findIndex(t=>t&&t.handle===e);i>-1&&(t[i].cancelled=!0,t.splice(i,1)),(t=this[we].currentFrameCallbacks)&&(i=t.findIndex(t=>t&&t.handle===e))>-1&&(t[i].cancelled=!0)}get inputSources(){return this[we].device.getInputSources()}async end(){if(!this[we].ended)return this.immersive&&(this[we].ended=!0,this[we].device.removeEventListener("@@webvr-polyfill/vr-present-start",this[we].onPresentationStart),this[we].device.removeEventListener("@@webvr-polyfill/vr-present-end",this[we].onPresentationEnd),this[we].device.removeEventListener("@@webvr-polyfill/input-select-start",this[we].onSelectStart),this[we].device.removeEventListener("@@webvr-polyfill/input-select-end",this[we].onSelectEnd),this.dispatchEvent("end",new me("end",{session:this}))),this[we].stopDeviceFrameLoop(),this[we].device.endSession(this[we].id)}updateRenderState(e){if(this[we].ended){throw new Error("Can't call updateRenderState on an XRSession that has already ended.")}if(e.baseLayer&&e.baseLayer._session!==this){throw new Error("Called updateRenderState with a base layer that was created by a different session.")}if(null!==e.inlineVerticalFieldOfView&&void 0!==e.inlineVerticalFieldOfView){if(this[we].immersive){throw new Error("inlineVerticalFieldOfView must not be set for an XRRenderState passed to updateRenderState for an immersive session.")}e.inlineVerticalFieldOfView=Math.min(3.13,Math.max(.01,e.inlineVerticalFieldOfView))}if(null===this[we].pendingRenderState){const e=this[we].activeRenderState;this[we].pendingRenderState={depthNear:e.depthNear,depthFar:e.depthFar,inlineVerticalFieldOfView:e.inlineVerticalFieldOfView,baseLayer:e.baseLayer}}Object.assign(this[we].pendingRenderState,e)}_checkInputSourcesChange(){const e=[],t=[],i=this.inputSources,r=this[we].currentInputSources;for(const t of i)r.includes(t)||e.push(t);for(const e of r)i.includes(e)||t.push(e);(e.length>0||t.length>0)&&this.dispatchEvent("inputsourceschange",new ve("inputsourceschange",{session:this,added:e,removed:t})),this[we].currentInputSources.length=0;for(const e of i)this[we].currentInputSources.push(e)}}const Ee=Symbol("@@webxr-polyfill/XRInputSource");class Se{constructor(e){this[Ee]={impl:e,gripSpace:new L("grip",this),targetRaySpace:new L("target-ray",this)}}get handedness(){return this[Ee].impl.handedness}get targetRayMode(){return this[Ee].impl.targetRayMode}get gripSpace(){let e=this[Ee].impl.targetRayMode;return"gaze"===e||"screen"===e?null:this[Ee].gripSpace}get targetRaySpace(){return this[Ee].targetRaySpace}get profiles(){return this[Ee].impl.profiles}get gamepad(){return this[Ee].impl.gamepad}}const Me=Symbol("@@webxr-polyfill/XRReferenceSpaceEvent");var xe={XR:class extends i{constructor(e){super(),this[k]={device:null,devicePromise:e,immersiveSession:null,inlineSessions:new Set},e.then(e=>{this[k].device=e})}async isSessionSupported(e){return this[k].device||await this[k].devicePromise,"inline"!=e?Promise.resolve(this[k].device.isSessionSupported(e)):Promise.resolve(!0)}async requestSession(e,t){if(!this[k].device){if("inline"!=e)throw new Error(U);await this[k].devicePromise}if(!z.includes(e))throw new TypeError(`The provided value '${e}' is not a valid enum value of type XRSessionMode`);const i=V[e],r=i.requiredFeatures.concat(t&&t.requiredFeatures?t.requiredFeatures:[]),s=i.optionalFeatures.concat(t&&t.optionalFeatures?t.optionalFeatures:[]),n=new Set;let a=!1;for(let e of r)this[k].device.isFeatureSupported(e)?n.add(e):(console.error(`The required feature '${e}' is not supported`),a=!0);if(a)throw new DOMException("Session does not support some required features","NotSupportedError");for(let e of s)this[k].device.isFeatureSupported(e)?n.add(e):console.log(`The optional feature '${e}' is not supported`);const o=await this[k].device.requestSession(e,n),l=new XRSession(this[k].device,e,o);"inline"==e?this[k].inlineSessions.add(l):this[k].immersiveSession=l;const A=()=>{"inline"==e?this[k].inlineSessions.delete(l):this[k].immersiveSession=null,l.removeEventListener("end",A)};return l.addEventListener("end",A),l}},XRSession:be,XRSessionEvent:me,XRFrame:ne,XRView:ee,XRViewport:J,XRViewerPose:Y,XRWebGLLayer:class{constructor(e,t,i={}){const r=Object.assign({},de,i);if(!(e instanceof be))throw new Error("session must be a XRSession");if(e.ended)throw new Error("InvalidStateError");if(t[Ae]&&!0!==t[he])throw new Error("InvalidStateError");const s=t.getParameter(t.FRAMEBUFFER_BINDING);this[ce]={context:t,config:r,framebuffer:s,session:e}}get context(){return this[ce].context}get antialias(){return this[ce].config.antialias}get ignoreDepthValues(){return!0}get framebuffer(){return this[ce].framebuffer}get framebufferWidth(){return this[ce].context.drawingBufferWidth}get framebufferHeight(){return this[ce].context.drawingBufferHeight}get _session(){return this[ce].session}getViewport(e){return e._getViewport(this)}static getNativeFramebufferScaleFactor(e){if(!e)throw new TypeError("getNativeFramebufferScaleFactor must be passed a session.");return e[we].ended?0:1}},XRSpace:L,XRReferenceSpace:G,XRReferenceSpaceEvent:class extends Event{constructor(e,t){super(e,t),this[Me]={referenceSpace:t.referenceSpace,transform:t.transform||null}}get referenceSpace(){return this[Me].referenceSpace}get transform(){return this[Me].transform}},XRInputSource:Se,XRInputSourceEvent:pe,XRInputSourcesChangeEvent:ve,XRRenderState:le,XRRigidTransform:P,XRPose:j};const _e=e=>"function"!=typeof e.prototype.makeXRCompatible&&(e.prototype.makeXRCompatible=function(){return this[he]=!0,Promise.resolve()},!0),Fe=e=>{const t=e.prototype.getContext;e.prototype.getContext=function(e,i){const r=t.call(this,e,i);return r&&(r[Ae]=!0,i&&"xrCompatible"in i&&(r[he]=i.xrCompatible)),r}},Re=e=>!(!e.ImageBitmapRenderingContext||!e.createImageBitmap);var Te;const Be=e=>{e.style.display="block",e.style.position="absolute",e.style.width=e.style.height="1px",e.style.top=e.style.left="0px"};var Ce="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var De,Pe,Ie=(function(e,t){e.exports=function(){var e,t,i,r=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},s=function(){function e(e,t){for(var i=0;ie.TEXTURE31){console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit"),r.push(null,null);break}s||(s=e.getParameter(e.ACTIVE_TEXTURE)),e.activeTexture(o),r.push(e.getParameter(a),null);break;case e.ACTIVE_TEXTURE:s=e.getParameter(e.ACTIVE_TEXTURE),r.push(null);break;default:r.push(e.getParameter(a))}}i(e);for(var n=0;ne.TEXTURE31)break;e.activeTexture(o),e.bindTexture(e.TEXTURE_2D,l);break;case e.TEXTURE_BINDING_CUBE_MAP:var o=t[++n];if(oe.TEXTURE31)break;e.activeTexture(o),e.bindTexture(e.TEXTURE_CUBE_MAP,l);break;case e.VIEWPORT:e.viewport(l[0],l[1],l[2],l[3]);break;case e.BLEND:case e.CULL_FACE:case e.DEPTH_TEST:case e.SCISSOR_TEST:case e.STENCIL_TEST:l?e.enable(a):e.disable(a);break;default:console.log("No GL restore behavior for 0x"+a.toString(16))}s&&e.activeTexture(s)}}else i(e)},F=["attribute vec2 position;","attribute vec3 texCoord;","varying vec2 vTexCoord;","uniform vec4 viewportOffsetScale[2];","void main() {"," vec4 viewport = viewportOffsetScale[int(texCoord.z)];"," vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;"," gl_Position = vec4( position, 1.0, 1.0 );","}"].join("\n"),R=["precision mediump float;","uniform sampler2D diffuse;","varying vec2 vTexCoord;","void main() {"," gl_FragColor = texture2D(diffuse, vTexCoord);","}"].join("\n");function T(e,t,i,r){this.gl=e,this.cardboardUI=t,this.bufferScale=i,this.dirtySubmitFrameBindings=r,this.ctxAttribs=e.getContextAttributes(),this.meshWidth=20,this.meshHeight=20,this.bufferWidth=e.drawingBufferWidth,this.bufferHeight=e.drawingBufferHeight,this.realBindFramebuffer=e.bindFramebuffer,this.realEnable=e.enable,this.realDisable=e.disable,this.realColorMask=e.colorMask,this.realClearColor=e.clearColor,this.realViewport=e.viewport,o()||(this.realCanvasWidth=Object.getOwnPropertyDescriptor(e.canvas.__proto__,"width"),this.realCanvasHeight=Object.getOwnPropertyDescriptor(e.canvas.__proto__,"height")),this.isPatched=!1,this.lastBoundFramebuffer=null,this.cullFace=!1,this.depthTest=!1,this.blend=!1,this.scissorTest=!1,this.stencilTest=!1,this.viewport=[0,0,0,0],this.colorMask=[!0,!0,!0,!0],this.clearColor=[0,0,0,0],this.attribs={position:0,texCoord:1},this.program=g(e,F,R,this.attribs),this.uniforms=v(e,this.program),this.viewportOffsetScale=new Float32Array(8),this.setTextureBounds(),this.vertexBuffer=e.createBuffer(),this.indexBuffer=e.createBuffer(),this.indexCount=0,this.renderTarget=e.createTexture(),this.framebuffer=e.createFramebuffer(),this.depthStencilBuffer=null,this.depthBuffer=null,this.stencilBuffer=null,this.ctxAttribs.depth&&this.ctxAttribs.stencil?this.depthStencilBuffer=e.createRenderbuffer():this.ctxAttribs.depth?this.depthBuffer=e.createRenderbuffer():this.ctxAttribs.stencil&&(this.stencilBuffer=e.createRenderbuffer()),this.patch(),this.onResize()}T.prototype.destroy=function(){var e=this.gl;this.unpatch(),e.deleteProgram(this.program),e.deleteBuffer(this.vertexBuffer),e.deleteBuffer(this.indexBuffer),e.deleteTexture(this.renderTarget),e.deleteFramebuffer(this.framebuffer),this.depthStencilBuffer&&e.deleteRenderbuffer(this.depthStencilBuffer),this.depthBuffer&&e.deleteRenderbuffer(this.depthBuffer),this.stencilBuffer&&e.deleteRenderbuffer(this.stencilBuffer),this.cardboardUI&&this.cardboardUI.destroy()},T.prototype.onResize=function(){var e=this.gl,t=this,i=[e.RENDERBUFFER_BINDING,e.TEXTURE_BINDING_2D,e.TEXTURE0];_(e,i,function(e){t.realBindFramebuffer.call(e,e.FRAMEBUFFER,null),t.scissorTest&&t.realDisable.call(e,e.SCISSOR_TEST),t.realColorMask.call(e,!0,!0,!0,!0),t.realViewport.call(e,0,0,e.drawingBufferWidth,e.drawingBufferHeight),t.realClearColor.call(e,0,0,0,1),e.clear(e.COLOR_BUFFER_BIT),t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.framebuffer),e.bindTexture(e.TEXTURE_2D,t.renderTarget),e.texImage2D(e.TEXTURE_2D,0,t.ctxAttribs.alpha?e.RGBA:e.RGB,t.bufferWidth,t.bufferHeight,0,t.ctxAttribs.alpha?e.RGBA:e.RGB,e.UNSIGNED_BYTE,null),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t.renderTarget,0),t.ctxAttribs.depth&&t.ctxAttribs.stencil?(e.bindRenderbuffer(e.RENDERBUFFER,t.depthStencilBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.DEPTH_STENCIL,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.DEPTH_STENCIL_ATTACHMENT,e.RENDERBUFFER,t.depthStencilBuffer)):t.ctxAttribs.depth?(e.bindRenderbuffer(e.RENDERBUFFER,t.depthBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.DEPTH_COMPONENT16,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.DEPTH_ATTACHMENT,e.RENDERBUFFER,t.depthBuffer)):t.ctxAttribs.stencil&&(e.bindRenderbuffer(e.RENDERBUFFER,t.stencilBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.STENCIL_INDEX8,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.STENCIL_ATTACHMENT,e.RENDERBUFFER,t.stencilBuffer)),!e.checkFramebufferStatus(e.FRAMEBUFFER)===e.FRAMEBUFFER_COMPLETE&&console.error("Framebuffer incomplete!"),t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.lastBoundFramebuffer),t.scissorTest&&t.realEnable.call(e,e.SCISSOR_TEST),t.realColorMask.apply(e,t.colorMask),t.realViewport.apply(e,t.viewport),t.realClearColor.apply(e,t.clearColor)}),this.cardboardUI&&this.cardboardUI.onResize()},T.prototype.patch=function(){if(!this.isPatched){var e=this,t=this.gl.canvas,i=this.gl;o()||(t.width=p()*this.bufferScale,t.height=f()*this.bufferScale,Object.defineProperty(t,"width",{configurable:!0,enumerable:!0,get:function(){return e.bufferWidth},set:function(i){e.bufferWidth=i,e.realCanvasWidth.set.call(t,i),e.onResize()}}),Object.defineProperty(t,"height",{configurable:!0,enumerable:!0,get:function(){return e.bufferHeight},set:function(i){e.bufferHeight=i,e.realCanvasHeight.set.call(t,i),e.onResize()}})),this.lastBoundFramebuffer=i.getParameter(i.FRAMEBUFFER_BINDING),null==this.lastBoundFramebuffer&&(this.lastBoundFramebuffer=this.framebuffer,this.gl.bindFramebuffer(i.FRAMEBUFFER,this.framebuffer)),this.gl.bindFramebuffer=function(t,r){e.lastBoundFramebuffer=r||e.framebuffer,e.realBindFramebuffer.call(i,t,e.lastBoundFramebuffer)},this.cullFace=i.getParameter(i.CULL_FACE),this.depthTest=i.getParameter(i.DEPTH_TEST),this.blend=i.getParameter(i.BLEND),this.scissorTest=i.getParameter(i.SCISSOR_TEST),this.stencilTest=i.getParameter(i.STENCIL_TEST),i.enable=function(t){switch(t){case i.CULL_FACE:e.cullFace=!0;break;case i.DEPTH_TEST:e.depthTest=!0;break;case i.BLEND:e.blend=!0;break;case i.SCISSOR_TEST:e.scissorTest=!0;break;case i.STENCIL_TEST:e.stencilTest=!0}e.realEnable.call(i,t)},i.disable=function(t){switch(t){case i.CULL_FACE:e.cullFace=!1;break;case i.DEPTH_TEST:e.depthTest=!1;break;case i.BLEND:e.blend=!1;break;case i.SCISSOR_TEST:e.scissorTest=!1;break;case i.STENCIL_TEST:e.stencilTest=!1}e.realDisable.call(i,t)},this.colorMask=i.getParameter(i.COLOR_WRITEMASK),i.colorMask=function(t,r,s,n){e.colorMask[0]=t,e.colorMask[1]=r,e.colorMask[2]=s,e.colorMask[3]=n,e.realColorMask.call(i,t,r,s,n)},this.clearColor=i.getParameter(i.COLOR_CLEAR_VALUE),i.clearColor=function(t,r,s,n){e.clearColor[0]=t,e.clearColor[1]=r,e.clearColor[2]=s,e.clearColor[3]=n,e.realClearColor.call(i,t,r,s,n)},this.viewport=i.getParameter(i.VIEWPORT),i.viewport=function(t,r,s,n){e.viewport[0]=t,e.viewport[1]=r,e.viewport[2]=s,e.viewport[3]=n,e.realViewport.call(i,t,r,s,n)},this.isPatched=!0,b(t)}},T.prototype.unpatch=function(){if(this.isPatched){var e=this.gl,t=this.gl.canvas;o()||(Object.defineProperty(t,"width",this.realCanvasWidth),Object.defineProperty(t,"height",this.realCanvasHeight)),t.width=this.bufferWidth,t.height=this.bufferHeight,e.bindFramebuffer=this.realBindFramebuffer,e.enable=this.realEnable,e.disable=this.realDisable,e.colorMask=this.realColorMask,e.clearColor=this.realClearColor,e.viewport=this.realViewport,this.lastBoundFramebuffer==this.framebuffer&&e.bindFramebuffer(e.FRAMEBUFFER,null),this.isPatched=!1,setTimeout(function(){b(t)},1)}},T.prototype.setTextureBounds=function(e,t){e||(e=[0,0,.5,1]),t||(t=[.5,0,.5,1]),this.viewportOffsetScale[0]=e[0],this.viewportOffsetScale[1]=e[1],this.viewportOffsetScale[2]=e[2],this.viewportOffsetScale[3]=e[3],this.viewportOffsetScale[4]=t[0],this.viewportOffsetScale[5]=t[1],this.viewportOffsetScale[6]=t[2],this.viewportOffsetScale[7]=t[3]},T.prototype.submitFrame=function(){var e=this.gl,t=this,i=[];if(this.dirtySubmitFrameBindings||i.push(e.CURRENT_PROGRAM,e.ARRAY_BUFFER_BINDING,e.ELEMENT_ARRAY_BUFFER_BINDING,e.TEXTURE_BINDING_2D,e.TEXTURE0),_(e,i,function(e){t.realBindFramebuffer.call(e,e.FRAMEBUFFER,null),t.cullFace&&t.realDisable.call(e,e.CULL_FACE),t.depthTest&&t.realDisable.call(e,e.DEPTH_TEST),t.blend&&t.realDisable.call(e,e.BLEND),t.scissorTest&&t.realDisable.call(e,e.SCISSOR_TEST),t.stencilTest&&t.realDisable.call(e,e.STENCIL_TEST),t.realColorMask.call(e,!0,!0,!0,!0),t.realViewport.call(e,0,0,e.drawingBufferWidth,e.drawingBufferHeight),(t.ctxAttribs.alpha||o())&&(t.realClearColor.call(e,0,0,0,1),e.clear(e.COLOR_BUFFER_BIT)),e.useProgram(t.program),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,t.indexBuffer),e.bindBuffer(e.ARRAY_BUFFER,t.vertexBuffer),e.enableVertexAttribArray(t.attribs.position),e.enableVertexAttribArray(t.attribs.texCoord),e.vertexAttribPointer(t.attribs.position,2,e.FLOAT,!1,20,0),e.vertexAttribPointer(t.attribs.texCoord,3,e.FLOAT,!1,20,8),e.activeTexture(e.TEXTURE0),e.uniform1i(t.uniforms.diffuse,0),e.bindTexture(e.TEXTURE_2D,t.renderTarget),e.uniform4fv(t.uniforms.viewportOffsetScale,t.viewportOffsetScale),e.drawElements(e.TRIANGLES,t.indexCount,e.UNSIGNED_SHORT,0),t.cardboardUI&&t.cardboardUI.renderNoState(),t.realBindFramebuffer.call(t.gl,e.FRAMEBUFFER,t.framebuffer),t.ctxAttribs.preserveDrawingBuffer||(t.realClearColor.call(e,0,0,0,0),e.clear(e.COLOR_BUFFER_BIT)),t.dirtySubmitFrameBindings||t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.lastBoundFramebuffer),t.cullFace&&t.realEnable.call(e,e.CULL_FACE),t.depthTest&&t.realEnable.call(e,e.DEPTH_TEST),t.blend&&t.realEnable.call(e,e.BLEND),t.scissorTest&&t.realEnable.call(e,e.SCISSOR_TEST),t.stencilTest&&t.realEnable.call(e,e.STENCIL_TEST),t.realColorMask.apply(e,t.colorMask),t.realViewport.apply(e,t.viewport),!t.ctxAttribs.alpha&&t.ctxAttribs.preserveDrawingBuffer||t.realClearColor.apply(e,t.clearColor)}),o()){var r=e.canvas;r.width==t.bufferWidth&&r.height==t.bufferHeight||(t.bufferWidth=r.width,t.bufferHeight=r.height,t.onResize())}},T.prototype.updateDeviceInfo=function(e){var t=this.gl,i=this,r=[t.ARRAY_BUFFER_BINDING,t.ELEMENT_ARRAY_BUFFER_BINDING];_(t,r,function(t){var r=i.computeMeshVertices_(i.meshWidth,i.meshHeight,e);if(t.bindBuffer(t.ARRAY_BUFFER,i.vertexBuffer),t.bufferData(t.ARRAY_BUFFER,r,t.STATIC_DRAW),!i.indexCount){var s=i.computeMeshIndices_(i.meshWidth,i.meshHeight);t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,i.indexBuffer),t.bufferData(t.ELEMENT_ARRAY_BUFFER,s,t.STATIC_DRAW),i.indexCount=s.length}})},T.prototype.computeMeshVertices_=function(e,t,i){for(var r=new Float32Array(2*e*t*5),s=i.getLeftEyeVisibleTanAngles(),n=i.getLeftEyeNoLensTanAngles(),o=i.getLeftEyeVisibleScreenRect(n),l=0,A=0;A<2;A++){for(var h=0;hs-42&&r.clientXi.clientHeight-42?e(r):r.clientX<42&&r.clientY<42&&t(r)},i.addEventListener("click",this.listener,!1)},I.prototype.onResize=function(){var e=this.gl,t=this,i=[e.ARRAY_BUFFER_BINDING];_(e,i,function(e){var i=[],r=e.drawingBufferWidth/2,s=Math.max(screen.width,screen.height)*window.devicePixelRatio,n=e.drawingBufferWidth/s,a=n*window.devicePixelRatio,o=4*a/2,l=42*a,A=28*a/2,h=14*a;function c(e,t){var s=(90-e)*D,n=Math.cos(s),a=Math.sin(s);i.push(P*n*A+r,P*a*A+A),i.push(t*n*A+r,t*a*A+A)}i.push(r-o,l),i.push(r-o,e.drawingBufferHeight),i.push(r+o,l),i.push(r+o,e.drawingBufferHeight),t.gearOffset=i.length/2;for(var d=0;d<=6;d++){var u=60*d;c(u,1),c(u+12,1),c(u+20,.75),c(u+40,.75),c(u+48,1)}function p(t,r){i.push(h+t,e.drawingBufferHeight-h-r)}t.gearVertexCount=i.length/2-t.gearOffset,t.arrowOffset=i.length/2;var f=o/Math.sin(45*D);p(0,A),p(A,0),p(A+f,f),p(f,A+f),p(f,A-f),p(0,A),p(A,2*A),p(A+f,2*A-f),p(f,A-f),p(0,A),p(f,A-o),p(28*a,A-o),p(f,A+o),p(28*a,A+o),t.arrowVertexCount=i.length/2-t.arrowOffset,e.bindBuffer(e.ARRAY_BUFFER,t.vertexBuffer),e.bufferData(e.ARRAY_BUFFER,new Float32Array(i),e.STATIC_DRAW)})},I.prototype.render=function(){var e=this.gl,t=this,i=[e.CULL_FACE,e.DEPTH_TEST,e.BLEND,e.SCISSOR_TEST,e.STENCIL_TEST,e.COLOR_WRITEMASK,e.VIEWPORT,e.CURRENT_PROGRAM,e.ARRAY_BUFFER_BINDING];_(e,i,function(e){e.disable(e.CULL_FACE),e.disable(e.DEPTH_TEST),e.disable(e.BLEND),e.disable(e.SCISSOR_TEST),e.disable(e.STENCIL_TEST),e.colorMask(!0,!0,!0,!0),e.viewport(0,0,e.drawingBufferWidth,e.drawingBufferHeight),t.renderNoState()})},I.prototype.renderNoState=function(){var e,t,i,r,s,n,a,o,l,A,h=this.gl;h.useProgram(this.program),h.bindBuffer(h.ARRAY_BUFFER,this.vertexBuffer),h.enableVertexAttribArray(this.attribs.position),h.vertexAttribPointer(this.attribs.position,2,h.FLOAT,!1,8,0),h.uniform4f(this.uniforms.color,1,1,1,1),e=this.projMat,t=0,i=h.drawingBufferWidth,r=0,s=h.drawingBufferHeight,o=1/(t-i),l=1/(r-s),A=1/((n=.1)-(a=1024)),e[0]=-2*o,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=-2*l,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=2*A,e[11]=0,e[12]=(t+i)*o,e[13]=(s+r)*l,e[14]=(a+n)*A,e[15]=1,h.uniformMatrix4fv(this.uniforms.projectionMat,!1,this.projMat),h.drawArrays(h.TRIANGLE_STRIP,0,4),h.drawArrays(h.TRIANGLE_STRIP,this.gearOffset,this.gearVertexCount),h.drawArrays(h.TRIANGLE_STRIP,this.arrowOffset,this.arrowVertexCount)},L.prototype.distortInverse=function(e){for(var t=0,i=1,r=e-this.distort(t);Math.abs(i-t)>1e-4;){var s=e-this.distort(i),n=i-s*((i-t)/(s-r));t=i,i=n,r=s}return i},L.prototype.distort=function(e){for(var t=e*e,i=0,r=0;r=1)return this.w=n,this.x=i,this.y=r,this.z=s,this;var o=Math.acos(a),l=Math.sqrt(1-a*a);if(Math.abs(l)<.001)return this.w=.5*(n+this.w),this.x=.5*(i+this.x),this.y=.5*(r+this.y),this.z=.5*(s+this.z),this;var A=Math.sin((1-t)*o)/l,h=Math.sin(t*o)/l;return this.w=n*A+this.w*h,this.x=i*A+this.x*h,this.y=r*A+this.y*h,this.z=s*A+this.z*h,this},setFromUnitVectors:function(e,t){return void 0===G&&(G=new Q),(k=e.dot(t)+1)<1e-6?(k=0,Math.abs(e.x)>Math.abs(e.z)?G.set(-e.y,e.x,0):G.set(0,-e.z,e.y)):G.crossVectors(e,t),this.x=G.x,this.y=G.y,this.z=G.z,this.w=k,this.normalize(),this}};var U=new V({widthMeters:.11,heightMeters:.062,bevelMeters:.004}),H=new V({widthMeters:.1038,heightMeters:.0584,bevelMeters:.004}),X={CardboardV1:new j({id:"CardboardV1",label:"Cardboard I/O 2014",fov:40,interLensDistance:.06,baselineLensDistance:.035,screenLensDistance:.042,distortionCoefficients:[.441,.156],inverseCoefficients:[-.4410035,.42756155,-.4804439,.5460139,-.58821183,.5733938,-.48303202,.33299083,-.17573841,.0651772,-.01488963,.001559834]}),CardboardV2:new j({id:"CardboardV2",label:"Cardboard I/O 2015",fov:60,interLensDistance:.064,baselineLensDistance:.035,screenLensDistance:.039,distortionCoefficients:[.34,.55],inverseCoefficients:[-.33836704,-.18162185,.862655,-1.2462051,1.0560602,-.58208317,.21609078,-.05444823,.009177956,-.0009904169,6183535e-11,-16981803e-13]})};function W(e,t){this.viewer=X.CardboardV2,this.updateDeviceParams(e),this.distortion=new L(this.viewer.distortionCoefficients);for(var i=0;i=200&&i.status<=299?(r.dpdb=JSON.parse(i.response),r.recalculateDeviceParams_()):console.error("Error loading online DPDB!")}),i.send()}}function Z(e){this.xdpi=e.xdpi,this.ydpi=e.ydpi,this.bevelMm=e.bevelMm}function J(e,t){this.set(e,t)}function K(e,t){this.kFilter=e,this.isDebug=t,this.currentAccelMeasurement=new J,this.currentGyroMeasurement=new J,this.previousGyroMeasurement=new J,o()?this.filterQ=new z(-1,0,0,1):this.filterQ=new z(1,0,0,1),this.previousFilterQ=new z,this.previousFilterQ.copy(this.filterQ),this.accelQ=new z,this.isOrientationInitialized=!1,this.estimatedGravity=new Q,this.measuredGravity=new Q,this.gyroIntegralQ=new z}function $(e,t){this.predictionTimeS=e,this.isDebug=t,this.previousQ=new z,this.previousTimestampS=null,this.deltaQ=new z,this.outQ=new z}function ee(e,t,i,r){this.yawOnly=i,this.accelerometer=new Q,this.gyroscope=new Q,this.filter=new K(e,r),this.posePredictor=new $(t,r),this.isFirefoxAndroid=A(),this.isIOS=o();var s=h();this.isDeviceMotionInRadians=!this.isIOS&&s&&s<66,this.isWithoutDeviceMotion=c(),this.filterToWorldQ=new z,o()?this.filterToWorldQ.setFromAxisAngle(new Q(1,0,0),Math.PI/2):this.filterToWorldQ.setFromAxisAngle(new Q(1,0,0),-Math.PI/2),this.inverseWorldToScreenQ=new z,this.worldToScreenQ=new z,this.originalPoseAdjustQ=new z,this.originalPoseAdjustQ.setFromAxisAngle(new Q(0,0,1),-window.orientation*Math.PI/180),this.setScreenTransform_(),u()&&this.filterToWorldQ.multiply(this.inverseWorldToScreenQ),this.resetQ=new z,this.orientationOut_=new Float32Array(4),this.start()}Y.prototype.getDeviceParams=function(){return this.deviceParams},Y.prototype.recalculateDeviceParams_=function(){var e=this.calcDeviceParams_();e?(this.deviceParams=e,this.onDeviceParamsUpdated&&this.onDeviceParamsUpdated(this.deviceParams)):console.error("Failed to recalculate device parameters.")},Y.prototype.calcDeviceParams_=function(){var e=this.dpdb;if(!e)return console.error("DPDB not available."),null;if(1!=e.format)return console.error("DPDB has unexpected format version."),null;if(!e.devices||!e.devices.length)return console.error("DPDB does not have a devices section."),null;var t=navigator.userAgent||navigator.vendor||window.opera,i=p(),r=f();if(!e.devices)return console.error("DPDB has no devices section."),null;for(var s=0;s1)&&this.run_(),this.previousGyroMeasurement.copy(this.currentGyroMeasurement)},K.prototype.run_=function(){if(!this.isOrientationInitialized)return this.accelQ=this.accelToQuaternion_(this.currentAccelMeasurement.sample),this.previousFilterQ.copy(this.accelQ),void(this.isOrientationInitialized=!0);var e=this.currentGyroMeasurement.timestampS-this.previousGyroMeasurement.timestampS,t=this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample,e);this.gyroIntegralQ.multiply(t),this.filterQ.copy(this.previousFilterQ),this.filterQ.multiply(t);var i=new z;i.copy(this.filterQ),i.inverse(),this.estimatedGravity.set(0,0,-1),this.estimatedGravity.applyQuaternion(i),this.estimatedGravity.normalize(),this.measuredGravity.copy(this.currentAccelMeasurement.sample),this.measuredGravity.normalize();var r,s=new z;s.setFromUnitVectors(this.estimatedGravity,this.measuredGravity),s.inverse(),this.isDebug&&console.log("Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)",N*((r=s).w>1?(console.warn("getQuaternionAngle: w > 1"),0):2*Math.acos(r.w)),this.estimatedGravity.x.toFixed(1),this.estimatedGravity.y.toFixed(1),this.estimatedGravity.z.toFixed(1),this.measuredGravity.x.toFixed(1),this.measuredGravity.y.toFixed(1),this.measuredGravity.z.toFixed(1));var n=new z;n.copy(this.filterQ),n.multiply(s),this.filterQ.slerp(n,1-this.kFilter),this.previousFilterQ.copy(this.filterQ)},K.prototype.getOrientation=function(){return this.filterQ},K.prototype.accelToQuaternion_=function(e){var t=new Q;t.copy(e),t.normalize();var i=new z;return i.setFromUnitVectors(new Q(0,0,-1),t),i.inverse(),i},K.prototype.gyroToQuaternionDelta_=function(e,t){var i=new z,r=new Q;return r.copy(e),r.normalize(),i.setFromAxisAngle(r,e.length()*t),i},$.prototype.getPrediction=function(e,t,i){if(!this.previousTimestampS)return this.previousQ.copy(e),this.previousTimestampS=i,e;var r=new Q;r.copy(t),r.normalize();var s=t.length();if(s<20*O)return this.isDebug&&console.log("Moving slowly, at %s deg/s: no prediction",(N*s).toFixed(1)),this.outQ.copy(e),this.previousQ.copy(e),this.outQ;var n=s*this.predictionTimeS;return this.deltaQ.setFromAxisAngle(r,n),this.outQ.copy(this.previousQ),this.outQ.multiply(this.deltaQ),this.previousQ.copy(e),this.previousTimestampS=i,this.outQ},ee.prototype.getPosition=function(){return null},ee.prototype.getOrientation=function(){var e=void 0;if(this.isWithoutDeviceMotion&&this._deviceOrientationQ){this.deviceOrientationFixQ=this.deviceOrientationFixQ||(r=(new z).setFromAxisAngle(new Q(0,0,-1),0),s=new z,-90===window.orientation?s.setFromAxisAngle(new Q(0,1,0),Math.PI/-2):s.setFromAxisAngle(new Q(0,1,0),Math.PI/2),r.multiply(s)),this.deviceOrientationFilterToWorldQ=this.deviceOrientationFilterToWorldQ||((i=new z).setFromAxisAngle(new Q(1,0,0),-Math.PI/2),i),e=this._deviceOrientationQ;var t=new z;return t.copy(e),t.multiply(this.deviceOrientationFilterToWorldQ),t.multiply(this.resetQ),t.multiply(this.worldToScreenQ),t.multiplyQuaternions(this.deviceOrientationFixQ,t),this.yawOnly&&(t.x=0,t.z=0,t.normalize()),this.orientationOut_[0]=t.x,this.orientationOut_[1]=t.y,this.orientationOut_[2]=t.z,this.orientationOut_[3]=t.w,this.orientationOut_}var i,r,s,n=this.filter.getOrientation();e=this.posePredictor.getPrediction(n,this.gyroscope,this.previousTimestampS);var t=new z;return t.copy(this.filterToWorldQ),t.multiply(this.resetQ),t.multiply(e),t.multiply(this.worldToScreenQ),this.yawOnly&&(t.x=0,t.z=0,t.normalize()),this.orientationOut_[0]=t.x,this.orientationOut_[1]=t.y,this.orientationOut_[2]=t.z,this.orientationOut_[3]=t.w,this.orientationOut_},ee.prototype.resetPose=function(){this.resetQ.copy(this.filter.getOrientation()),this.resetQ.x=0,this.resetQ.y=0,this.resetQ.z*=-1,this.resetQ.normalize(),u()&&this.resetQ.multiply(this.inverseWorldToScreenQ),this.resetQ.multiply(this.originalPoseAdjustQ)},ee.prototype.onDeviceOrientation_=function(e){this._deviceOrientationQ=this._deviceOrientationQ||new z;var t=e.alpha,i=e.beta,r=e.gamma;t=(t||0)*Math.PI/180,i=(i||0)*Math.PI/180,r=(r||0)*Math.PI/180,this._deviceOrientationQ.setFromEulerYXZ(i,t,-r)},ee.prototype.onDeviceMotion_=function(e){this.updateDeviceMotion_(e)},ee.prototype.updateDeviceMotion_=function(e){var t=e.accelerationIncludingGravity,i=e.rotationRate,r=e.timeStamp/1e3,s=r-this.previousTimestampS;return s<0?(M("fusion-pose-sensor:invalid:non-monotonic","Invalid timestamps detected: non-monotonic timestamp from devicemotion"),void(this.previousTimestampS=r)):s<=.001||s>1?(M("fusion-pose-sensor:invalid:outside-threshold","Invalid timestamps detected: Timestamp from devicemotion outside expected range."),void(this.previousTimestampS=r)):(this.accelerometer.set(-t.x,-t.y,-t.z),d()?this.gyroscope.set(-i.beta,i.alpha,i.gamma):this.gyroscope.set(i.alpha,i.beta,i.gamma),this.isDeviceMotionInRadians||this.gyroscope.multiplyScalar(Math.PI/180),this.filter.addAccelMeasurement(this.accelerometer,r),this.filter.addGyroMeasurement(this.gyroscope,r),void(this.previousTimestampS=r))},ee.prototype.onOrientationChange_=function(e){this.setScreenTransform_()},ee.prototype.onMessage_=function(e){var t=e.data;if(t&&t.type){var i=t.type.toLowerCase();"devicemotion"===i&&this.updateDeviceMotion_(t.deviceMotionEvent)}},ee.prototype.setScreenTransform_=function(){switch(this.worldToScreenQ.set(0,0,0,1),window.orientation){case 0:break;case 90:this.worldToScreenQ.setFromAxisAngle(new Q(0,0,1),-Math.PI/2);break;case-90:this.worldToScreenQ.setFromAxisAngle(new Q(0,0,1),Math.PI/2)}this.inverseWorldToScreenQ.copy(this.worldToScreenQ),this.inverseWorldToScreenQ.inverse()},ee.prototype.start=function(){var e,t,i;this.onDeviceMotionCallback_=this.onDeviceMotion_.bind(this),this.onOrientationChangeCallback_=this.onOrientationChange_.bind(this),this.onMessageCallback_=this.onMessage_.bind(this),this.onDeviceOrientationCallback_=this.onDeviceOrientation_.bind(this),o()&&(e=window.self!==window.top,t=S(document.referrer),i=S(window.location.href),e&&t!==i)&&window.addEventListener("message",this.onMessageCallback_),window.addEventListener("orientationchange",this.onOrientationChangeCallback_),this.isWithoutDeviceMotion?window.addEventListener("deviceorientation",this.onDeviceOrientationCallback_):window.addEventListener("devicemotion",this.onDeviceMotionCallback_)},ee.prototype.stop=function(){window.removeEventListener("devicemotion",this.onDeviceMotionCallback_),window.removeEventListener("deviceorientation",this.onDeviceOrientationCallback_),window.removeEventListener("orientationchange",this.onOrientationChangeCallback_),window.removeEventListener("message",this.onMessageCallback_)};var te=new Q(1,0,0),ie=new Q(0,0,1),re=new z;re.setFromAxisAngle(te,-Math.PI/2),re.multiply((new z).setFromAxisAngle(ie,Math.PI/2));var se=function(){function e(t){r(this,e),this.config=t,this.sensor=null,this.fusionSensor=null,this._out=new Float32Array(4),this.api=null,this.errors=[],this._sensorQ=new z,this._outQ=new z,this._onSensorRead=this._onSensorRead.bind(this),this._onSensorError=this._onSensorError.bind(this),this.init()}return s(e,[{key:"init",value:function(){var e=null;try{(e=new RelativeOrientationSensor({frequency:60,referenceFrame:"screen"})).addEventListener("error",this._onSensorError)}catch(e){this.errors.push(e),"SecurityError"===e.name?(console.error("Cannot construct sensors due to the Feature Policy"),console.warn('Attempting to fall back using "devicemotion"; however this will fail in the future without correct permissions.'),this.useDeviceMotion()):"ReferenceError"===e.name?this.useDeviceMotion():console.error(e)}e&&(this.api="sensor",this.sensor=e,this.sensor.addEventListener("reading",this._onSensorRead),this.sensor.start())}},{key:"useDeviceMotion",value:function(){this.api="devicemotion",this.fusionSensor=new ee(this.config.K_FILTER,this.config.PREDICTION_TIME_S,this.config.YAW_ONLY,this.config.DEBUG),this.sensor&&(this.sensor.removeEventListener("reading",this._onSensorRead),this.sensor.removeEventListener("error",this._onSensorError),this.sensor=null)}},{key:"getOrientation",value:function(){if(this.fusionSensor)return this.fusionSensor.getOrientation();if(!this.sensor||!this.sensor.quaternion)return this._out[0]=this._out[1]=this._out[2]=0,this._out[3]=1,this._out;var e=this.sensor.quaternion;this._sensorQ.set(e[0],e[1],e[2],e[3]);var t=this._outQ;return t.copy(re),t.multiply(this._sensorQ),this.config.YAW_ONLY&&(t.x=t.z=0,t.normalize()),this._out[0]=t.x,this._out[1]=t.y,this._out[2]=t.z,this._out[3]=t.w,this._out}},{key:"_onSensorError",value:function(e){this.errors.push(e.error),"NotAllowedError"===e.error.name?console.error("Permission to access sensor was denied"):"NotReadableError"===e.error.name?console.error("Sensor could not be read"):console.error(e.error),this.useDeviceMotion()}},{key:"_onSensorRead",value:function(){}}]),e}();function ne(){this.loadIcon_();var e=document.createElement("div"),t=e.style;t.position="fixed",t.top=0,t.right=0,t.bottom=0,t.left=0,t.backgroundColor="gray",t.fontFamily="sans-serif",t.zIndex=1e6;var i=document.createElement("img");i.src=this.icon;var t=i.style;t.marginLeft="25%",t.marginTop="25%",t.width="50%",e.appendChild(i);var r=document.createElement("div"),t=r.style;t.textAlign="center",t.fontSize="16px",t.lineHeight="24px",t.margin="24px 25%",t.width="50%",r.innerHTML="Place your phone into your Cardboard viewer.",e.appendChild(r);var s=document.createElement("div"),t=s.style;t.backgroundColor="#CFD8DC",t.position="fixed",t.bottom=0,t.width="100%",t.height="48px",t.padding="14px 24px",t.boxSizing="border-box",t.color="#656A6B",e.appendChild(s);var n=document.createElement("div");n.style.float="left",n.innerHTML="No Cardboard viewer?";var a=document.createElement("a");a.href="https://www.google.com/get/cardboard/get-cardboard/",a.innerHTML="get one",a.target="_blank";var t=a.style;t.float="right",t.fontWeight=600,t.textTransform="uppercase",t.borderLeft="1px solid gray",t.paddingLeft="24px",t.textDecoration="none",t.color="#656A6B",s.appendChild(n),s.appendChild(a),this.overlay=e,this.text=r,this.hide()}ne.prototype.show=function(e){e||this.overlay.parentElement?e&&(this.overlay.parentElement&&this.overlay.parentElement!=e&&this.overlay.parentElement.removeChild(this.overlay),e.appendChild(this.overlay)):document.body.appendChild(this.overlay),this.overlay.style.display="block";var t=this.overlay.querySelector("img"),i=t.style;u()?(i.width="20%",i.marginLeft="40%",i.marginTop="3%"):(i.width="50%",i.marginLeft="25%",i.marginTop="25%")},ne.prototype.hide=function(){this.overlay.style.display="none"},ne.prototype.showTemporarily=function(e,t){this.show(t),this.timer=setTimeout(this.hide.bind(this),e)},ne.prototype.disableShowTemporarily=function(){clearTimeout(this.timer)},ne.prototype.update=function(){this.disableShowTemporarily(),!u()&&w()?this.show():this.hide()},ne.prototype.loadIcon_=function(){this.icon="data:image/svg+xml,"+encodeURIComponent("")};var ae="CardboardV1",oe="WEBVR_CARDBOARD_VIEWER";function le(e){try{this.selectedKey=localStorage.getItem(oe)}catch(e){console.error("Failed to load viewer profile: %s",e)}this.selectedKey||(this.selectedKey=e||ae),this.dialog=this.createDialog_(W.Viewers),this.root=null,this.onChangeCallbacks_=[]}le.prototype.show=function(e){this.root=e,e.appendChild(this.dialog);var t=this.dialog.querySelector("#"+this.selectedKey);t.checked=!0,this.dialog.style.display="block"},le.prototype.hide=function(){this.root&&this.root.contains(this.dialog)&&this.root.removeChild(this.dialog),this.dialog.style.display="none"},le.prototype.getCurrentViewer=function(){return W.Viewers[this.selectedKey]},le.prototype.getSelectedKey_=function(){var e=this.dialog.querySelector("input[name=field]:checked");return e?e.id:null},le.prototype.onChange=function(e){this.onChangeCallbacks_.push(e)},le.prototype.fireOnChange_=function(e){for(var t=0;t.5&&(this.noSleepVideo.currentTime=Math.random())}.bind(this)))}return r(e,[{key:"enable",value:function(){n?(this.disable(),this.noSleepTimer=window.setInterval(function(){window.location.href="/",window.setTimeout(window.stop,0)},15e3)):this.noSleepVideo.play()}},{key:"disable",value:function(){n?this.noSleepTimer&&(window.clearInterval(this.noSleepTimer),this.noSleepTimer=null):this.noSleepVideo.pause()}}]),e}();e.exports=a},function(e,t,i){e.exports="data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA="}])},e.exports=i()}(he={exports:{}},he.exports),(Ae=he.exports)&&Ae.__esModule&&Object.prototype.hasOwnProperty.call(Ae,"default")?Ae.default:Ae),de=1e3,ue=[0,0,.5,1],pe=[.5,0,.5,1],fe=window.requestAnimationFrame,me=window.cancelAnimationFrame;function ge(e){Object.defineProperties(this,{hasPosition:{writable:!1,enumerable:!0,value:e.hasPosition},hasExternalDisplay:{writable:!1,enumerable:!0,value:e.hasExternalDisplay},canPresent:{writable:!1,enumerable:!0,value:e.canPresent},maxLayers:{writable:!1,enumerable:!0,value:e.maxLayers},hasOrientation:{enumerable:!0,get:function(){return x("VRDisplayCapabilities.prototype.hasOrientation","VRDisplay.prototype.getFrameData"),e.hasOrientation}}})}function ve(e){var t=!("wakelock"in(e=e||{}))||e.wakelock;this.isPolyfilled=!0,this.displayId=de++,this.displayName="",this.depthNear=.01,this.depthFar=1e4,this.isPresenting=!1,Object.defineProperty(this,"isConnected",{get:function(){return x("VRDisplay.prototype.isConnected","VRDisplayCapabilities.prototype.hasExternalDisplay"),!1}}),this.capabilities=new ge({hasPosition:!1,hasOrientation:!1,hasExternalDisplay:!1,canPresent:!1,maxLayers:1}),this.stageParameters=null,this.waitingForPresent_=!1,this.layer_=null,this.originalParent_=null,this.fullscreenElement_=null,this.fullscreenWrapper_=null,this.fullscreenElementCachedStyle_=null,this.fullscreenEventTarget_=null,this.fullscreenChangeHandler_=null,this.fullscreenErrorHandler_=null,t&&w()&&(this.wakelock_=new ce)}ve.prototype.getFrameData=function(e){return E(e,this._getPose(),this)},ve.prototype.getPose=function(){return x("VRDisplay.prototype.getPose","VRDisplay.prototype.getFrameData"),this._getPose()},ve.prototype.resetPose=function(){return x("VRDisplay.prototype.resetPose"),this._resetPose()},ve.prototype.getImmediatePose=function(){return x("VRDisplay.prototype.getImmediatePose","VRDisplay.prototype.getFrameData"),this._getPose()},ve.prototype.requestAnimationFrame=function(e){return fe(e)},ve.prototype.cancelAnimationFrame=function(e){return me(e)},ve.prototype.wrapForFullscreen=function(e){if(o())return e;if(!this.fullscreenWrapper_){this.fullscreenWrapper_=document.createElement("div");var t=["height: "+Math.min(screen.height,screen.width)+"px !important","top: 0 !important","left: 0 !important","right: 0 !important","border: 0","margin: 0","padding: 0","z-index: 999999 !important","position: fixed"];this.fullscreenWrapper_.setAttribute("style",t.join("; ")+";"),this.fullscreenWrapper_.classList.add("webvr-polyfill-fullscreen-wrapper")}if(this.fullscreenElement_==e)return this.fullscreenWrapper_;if(this.fullscreenElement_&&(this.originalParent_?this.originalParent_.appendChild(this.fullscreenElement_):this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_)),this.fullscreenElement_=e,this.originalParent_=e.parentElement,this.originalParent_||document.body.appendChild(e),!this.fullscreenWrapper_.parentElement){var i=this.fullscreenElement_.parentElement;i.insertBefore(this.fullscreenWrapper_,this.fullscreenElement_),i.removeChild(this.fullscreenElement_)}this.fullscreenWrapper_.insertBefore(this.fullscreenElement_,this.fullscreenWrapper_.firstChild),this.fullscreenElementCachedStyle_=this.fullscreenElement_.getAttribute("style");var r=this;return function(){if(r.fullscreenElement_){var e=["position: absolute","top: 0","left: 0","width: "+Math.max(screen.width,screen.height)+"px","height: "+Math.min(screen.height,screen.width)+"px","border: 0","margin: 0","padding: 0"];r.fullscreenElement_.setAttribute("style",e.join("; ")+";")}}(),this.fullscreenWrapper_},ve.prototype.removeFullscreenWrapper=function(){if(this.fullscreenElement_){var e=this.fullscreenElement_;this.fullscreenElementCachedStyle_?e.setAttribute("style",this.fullscreenElementCachedStyle_):e.removeAttribute("style"),this.fullscreenElement_=null,this.fullscreenElementCachedStyle_=null;var t=this.fullscreenWrapper_.parentElement;return this.fullscreenWrapper_.removeChild(e),this.originalParent_===t?t.insertBefore(e,this.fullscreenWrapper_):this.originalParent_&&this.originalParent_.appendChild(e),t.removeChild(this.fullscreenWrapper_),e}},ve.prototype.requestPresent=function(e){var t=this.isPresenting,i=this;return e instanceof Array||(x("VRDisplay.prototype.requestPresent with non-array argument","an array of VRLayers as the first argument"),e=[e]),new Promise(function(r,s){if(i.capabilities.canPresent)if(0==e.length||e.length>i.capabilities.maxLayers)s(new Error("Invalid number of layers."));else{var n=e[0];if(n.source){var a=n.leftBounds||ue,A=n.rightBounds||pe;if(t){var h=i.layer_;h.source!==n.source&&(h.source=n.source);for(var c=0;c<4;c++)h.leftBounds[c]=a[c],h.rightBounds[c]=A[c];return i.wrapForFullscreen(i.layer_.source),i.updatePresent_(),void r()}if(i.layer_={predistorted:n.predistorted,source:n.source,leftBounds:a.slice(0),rightBounds:A.slice(0)},i.waitingForPresent_=!1,i.layer_&&i.layer_.source){var d=i.wrapForFullscreen(i.layer_.source);i.addFullscreenListeners_(d,function(){var e=document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement;i.isPresenting=d===e,i.isPresenting?(screen.orientation&&screen.orientation.lock&&screen.orientation.lock("landscape-primary").catch(function(e){console.error("screen.orientation.lock() failed due to",e.message)}),i.waitingForPresent_=!1,i.beginPresent_(),r()):(screen.orientation&&screen.orientation.unlock&&screen.orientation.unlock(),i.removeFullscreenWrapper(),i.disableWakeLock(),i.endPresent_(),i.removeFullscreenListeners_()),i.fireVRDisplayPresentChange_()},function(){i.waitingForPresent_&&(i.removeFullscreenWrapper(),i.removeFullscreenListeners_(),i.disableWakeLock(),i.waitingForPresent_=!1,i.isPresenting=!1,s(new Error("Unable to present.")))}),function(e){if(l())return!1;if(e.requestFullscreen)e.requestFullscreen();else if(e.webkitRequestFullscreen)e.webkitRequestFullscreen();else if(e.mozRequestFullScreen)e.mozRequestFullScreen();else{if(!e.msRequestFullscreen)return!1;e.msRequestFullscreen()}return!0}(d)?(i.enableWakeLock(),i.waitingForPresent_=!0):(o()||l())&&(i.enableWakeLock(),i.isPresenting=!0,i.beginPresent_(),i.fireVRDisplayPresentChange_(),r())}i.waitingForPresent_||o()||(m(),s(new Error("Unable to present.")))}else r()}else s(new Error("VRDisplay is not capable of presenting."))})},ve.prototype.exitPresent=function(){var e=this.isPresenting,t=this;return this.isPresenting=!1,this.layer_=null,this.disableWakeLock(),new Promise(function(i,r){e?(!m()&&o()&&(t.endPresent_(),t.fireVRDisplayPresentChange_()),l()&&(t.removeFullscreenWrapper(),t.removeFullscreenListeners_(),t.endPresent_(),t.fireVRDisplayPresentChange_()),i()):r(new Error("Was not presenting to VRDisplay."))})},ve.prototype.getLayers=function(){return this.layer_?[this.layer_]:[]},ve.prototype.fireVRDisplayPresentChange_=function(){var e=new CustomEvent("vrdisplaypresentchange",{detail:{display:this}});window.dispatchEvent(e)},ve.prototype.fireVRDisplayConnect_=function(){var e=new CustomEvent("vrdisplayconnect",{detail:{display:this}});window.dispatchEvent(e)},ve.prototype.addFullscreenListeners_=function(e,t,i){this.removeFullscreenListeners_(),this.fullscreenEventTarget_=e,this.fullscreenChangeHandler_=t,this.fullscreenErrorHandler_=i,t&&(document.fullscreenEnabled?e.addEventListener("fullscreenchange",t,!1):document.webkitFullscreenEnabled?e.addEventListener("webkitfullscreenchange",t,!1):document.mozFullScreenEnabled?document.addEventListener("mozfullscreenchange",t,!1):document.msFullscreenEnabled&&e.addEventListener("msfullscreenchange",t,!1)),i&&(document.fullscreenEnabled?e.addEventListener("fullscreenerror",i,!1):document.webkitFullscreenEnabled?e.addEventListener("webkitfullscreenerror",i,!1):document.mozFullScreenEnabled?document.addEventListener("mozfullscreenerror",i,!1):document.msFullscreenEnabled&&e.addEventListener("msfullscreenerror",i,!1))},ve.prototype.removeFullscreenListeners_=function(){if(this.fullscreenEventTarget_){var e=this.fullscreenEventTarget_;if(this.fullscreenChangeHandler_){var t=this.fullscreenChangeHandler_;e.removeEventListener("fullscreenchange",t,!1),e.removeEventListener("webkitfullscreenchange",t,!1),document.removeEventListener("mozfullscreenchange",t,!1),e.removeEventListener("msfullscreenchange",t,!1)}if(this.fullscreenErrorHandler_){var i=this.fullscreenErrorHandler_;e.removeEventListener("fullscreenerror",i,!1),e.removeEventListener("webkitfullscreenerror",i,!1),document.removeEventListener("mozfullscreenerror",i,!1),e.removeEventListener("msfullscreenerror",i,!1)}this.fullscreenEventTarget_=null,this.fullscreenChangeHandler_=null,this.fullscreenErrorHandler_=null}},ve.prototype.enableWakeLock=function(){this.wakelock_&&this.wakelock_.enable()},ve.prototype.disableWakeLock=function(){this.wakelock_&&this.wakelock_.disable()},ve.prototype.beginPresent_=function(){},ve.prototype.endPresent_=function(){},ve.prototype.submitFrame=function(e){},ve.prototype.getEyeParameters=function(e){return null};var we={ADDITIONAL_VIEWERS:[],DEFAULT_VIEWER:"",MOBILE_WAKE_LOCK:!0,DEBUG:!1,DPDB_URL:"https://dpdb.webvr.rocks/dpdb.json",K_FILTER:.98,PREDICTION_TIME_S:.04,CARDBOARD_UI_DISABLED:!1,ROTATE_INSTRUCTIONS_DISABLED:!1,YAW_ONLY:!1,BUFFER_SCALE:.5,DIRTY_SUBMIT_FRAME_BINDINGS:!1},ye={LEFT:"left",RIGHT:"right"};function be(e){var t=y({},we);e=y(t,e||{}),ve.call(this,{wakelock:e.MOBILE_WAKE_LOCK}),this.config=e,this.displayName="Cardboard VRDisplay",this.capabilities=new ge({hasPosition:!1,hasOrientation:!0,hasExternalDisplay:!1,canPresent:!0,maxLayers:1}),this.stageParameters=null,this.bufferScale_=this.config.BUFFER_SCALE,this.poseSensor_=new se(this.config),this.distorter_=null,this.cardboardUI_=null,this.dpdb_=new Y(this.config.DPDB_URL,this.onDeviceParamsUpdated_.bind(this)),this.deviceInfo_=new W(this.dpdb_.getDeviceParams(),e.ADDITIONAL_VIEWERS),this.viewerSelector_=new le(e.DEFAULT_VIEWER),this.viewerSelector_.onChange(this.onViewerChanged_.bind(this)),this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer()),this.config.ROTATE_INSTRUCTIONS_DISABLED||(this.rotateInstructions_=new ne),o()&&window.addEventListener("resize",this.onResize_.bind(this))}return be.prototype=Object.create(ve.prototype),be.prototype._getPose=function(){return{position:null,orientation:this.poseSensor_.getOrientation(),linearVelocity:null,linearAcceleration:null,angularVelocity:null,angularAcceleration:null}},be.prototype._resetPose=function(){this.poseSensor_.resetPose&&this.poseSensor_.resetPose()},be.prototype._getFieldOfView=function(e){var t;if(e==ye.LEFT)t=this.deviceInfo_.getFieldOfViewLeftEye();else{if(e!=ye.RIGHT)return console.error("Invalid eye provided: %s",e),null;t=this.deviceInfo_.getFieldOfViewRightEye()}return t},be.prototype._getEyeOffset=function(e){var t;if(e==ye.LEFT)t=[.5*-this.deviceInfo_.viewer.interLensDistance,0,0];else{if(e!=ye.RIGHT)return console.error("Invalid eye provided: %s",e),null;t=[.5*this.deviceInfo_.viewer.interLensDistance,0,0]}return t},be.prototype.getEyeParameters=function(e){var t=this._getEyeOffset(e),i=this._getFieldOfView(e),r={offset:t,renderWidth:.5*this.deviceInfo_.device.width*this.bufferScale_,renderHeight:this.deviceInfo_.device.height*this.bufferScale_};return Object.defineProperty(r,"fieldOfView",{enumerable:!0,get:function(){return x("VRFieldOfView","VRFrameData's projection matrices"),i}}),r},be.prototype.onDeviceParamsUpdated_=function(e){this.config.DEBUG&&console.log("DPDB reported that device params were updated."),this.deviceInfo_.updateDeviceParams(e),this.distorter_&&this.distorter_.updateDeviceInfo(this.deviceInfo_)},be.prototype.updateBounds_=function(){this.layer_&&this.distorter_&&(this.layer_.leftBounds||this.layer_.rightBounds)&&this.distorter_.setTextureBounds(this.layer_.leftBounds,this.layer_.rightBounds)},be.prototype.beginPresent_=function(){var e=this.layer_.source.getContext("webgl");e||(e=this.layer_.source.getContext("experimental-webgl")),e||(e=this.layer_.source.getContext("webgl2")),e&&(this.layer_.predistorted?this.config.CARDBOARD_UI_DISABLED||(e.canvas.width=p()*this.bufferScale_,e.canvas.height=f()*this.bufferScale_,this.cardboardUI_=new I(e)):(this.config.CARDBOARD_UI_DISABLED||(this.cardboardUI_=new I(e)),this.distorter_=new T(e,this.cardboardUI_,this.config.BUFFER_SCALE,this.config.DIRTY_SUBMIT_FRAME_BINDINGS),this.distorter_.updateDeviceInfo(this.deviceInfo_)),this.cardboardUI_&&this.cardboardUI_.listen(function(e){this.viewerSelector_.show(this.layer_.source.parentElement),e.stopPropagation(),e.preventDefault()}.bind(this),function(e){this.exitPresent(),e.stopPropagation(),e.preventDefault()}.bind(this)),this.rotateInstructions_&&(u()&&w()?this.rotateInstructions_.showTemporarily(3e3,this.layer_.source.parentElement):this.rotateInstructions_.update()),this.orientationHandler=this.onOrientationChange_.bind(this),window.addEventListener("orientationchange",this.orientationHandler),this.vrdisplaypresentchangeHandler=this.updateBounds_.bind(this),window.addEventListener("vrdisplaypresentchange",this.vrdisplaypresentchangeHandler),this.fireVRDisplayDeviceParamsChange_())},be.prototype.endPresent_=function(){this.distorter_&&(this.distorter_.destroy(),this.distorter_=null),this.cardboardUI_&&(this.cardboardUI_.destroy(),this.cardboardUI_=null),this.rotateInstructions_&&this.rotateInstructions_.hide(),this.viewerSelector_.hide(),window.removeEventListener("orientationchange",this.orientationHandler),window.removeEventListener("vrdisplaypresentchange",this.vrdisplaypresentchangeHandler)},be.prototype.updatePresent_=function(){this.endPresent_(),this.beginPresent_()},be.prototype.submitFrame=function(e){if(this.distorter_)this.updateBounds_(),this.distorter_.submitFrame();else if(this.cardboardUI_&&this.layer_){var t=this.layer_.source.getContext("webgl").canvas;t.width==this.lastWidth&&t.height==this.lastHeight||this.cardboardUI_.onResize(),this.lastWidth=t.width,this.lastHeight=t.height,this.cardboardUI_.render()}},be.prototype.onOrientationChange_=function(e){this.viewerSelector_.hide(),this.rotateInstructions_&&this.rotateInstructions_.update(),this.onResize_()},be.prototype.onResize_=function(e){if(this.layer_){var t=this.layer_.source.getContext("webgl");t.canvas.setAttribute("style",["position: absolute","top: 0","left: 0","width: 100vw","height: 100vh","border: 0","margin: 0","padding: 0px","box-sizing: content-box"].join("; ")+";"),b(t.canvas)}},be.prototype.onViewerChanged_=function(e){this.deviceInfo_.setViewer(e),this.distorter_&&this.distorter_.updateDeviceInfo(this.deviceInfo_),this.fireVRDisplayDeviceParamsChange_()},be.prototype.fireVRDisplayDeviceParamsChange_=function(){var e=new CustomEvent("vrdisplaydeviceparamschange",{detail:{vrdisplay:this,deviceInfo:this.deviceInfo_}});window.dispatchEvent(e)},be.VRFrameData=function(){this.leftProjectionMatrix=new Float32Array(16),this.leftViewMatrix=new Float32Array(16),this.rightProjectionMatrix=new Float32Array(16),this.rightViewMatrix=new Float32Array(16),this.pose=null},be.VRDisplay=ve,be}()}(De={exports:{}},De.exports),De.exports),Le=(Pe=Ie)&&Pe.__esModule&&Object.prototype.hasOwnProperty.call(Pe,"default")?Pe.default:Pe;class Oe extends i{constructor(e){super(),this.global=e,this.onWindowResize=this.onWindowResize.bind(this),this.global.window.addEventListener("resize",this.onWindowResize),this.environmentBlendMode="opaque"}onBaseLayerSet(e,t){throw new Error("Not implemented")}isSessionSupported(e){throw new Error("Not implemented")}isFeatureSupported(e){throw new Error("Not implemented")}async requestSession(e,t){throw new Error("Not implemented")}requestAnimationFrame(e){throw new Error("Not implemented")}onFrameStart(e){throw new Error("Not implemented")}onFrameEnd(e){throw new Error("Not implemented")}doesSessionSupportReferenceSpace(e,t){throw new Error("Not implemented")}requestStageBounds(){throw new Error("Not implemented")}async requestFrameOfReferenceTransform(e,t){}cancelAnimationFrame(e){throw new Error("Not implemented")}endSession(e){throw new Error("Not implemented")}getViewport(e,t,i,r){throw new Error("Not implemented")}getProjectionMatrix(e){throw new Error("Not implemented")}getBasePoseMatrix(){throw new Error("Not implemented")}getBaseViewMatrix(e){throw new Error("Not implemented")}getInputSources(){throw new Error("Not implemented")}getInputPose(e,t,i){throw new Error("Not implemented")}onWindowResize(){this.onWindowResize()}}let Ne={mapping:"xr-standard",profiles:["oculus-go","generic-trigger-touchpad"],buttons:{length:3,0:1,1:null,2:0},gripTransform:{orientation:[.11*Math.PI,0,0,1]}},Qe={mapping:"xr-standard",displayProfiles:{"Oculus Quest":["oculus-touch-v2","oculus-touch","generic-trigger-squeeze-thumbstick"]},profiles:["oculus-touch","generic-trigger-squeeze-thumbstick"],axes:{length:4,0:null,1:null,2:0,3:1},buttons:{length:7,0:1,1:2,2:null,3:0,4:3,5:4,6:null},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Ge={mapping:"xr-standard",profiles:["htc-vive","generic-trigger-squeeze-touchpad"],displayProfiles:{"HTC Vive":["htc-vive","generic-trigger-squeeze-touchpad"],"HTC Vive DVT":["htc-vive","generic-trigger-squeeze-touchpad"],"Valve Index":["valve-index","generic-trigger-squeeze-touchpad-thumbstick"]},buttons:{length:3,0:1,1:2,2:0},gripTransform:{position:[0,0,.05,1]},targetRayTransform:{orientation:[-.08*Math.PI,0,0,1]},userAgentOverrides:{Firefox:{axes:{invert:[1,3]}}}},ke={mapping:"xr-standard",profiles:["samsung-gearvr","generic-trigger-touchpad"],buttons:{length:3,0:1,1:null,2:0},gripTransform:{orientation:[.11*Math.PI,0,0,1]}},ze={mapping:"xr-standard",profiles:["samsung-odyssey","microsoft-mixed-reality","generic-trigger-squeeze-touchpad-thumbstick"],buttons:{length:4,0:1,1:0,2:2,3:4},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Ve={mapping:"xr-standard",profiles:["microsoft-mixed-reality","generic-trigger-squeeze-touchpad-thumbstick"],buttons:{length:4,0:1,1:0,2:2,3:4},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Ue={"Daydream Controller":{mapping:"",profiles:["google-daydream","generic-trigger-touchpad"],buttons:{length:3,0:null,1:null,2:0}},"Gear VR Controller":ke,"HTC Vive Focus Controller":{mapping:"xr-standard",profiles:["htc-vive-focus","generic-trigger-touchpad"],buttons:{length:3,0:1,1:null,2:0}},"Oculus Go Controller":Ne,"Oculus Touch (Right)":Qe,"Oculus Touch (Left)":Qe,"OpenVR Gamepad":Ge,"Spatial Controller (Spatial Interaction Source) 045E-065A":Ve,"Spatial Controller (Spatial Interaction Source) 045E-065D":ze,"Windows Mixed Reality (Right)":Ve,"Windows Mixed Reality (Left)":Ve};const He=f(.155,-.465,-.15),Xe=f(-.155,-.465,-.15),We=f(0,0,-.25),je=f(0,0,.05),qe=f(-.08,.14,.08),Ye=.4,Ze=.4,Je=.61,Ke=.175,$e=.12,et=.87,tt=180/Math.PI;class it{constructor(){this.hand="right",this.headElbowOffset=He,this.controllerQ=M(),this.lastControllerQ=M(),this.headQ=M(),this.headPos=u(),this.elbowPos=u(),this.wristPos=u(),this.time=null,this.lastTime=null,this.rootQ=M(),this.position=u()}setHandedness(e){this.hand!=e&&(this.hand=e,"left"==this.hand?this.headElbowOffset=Xe:this.headElbowOffset=He)}update(e,t){this.time=X(),e&&(B(this.lastControllerQ,this.controllerQ),B(this.controllerQ,e)),t&&(h(this.headPos,t),c(this.headQ,t));let i=this.getHeadYawOrientation_(),r=this.quatAngle_(this.lastControllerQ,this.controllerQ);r/((this.time-this.lastTime)/1e3)>Je?_(this.rootQ,this.rootQ,i,Math.min(r/Ke,1)):B(this.rootQ,i);let s=f(0,0,-1);E(s,s,this.controllerQ);let n=y(s,[0,1,0]),a=this.clamp_((n-$e)/et,0,1),o=R(this.rootQ);F(o,o),x(o,o,this.controllerQ);let l=this.elbowPos;m(l,this.headPos),g(l,l,this.headElbowOffset);let A=p(qe);v(A,A,a),g(l,l,A);let d=this.quatAngle_(o,M())*tt,u=(1-Math.pow(d/180,4))*(Ye+(1-Ye)*a*Ze),w=M();_(w,w,o,u);let b=F(M(),w),S=R(o);x(S,S,b);let T=this.wristPos;m(T,je),E(T,T,w),g(T,T,We),E(T,T,S),g(T,T,l);let C=p(qe);v(C,C,a),g(this.position,this.wristPos,C),E(this.position,this.position,this.rootQ),this.lastTime=this.time}getPosition(){return this.position}getHeadYawOrientation_(){let e=u();return function(e,t,i){function r(e,t,i){return ei?i:e}var s=t[0]*t[0],n=t[1]*t[1],a=t[2]*t[2],o=t[3]*t[3];if("XYZ"===i)e[0]=Math.atan2(2*(t[0]*t[3]-t[1]*t[2]),o-s-n+a),e[1]=Math.asin(r(2*(t[0]*t[2]+t[1]*t[3]),-1,1)),e[2]=Math.atan2(2*(t[2]*t[3]-t[0]*t[1]),o+s-n-a);else if("YXZ"===i)e[0]=Math.asin(r(2*(t[0]*t[3]-t[1]*t[2]),-1,1)),e[1]=Math.atan2(2*(t[0]*t[2]+t[1]*t[3]),o-s-n+a),e[2]=Math.atan2(2*(t[0]*t[1]+t[2]*t[3]),o-s+n-a);else if("ZXY"===i)e[0]=Math.asin(r(2*(t[0]*t[3]+t[1]*t[2]),-1,1)),e[1]=Math.atan2(2*(t[1]*t[3]-t[2]*t[0]),o-s-n+a),e[2]=Math.atan2(2*(t[2]*t[3]-t[0]*t[1]),o-s+n-a);else if("ZYX"===i)e[0]=Math.atan2(2*(t[0]*t[3]+t[2]*t[1]),o-s-n+a),e[1]=Math.asin(r(2*(t[1]*t[3]-t[0]*t[2]),-1,1)),e[2]=Math.atan2(2*(t[0]*t[1]+t[2]*t[3]),o+s-n-a);else if("YZX"===i)e[0]=Math.atan2(2*(t[0]*t[3]-t[2]*t[1]),o-s+n-a),e[1]=Math.atan2(2*(t[1]*t[3]-t[0]*t[2]),o+s-n-a),e[2]=Math.asin(r(2*(t[0]*t[1]+t[2]*t[3]),-1,1));else{if("XZY"!==i)return void console.log("No order given for quaternion to euler conversion.");e[0]=Math.atan2(2*(t[0]*t[3]+t[1]*t[2]),o-s+n-a),e[1]=Math.atan2(2*(t[0]*t[2]+t[1]*t[3]),o+s-n-a),e[2]=Math.asin(r(2*(t[2]*t[3]-t[0]*t[1]),-1,1))}}(e,this.headQ,"YXZ"),function(e,t,i,r){let s=.5*Math.PI/180;t*=s,i*=s,r*=s;let n=Math.sin(t),a=Math.cos(t),o=Math.sin(i),l=Math.cos(i),A=Math.sin(r),h=Math.cos(r);return e[0]=n*l*h-a*o*A,e[1]=a*o*h+n*l*A,e[2]=a*l*A-n*o*h,e[3]=a*l*h+n*o*A,e}(M(),0,e[1]*tt,0)}clamp_(e,t,i){return Math.min(Math.max(e,t),i)}quatAngle_(e,t){let i=[0,0,-1],r=[0,0,-1];return E(i,i,e),E(r,r,t),function(e,t){let i=f(e[0],e[1],e[2]),r=f(t[0],t[1],t[2]);w(i,i),w(r,r);let s=y(i,r);return s>1?0:s<-1?Math.PI:Math.acos(s)}(i,r)}}const rt=Symbol("@@webxr-polyfill/XRRemappedGamepad"),st={pressed:!1,touched:!1,value:0};Object.freeze(st);class nt{constructor(e,t,i){if(i||(i={}),i.userAgentOverrides)for(let e in i.userAgentOverrides)if(navigator.userAgent.includes(e)){let t=i.userAgentOverrides[e];for(let e in t)e in i?Object.assign(i[e],t[e]):i[e]=t[e];break}let r=new Array(i.axes&&i.axes.length?i.axes.length:e.axes.length),s=new Array(i.buttons&&i.buttons.length?i.buttons.length:e.buttons.length),a=null;if(i.gripTransform){let e=i.gripTransform.orientation||[0,0,0,1];A(a=n(),C(e,e),i.gripTransform.position||[0,0,0])}let o=null;if(i.targetRayTransform){let e=i.targetRayTransform.orientation||[0,0,0,1];A(o=n(),C(e,e),i.targetRayTransform.position||[0,0,0])}let l=i.profiles;i.displayProfiles&&t.displayName in i.displayProfiles&&(l=i.displayProfiles[t.displayName]),this[rt]={gamepad:e,map:i,profiles:l||[e.id],mapping:i.mapping||e.mapping,axes:r,buttons:s,gripTransform:a,targetRayTransform:o},this._update()}_update(){let e=this[rt].gamepad,t=this[rt].map,i=this[rt].axes;for(let r=0;r{ot||this.global.document.body.contains(r)||(i.modifiedCanvasLayer=!0,this.global.document.body.appendChild(r),Be(r)),i.baseLayer=t})}else i.baseLayer=t}isSessionSupported(e){return"immersive-ar"!=e&&("immersive-vr"!=e||!1!==this.canPresent)}isFeatureSupported(e){switch(e){case"viewer":case"local":case"local-floor":return!0;case"bounded":case"unbounded":default:return!1}}async requestSession(e,t){if(!this.isSessionSupported(e))return Promise.reject();let i="immersive-vr"==e;if(i){const e=this.global.document.createElement("canvas");if(!ot){e.getContext("webgl")}await this.display.requestPresent([{source:e,attributes:lt}])}const r=new ct(e,t,{renderContextType:this.HAS_BITMAP_SUPPORT?"bitmaprenderer":"2d"});return this.sessions.set(r.id,r),i&&(this.immersiveSession=r,this.dispatchEvent("@@webxr-polyfill/vr-present-start",r.id)),Promise.resolve(r.id)}requestAnimationFrame(e){return this.display.requestAnimationFrame(e)}getPrimaryButtonIndex(e){let t=0,i=e.id.toLowerCase();for(let e in At)if(i.includes(e)){t=At[e];break}return Math.min(t,e.buttons.length-1)}onFrameStart(e,t){this.display.depthNear=t.depthNear,this.display.depthFar=t.depthFar,this.display.getFrameData(this.frame);const i=this.sessions.get(e);if(i.immersive&&this.CAN_USE_GAMEPAD){let e=this.gamepadInputSources;this.gamepadInputSources={};let t=this.global.navigator.getGamepads();for(let r=0;r0){let t=e[r];if(t||(t=new at(this,this.display,this.getPrimaryButtonIndex(s))),t.updateFromGamepad(s),this.gamepadInputSources[r]=t,-1!=t.primaryButtonIndex){let e=s.buttons[t.primaryButtonIndex].pressed;e&&!t.primaryActionPressed?this.dispatchEvent("@@webxr-polyfill/input-select-start",{sessionId:i.id,inputSource:t.inputSource}):!e&&t.primaryActionPressed&&this.dispatchEvent("@@webxr-polyfill/input-select-end",{sessionId:i.id,inputSource:t.inputSource}),t.primaryActionPressed=e}if(-1!=t.primarySqueezeButtonIndex){let e=s.buttons[t.primarySqueezeButtonIndex].pressed;e&&!t.primarySqueezeActionPressed?this.dispatchEvent("@@webxr-polyfill/input-squeeze-start",{sessionId:i.id,inputSource:t.inputSource}):!e&&t.primarySqueezeActionPressed&&this.dispatchEvent("@@webxr-polyfill/input-squeeze-end",{sessionId:i.id,inputSource:t.inputSource}),t.primarySqueezeActionPressed=e}}}}if(!ot&&!i.immersive&&i.baseLayer){const e=i.baseLayer.context.canvas;d(this.frame.leftProjectionMatrix,t.inlineVerticalFieldOfView,e.width/e.height,t.depthNear,t.depthFar)}}onFrameEnd(e){const t=this.sessions.get(e);if(!t.ended&&t.baseLayer){if(t.outputContext&&(!t.immersive||this.display.capabilities.hasExternalDisplay)){const e=t.immersive&&this.display.capabilities.hasExternalDisplay,i=t.baseLayer.context.canvas,r=e?i.width/2:i.width,s=i.height;if(!ot){const e=t.outputContext.canvas,n=e.width,a=e.height,o=t.renderContext;this.HAS_BITMAP_SUPPORT?i.transferToImageBitmap?o.transferFromImageBitmap(i.transferToImageBitmap()):this.global.createImageBitmap(i,0,0,r,s,{resizeWidth:n,resizeHeight:a}).then(e=>o.transferFromImageBitmap(e)):o.drawImage(i,0,0,r,s,0,0,n,a)}}t.immersive&&t.baseLayer&&this.display.submitFrame()}}cancelAnimationFrame(e){this.display.cancelAnimationFrame(e)}async endSession(e){const t=this.sessions.get(e);if(!t.ended)return t.immersive?this.display.exitPresent():void(t.ended=!0)}doesSessionSupportReferenceSpace(e,t){const i=this.sessions.get(e);return!i.ended&&i.enabledFeatures.has(t)}requestStageBounds(){if(this.display.stageParameters){const e=this.display.stageParameters.sizeX,t=this.display.stageParameters.sizeZ,i=[];return i.push(-e/2),i.push(-t/2),i.push(e/2),i.push(-t/2),i.push(e/2),i.push(t/2),i.push(-e/2),i.push(t/2),i}return null}async requestFrameOfReferenceTransform(e,t){return("local-floor"===e||"bounded-floor"===e)&&this.display.stageParameters&&this.display.stageParameters.sittingToStandingTransform?this.display.stageParameters.sittingToStandingTransform:null}getProjectionMatrix(e){if("left"===e)return this.frame.leftProjectionMatrix;if("right"===e)return this.frame.rightProjectionMatrix;if("none"===e)return this.frame.leftProjectionMatrix;throw new Error("eye must be of type 'left' or 'right'")}getViewport(e,t,i,r){const s=this.sessions.get(e),{width:n,height:a}=i.context.canvas;if(!s.immersive)return r.x=r.y=0,r.width=n,r.height=a,!0;if("left"===t||"none"===t)r.x=0;else{if("right"!==t)return!1;r.x=n/2}return r.y=0,r.width=n/2,r.height=a,!0}getBasePoseMatrix(){let{position:e,orientation:t}=this.frame.pose;return e||t?(e||((e=this.tempVec3)[0]=e[1]=e[2]=0),A(this.baseModelMatrix,t,e),this.baseModelMatrix):this.baseModelMatrix}getBaseViewMatrix(e){if("left"===e||"none"===e)return this.frame.leftViewMatrix;if("right"===e)return this.frame.rightViewMatrix;throw new Error("eye must be of type 'left' or 'right'")}getInputSources(){let e=[];for(let t in this.gamepadInputSources)e.push(this.gamepadInputSources[t].inputSource);return e}getInputPose(e,t,i){if(!t)return null;for(let r in this.gamepadInputSources){let s=this.gamepadInputSources[r];if(s.inputSource===e)return s.getXRPose(t,i)}return null}onWindowResize(){}onVRDisplayPresentChange(e){this.display.isPresenting||this.sessions.forEach(e=>{if(e.immersive&&!e.ended){if(e.modifiedCanvasLayer){const t=e.baseLayer.context.canvas;document.body.removeChild(t),t.setAttribute("style","")}this.immersiveSession===e&&(this.immersiveSession=null),this.dispatchEvent("@@webxr-polyfill/vr-present-end",e.id)}})}}const ut=!1;let pt=0;class ft{constructor(e,t){this.mode=e,this.enabledFeatures=t,this.ended=null,this.baseLayer=null,this.id=++pt}}const mt=async function(e,t){if(t.webvr){let t=await async function(e){let t=null;if("getVRDisplays"in e.navigator)try{const i=await e.navigator.getVRDisplays();i&&i.length&&(t=new dt(e,i[0]))}catch(e){}return t}(e);if(t)return t}let i=(e=>{var t=!1;return Te=e.navigator.userAgent||e.navigator.vendor||e.opera,(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(Te)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(Te.substr(0,4)))&&(t=!0),t})(e);return i&&t.cardboard||!i&&t.allowCardboardOnDesktop?(e.VRFrameData||(e.VRFrameData=function(){this.rightViewMatrix=new Float32Array(16),this.leftViewMatrix=new Float32Array(16),this.rightProjectionMatrix=new Float32Array(16),this.leftProjectionMatrix=new Float32Array(16),this.pose=null}),new class extends dt{constructor(e,t){const i=new Le(t||{});super(e,i),this.display=i,this.frame={rightViewMatrix:new Float32Array(16),leftViewMatrix:new Float32Array(16),rightProjectionMatrix:new Float32Array(16),leftProjectionMatrix:new Float32Array(16),pose:null,timestamp:null}}}(e,t.cardboardConfig)):new class extends Oe{constructor(e){super(e),this.sessions=new Map,this.projectionMatrix=n(),this.identityMatrix=n()}onBaseLayerSet(e,t){this.sessions.get(e).baseLayer=t}isSessionSupported(e){return"inline"==e}isFeatureSupported(e){switch(e){case"viewer":return!0;default:return!1}}async requestSession(e,t){if(!this.isSessionSupported(e))return Promise.reject();const i=new ft(e,t);return this.sessions.set(i.id,i),Promise.resolve(i.id)}requestAnimationFrame(e){return window.requestAnimationFrame(e)}cancelAnimationFrame(e){window.cancelAnimationFrame(e)}onFrameStart(e,t){if(ut)return;const i=this.sessions.get(e);if(i.baseLayer){const e=i.baseLayer.context.canvas;d(this.projectionMatrix,t.inlineVerticalFieldOfView,e.width/e.height,t.depthNear,t.depthFar)}}onFrameEnd(e){}async endSession(e){this.sessions.get(e).ended=!0}doesSessionSupportReferenceSpace(e,t){const i=this.sessions.get(e);return!i.ended&&i.enabledFeatures.has(t)}requestStageBounds(){return null}async requestFrameOfReferenceTransform(e,t){return null}getProjectionMatrix(e){return this.projectionMatrix}getViewport(e,t,i,r){const{width:s,height:n}=i.context.canvas;return this.sessions.get(e),r.x=r.y=0,r.width=s,r.height=n,!0}getBasePoseMatrix(){return this.identityMatrix}getBaseViewMatrix(e){return this.identityMatrix}getInputSources(){return[]}getInputPose(e,t,i){return null}onWindowResize(){}}(e)},gt={global:e,webvr:!0,cardboard:!0,cardboardConfig:null,allowCardboardOnDesktop:!1},vt=["navigator","HTMLCanvasElement","WebGLRenderingContext"];return class{constructor(e={}){this.config=Object.freeze(Object.assign({},gt,e)),this.global=this.config.global,this.nativeWebXR="xr"in this.global.navigator,this.injected=!1,this.nativeWebXR?this._injectCompatibilityShims(this.global):this._injectPolyfill(this.global)}_injectPolyfill(e){if(!vt.every(t=>!!e[t]))throw new Error(`Global must have the following attributes : ${vt}`);for(const t of Object.keys(xe))void 0!==e[t]?console.warn(`${t} already defined on global.`):e[t]=xe[t];_e(e.WebGLRenderingContext)&&(Fe(e.HTMLCanvasElement),e.OffscreenCanvas&&Fe(e.OffscreenCanvas),e.WebGL2RenderingContext&&_e(e.WebGL2RenderingContext)),this.injected=!0,this._patchNavigatorXR()}_patchNavigatorXR(){let e=mt(this.global,this.config);this.xr=new xe.XR(e),Object.defineProperty(this.global.navigator,"xr",{value:this.xr,configurable:!0})}_injectCompatibilityShims(e){if(!vt.every(t=>!!e[t]))throw new Error(`Global must have the following attributes : ${vt}`);if(e.navigator.xr&&"supportsSession"in e.navigator.xr&&!("isSessionSupported"in e.navigator.xr)){let t=e.navigator.xr.supportsSession;e.navigator.xr.isSessionSupported=function(e){return t.call(this,e).then(()=>!0).catch(()=>!1)},e.navigator.xr.supportsSession=function(e){return console.warn("navigator.xr.supportsSession() is deprecated. Please call navigator.xr.isSessionSupported() instead and check the boolean value returned when the promise resolves."),t.call(this,e)}}}}}); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.WebXRPolyfill=t()}(this,function(){"use strict";const e="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},t=Symbol("@@webxr-polyfill/EventTarget");class i{constructor(){this[t]={listeners:new Map}}addEventListener(e,i){if("string"!=typeof e)throw new Error("`type` must be a string");if("function"!=typeof i)throw new Error("`listener` must be a function");const r=this[t].listeners.get(e)||[];r.push(i),this[t].listeners.set(e,r)}removeEventListener(e,i){if("string"!=typeof e)throw new Error("`type` must be a string");if("function"!=typeof i)throw new Error("`listener` must be a function");const r=this[t].listeners.get(e)||[];for(let e=r.length;e>=0;e--)r[e]===i&&r.pop()}dispatchEvent(e,i){const r=this[t].listeners.get(e)||[],s=[];for(let e=0;e0?(r=2*Math.sqrt(i+1),e[3]=.25*r,e[0]=(t[6]-t[9])/r,e[1]=(t[8]-t[2])/r,e[2]=(t[1]-t[4])/r):t[0]>t[5]&&t[0]>t[10]?(r=2*Math.sqrt(1+t[0]-t[5]-t[10]),e[3]=(t[6]-t[9])/r,e[0]=.25*r,e[1]=(t[1]+t[4])/r,e[2]=(t[8]+t[2])/r):t[5]>t[10]?(r=2*Math.sqrt(1+t[5]-t[0]-t[10]),e[3]=(t[8]-t[2])/r,e[0]=(t[1]+t[4])/r,e[1]=.25*r,e[2]=(t[6]+t[9])/r):(r=2*Math.sqrt(1+t[10]-t[0]-t[5]),e[3]=(t[1]-t[4])/r,e[0]=(t[8]+t[2])/r,e[1]=(t[6]+t[9])/r,e[2]=.25*r),e}function d(e,t,i,r,s){let n,a=1/Math.tan(t/2);return e[0]=a/i,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=a,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[11]=-1,e[12]=0,e[13]=0,e[15]=0,null!=s&&s!==1/0?(n=1/(r-s),e[10]=(s+r)*n,e[14]=2*s*r*n):(e[10]=-1,e[14]=-2*r),e}function u(){let e=new s(3);return s!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e}function p(e){var t=new s(3);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t}function f(e,t,i){let r=new s(3);return r[0]=e,r[1]=t,r[2]=i,r}function m(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e}function g(e,t,i){return e[0]=t[0]+i[0],e[1]=t[1]+i[1],e[2]=t[2]+i[2],e}function v(e,t,i){return e[0]=t[0]*i,e[1]=t[1]*i,e[2]=t[2]*i,e}function w(e,t){let i=t[0],r=t[1],s=t[2],n=i*i+r*r+s*s;return n>0&&(n=1/Math.sqrt(n),e[0]=t[0]*n,e[1]=t[1]*n,e[2]=t[2]*n),e}function y(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]}function b(e,t,i){let r=t[0],s=t[1],n=t[2],a=i[0],o=i[1],l=i[2];return e[0]=s*l-n*o,e[1]=n*a-r*l,e[2]=r*o-s*a,e}function E(e,t,i){let r=i[0],s=i[1],n=i[2],a=i[3],o=t[0],l=t[1],A=t[2],h=s*A-n*l,c=n*o-r*A,d=r*l-s*o,u=s*d-n*c,p=n*h-r*d,f=r*c-s*h,m=2*a;return h*=m,c*=m,d*=m,u*=2,p*=2,f*=2,e[0]=o+h+u,e[1]=l+c+p,e[2]=A+d+f,e}const S=function(e){let t=e[0],i=e[1],r=e[2];return Math.sqrt(t*t+i*i+r*r)};!function(){let e=u()}();!function(){let e=function(){let e=new s(4);return s!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0,e[3]=0),e}()}();function M(){let e=new s(4);return s!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e[3]=1,e}function x(e,t,i){let r=t[0],s=t[1],n=t[2],a=t[3],o=i[0],l=i[1],A=i[2],h=i[3];return e[0]=r*h+a*o+s*A-n*l,e[1]=s*h+a*l+n*o-r*A,e[2]=n*h+a*A+r*l-s*o,e[3]=a*h-r*o-s*l-n*A,e}function _(e,t,i,s){let n,a,o,l,A,h=t[0],c=t[1],d=t[2],u=t[3],p=i[0],f=i[1],m=i[2],g=i[3];return(a=h*p+c*f+d*m+u*g)<0&&(a=-a,p=-p,f=-f,m=-m,g=-g),1-a>r?(n=Math.acos(a),o=Math.sin(n),l=Math.sin((1-s)*n)/o,A=Math.sin(s*n)/o):(l=1-s,A=s),e[0]=l*h+A*p,e[1]=l*c+A*f,e[2]=l*d+A*m,e[3]=l*u+A*g,e}function F(e,t){let i=t[0],r=t[1],s=t[2],n=t[3],a=i*i+r*r+s*s+n*n,o=a?1/a:0;return e[0]=-i*o,e[1]=-r*o,e[2]=-s*o,e[3]=n*o,e}const R=function(e){let t=new s(4);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},T=function(e,t,i,r){let n=new s(4);return n[0]=e,n[1]=t,n[2]=i,n[3]=r,n},B=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e},P=function(e,t){let i=t[0],r=t[1],s=t[2],n=t[3],a=i*i+r*r+s*s+n*n;return a>0&&(a=1/Math.sqrt(a),e[0]=i*a,e[1]=r*a,e[2]=s*a,e[3]=n*a),e},C=(function(){let e=u(),t=f(1,0,0),i=f(0,1,0)}(),function(){let e=M(),t=M()}(),function(){let e=function(){let e=new s(9);return s!=Float32Array&&(e[1]=0,e[2]=0,e[3]=0,e[5]=0,e[6]=0,e[7]=0),e[0]=1,e[4]=1,e[8]=1,e}()}(),Symbol("@@webxr-polyfill/XRRigidTransform"));class D{constructor(){if(this[C]={matrix:null,position:null,orientation:null,inverse:null},0===arguments.length)this[C].matrix=a(new Float32Array(16));else if(1===arguments.length)arguments[0]instanceof Float32Array?this[C].matrix=arguments[0]:(this[C].position=this._getPoint(arguments[0]),this[C].orientation=DOMPointReadOnly.fromPoint({x:0,y:0,z:0,w:1}));else{if(2!==arguments.length)throw new Error("Too many arguments!");this[C].position=this._getPoint(arguments[0]),this[C].orientation=this._getPoint(arguments[1])}if(this[C].matrix){let e=u();h(e,this[C].matrix),this[C].position=DOMPointReadOnly.fromPoint({x:e[0],y:e[1],z:e[2]});let t=M();c(t,this[C].matrix),this[C].orientation=DOMPointReadOnly.fromPoint({x:t[0],y:t[1],z:t[2],w:t[3]})}else this[C].matrix=a(new Float32Array(16)),A(this[C].matrix,T(this[C].orientation.x,this[C].orientation.y,this[C].orientation.z,this[C].orientation.w),f(this[C].position.x,this[C].position.y,this[C].position.z))}_getPoint(e){return e instanceof DOMPointReadOnly?e:DOMPointReadOnly.fromPoint(e)}get matrix(){return this[C].matrix}get position(){return this[C].position}get orientation(){return this[C].orientation}get inverse(){if(null===this[C].inverse){let e=a(new Float32Array(16));o(e,this[C].matrix),this[C].inverse=new D(e),this[C].inverse[C].inverse=this}return this[C].inverse}}const I=Symbol("@@webxr-polyfill/XRSpace");class L{constructor(e=null,t=null){this[I]={specialType:e,inputSource:t,baseMatrix:null,inverseBaseMatrix:null,lastFrameId:-1}}get _specialType(){return this[I].specialType}get _inputSource(){return this[I].inputSource}_ensurePoseUpdated(e,t){t!=this[I].lastFrameId&&(this[I].lastFrameId=t,this._onPoseUpdate(e))}_onPoseUpdate(e){"viewer"==this[I].specialType&&(this._baseMatrix=e.getBasePoseMatrix())}set _baseMatrix(e){this[I].baseMatrix=e,this[I].inverseBaseMatrix=null}get _baseMatrix(){return this[I].baseMatrix||this[I].inverseBaseMatrix&&(this[I].baseMatrix=new Float32Array(16),o(this[I].baseMatrix,this[I].inverseBaseMatrix)),this[I].baseMatrix}set _inverseBaseMatrix(e){this[I].inverseBaseMatrix=e,this[I].baseMatrix=null}get _inverseBaseMatrix(){return this[I].inverseBaseMatrix||this[I].baseMatrix&&(this[I].inverseBaseMatrix=new Float32Array(16),o(this[I].inverseBaseMatrix,this[I].baseMatrix)),this[I].inverseBaseMatrix}_getSpaceRelativeTransform(e){if(!this._inverseBaseMatrix||!e._baseMatrix)return null;let t=new Float32Array(16);return l(t,this._inverseBaseMatrix,e._baseMatrix),new D(t)}}const O=1.6,N=Symbol("@@webxr-polyfill/XRReferenceSpace"),G=["viewer","local","local-floor","bounded-floor","unbounded"];class Q extends L{constructor(e,t=null){if(!G.includes(e))throw new Error(`XRReferenceSpaceType must be one of ${G}`);if(super(e),"bounded-floor"===e&&!t)throw new Error("XRReferenceSpace cannot use 'bounded-floor' type if the platform does not provide the floor level");(function(e){return"bounded-floor"===e||"local-floor"===e})(e)&&!t&&((t=a(new Float32Array(16)))[13]=O),this._inverseBaseMatrix=t||a(new Float32Array(16)),this[N]={type:e,transform:t,originOffset:a(new Float32Array(16))}}_transformBasePoseMatrix(e,t){l(e,this._inverseBaseMatrix,t)}_originOffsetMatrix(){return this[N].originOffset}_adjustForOriginOffset(e){let t=new Float32Array(16);o(t,this[N].originOffset),l(e,t,e)}_getSpaceRelativeTransform(e){let t=super._getSpaceRelativeTransform(e);return this._adjustForOriginOffset(t.matrix),new XRRigidTransform(t.matrix)}getOffsetReferenceSpace(e){let t=new Q(this[N].type,this[N].transform,this[N].bounds);return l(t[N].originOffset,this[N].originOffset,e.matrix),t}}const k=Symbol("@@webxr-polyfill/XR"),z=["inline","immersive-vr","immersive-ar"],U={inline:{requiredFeatures:["viewer"],optionalFeatures:[]},"immersive-vr":{requiredFeatures:["viewer","local"],optionalFeatures:[]},"immersive-ar":{requiredFeatures:["viewer","local"],optionalFeatures:[]}},V="Polyfill Error: Must call navigator.xr.isSessionSupported() with any XRSessionMode\nor navigator.xr.requestSession('inline') prior to requesting an immersive\nsession. This is a limitation specific to the WebXR Polyfill and does not apply\nto native implementations of the API.";let H;if("performance"in e==!1){let e=Date.now();H=(()=>Date.now()-e)}else H=(()=>performance.now());var X=H;const W=Symbol("@@webxr-polyfill/XRPose");class j{constructor(e,t){this[W]={transform:e,emulatedPosition:t}}get transform(){return this[W].transform}get emulatedPosition(){return this[W].emulatedPosition}}const q=Symbol("@@webxr-polyfill/XRViewerPose");class Y extends j{constructor(e,t,i=!1){super(e,i),this[q]={views:t}}get views(){return this[q].views}}const Z=Symbol("@@webxr-polyfill/XRViewport");class J{constructor(e){this[Z]={target:e}}get x(){return this[Z].target.x}get y(){return this[Z].target.y}get width(){return this[Z].target.width}get height(){return this[Z].target.height}}const K=["left","right","none"],$=Symbol("@@webxr-polyfill/XRView");class ee{constructor(e,t,i,r){if(!K.includes(i))throw new Error(`XREye must be one of: ${K}`);const s=Object.create(null),n=new J(s);this[$]={device:e,eye:i,viewport:n,temp:s,sessionId:r,transform:t}}get eye(){return this[$].eye}get projectionMatrix(){return this[$].device.getProjectionMatrix(this.eye)}get transform(){return this[$].transform}_getViewport(e){if(this[$].device.getViewport(this[$].sessionId,this.eye,e,this[$].temp))return this[$].viewport}}const te=Symbol("@@webxr-polyfill/XRFrame"),ie="XRFrame access outside the callback that produced it is invalid.",re="getViewerPose can only be called on XRFrame objects passed to XRSession.requestAnimationFrame callbacks.";let se=0;class ne{constructor(e,t,i){this[te]={id:++se,active:!1,animationFrame:!1,device:e,session:t,sessionId:i}}get session(){return this[te].session}getViewerPose(e){if(!this[te].animationFrame)throw new DOMException(re,"InvalidStateError");if(!this[te].active)throw new DOMException(ie,"InvalidStateError");const t=this[te].device,i=this[te].session;i[we].viewerSpace._ensurePoseUpdated(t,this[te].id),e._ensurePoseUpdated(t,this[te].id);let r=e._getSpaceRelativeTransform(i[we].viewerSpace);const s=[];for(let r of i[we].viewSpaces){r._ensurePoseUpdated(t,this[te].id);let i=e._getSpaceRelativeTransform(r),n=new ee(t,i,r.eye,this[te].sessionId);s.push(n)}return new Y(r,s,!1)}getPose(e,t){if(!this[te].active)throw new DOMException(ie,"InvalidStateError");const i=this[te].device;if("target-ray"===e._specialType||"grip"===e._specialType)return i.getInputPose(e._inputSource,t,e._specialType);{e._ensurePoseUpdated(i,this[te].id),t._ensurePoseUpdated(i,this[te].id);let r=t._getSpaceRelativeTransform(e);return r?new XRPose(r,!1):null}}}const ae=Symbol("@@webxr-polyfill/XRRenderState"),oe=Object.freeze({depthNear:.1,depthFar:1e3,inlineVerticalFieldOfView:null,baseLayer:null});class le{constructor(e={}){const t=Object.assign({},oe,e);this[ae]={config:t}}get depthNear(){return this[ae].config.depthNear}get depthFar(){return this[ae].config.depthFar}get inlineVerticalFieldOfView(){return this[ae].config.inlineVerticalFieldOfView}get baseLayer(){return this[ae].config.baseLayer}}const Ae=Symbol("@@webxr-polyfill/polyfilled-xr-compatible"),he=Symbol("@@webxr-polyfill/xr-compatible"),ce=Symbol("@@webxr-polyfill/XRWebGLLayer"),de=Object.freeze({antialias:!0,depth:!1,stencil:!1,alpha:!0,multiview:!1,ignoreDepthValues:!1,framebufferScaleFactor:1});const ue=Symbol("@@webxr-polyfill/XRInputSourceEvent");class pe extends Event{constructor(e,t){super(e,t),this[ue]={frame:t.frame,inputSource:t.inputSource}}get frame(){return this[ue].frame}get inputSource(){return this[ue].inputSource}}const fe=Symbol("@@webxr-polyfill/XRSessionEvent");class me extends Event{constructor(e,t){super(e,t),this[fe]={session:t.session}}get session(){return this[fe].session}}const ge=Symbol("@@webxr-polyfill/XRInputSourcesChangeEvent");class ve extends Event{constructor(e,t){super(e,t),this[ge]={session:t.session,added:t.added,removed:t.removed}}get session(){return this[ge].session}get added(){return this[ge].added}get removed(){return this[ge].removed}}const we=Symbol("@@webxr-polyfill/XRSession");class ye extends L{constructor(e){super(e)}get eye(){return this._specialType}_onPoseUpdate(e){this._inverseBaseMatrix=e.getBaseViewMatrix(this._specialType)}}class be extends i{constructor(e,t,i){super();let r="inline"!=t,s=new le({inlineVerticalFieldOfView:r?null:.5*Math.PI});this[we]={device:e,mode:t,immersive:r,ended:!1,suspended:!1,frameCallbacks:[],currentFrameCallbacks:null,frameHandle:0,deviceFrameHandle:null,id:i,activeRenderState:s,pendingRenderState:null,viewerSpace:new Q("viewer"),viewSpaces:[],currentInputSources:[]},r?this[we].viewSpaces.push(new ye("left"),new ye("right")):this[we].viewSpaces.push(new ye("none")),this[we].onDeviceFrame=(()=>{if(this[we].ended||this[we].suspended)return;if(this[we].deviceFrameHandle=null,this[we].startDeviceFrameLoop(),null!==this[we].pendingRenderState&&(this[we].activeRenderState=new le(this[we].pendingRenderState),this[we].pendingRenderState=null,this[we].activeRenderState.baseLayer&&this[we].device.onBaseLayerSet(this[we].id,this[we].activeRenderState.baseLayer)),null===this[we].activeRenderState.baseLayer)return;const t=new ne(e,this,this[we].id),i=this[we].currentFrameCallbacks=this[we].frameCallbacks;this[we].frameCallbacks=[],t[te].active=!0,t[te].animationFrame=!0,this[we].device.onFrameStart(this[we].id,this[we].activeRenderState),this._checkInputSourcesChange();const r=X();for(let e=0;e{null===this[we].deviceFrameHandle&&(this[we].deviceFrameHandle=this[we].device.requestAnimationFrame(this[we].onDeviceFrame))}),this[we].stopDeviceFrameLoop=(()=>{const e=this[we].deviceFrameHandle;null!==e&&(this[we].device.cancelAnimationFrame(e),this[we].deviceFrameHandle=null)}),this[we].onPresentationEnd=(t=>{if(t!==this[we].id)return this[we].suspended=!1,this[we].startDeviceFrameLoop(),void this.dispatchEvent("focus",{session:this});this[we].ended=!0,this[we].stopDeviceFrameLoop(),e.removeEventListener("@webvr-polyfill/vr-present-end",this[we].onPresentationEnd),e.removeEventListener("@webvr-polyfill/vr-present-start",this[we].onPresentationStart),e.removeEventListener("@@webvr-polyfill/input-select-start",this[we].onSelectStart),e.removeEventListener("@@webvr-polyfill/input-select-end",this[we].onSelectEnd),this.dispatchEvent("end",new me("end",{session:this}))}),e.addEventListener("@@webxr-polyfill/vr-present-end",this[we].onPresentationEnd),this[we].onPresentationStart=(e=>{e!==this[we].id&&(this[we].suspended=!0,this[we].stopDeviceFrameLoop(),this.dispatchEvent("blur",{session:this}))}),e.addEventListener("@@webxr-polyfill/vr-present-start",this[we].onPresentationStart),this[we].onSelectStart=(e=>{e.sessionId===this[we].id&&this[we].dispatchInputSourceEvent("selectstart",e.inputSource)}),e.addEventListener("@@webxr-polyfill/input-select-start",this[we].onSelectStart),this[we].onSelectEnd=(e=>{e.sessionId===this[we].id&&(this[we].dispatchInputSourceEvent("selectend",e.inputSource),this[we].dispatchInputSourceEvent("select",e.inputSource))}),e.addEventListener("@@webxr-polyfill/input-select-end",this[we].onSelectEnd),this[we].onSqueezeStart=(e=>{e.sessionId===this[we].id&&this[we].dispatchInputSourceEvent("squeezestart",e.inputSource)}),e.addEventListener("@@webxr-polyfill/input-squeeze-start",this[we].onSqueezeStart),this[we].onSqueezeEnd=(e=>{e.sessionId===this[we].id&&(this[we].dispatchInputSourceEvent("squeezeend",e.inputSource),this[we].dispatchInputSourceEvent("squeeze",e.inputSource))}),e.addEventListener("@@webxr-polyfill/input-squeeze-end",this[we].onSqueezeEnd),this[we].dispatchInputSourceEvent=((t,i)=>{const r=new ne(e,this,this[we].id),s=new pe(t,{frame:r,inputSource:i});r[te].active=!0,this.dispatchEvent(t,s),r[te].active=!1}),this[we].startDeviceFrameLoop(),this.onblur=void 0,this.onfocus=void 0,this.onresetpose=void 0,this.onend=void 0,this.onselect=void 0,this.onselectstart=void 0,this.onselectend=void 0}get renderState(){return this[we].activeRenderState}get environmentBlendMode(){return this[we].device.environmentBlendMode||"opaque"}async requestReferenceSpace(e){if(this[we].ended)return;if(!G.includes(e))throw new TypeError(`XRReferenceSpaceType must be one of ${G}`);if(!this[we].device.doesSessionSupportReferenceSpace(this[we].id,e))throw new DOMException(`The ${e} reference space is not supported by this session.`,"NotSupportedError");if("viewer"===e)return this[we].viewerSpace;let t=await this[we].device.requestFrameOfReferenceTransform(e);if("bounded-floor"===e){if(!t)throw new DOMException(`${e} XRReferenceSpace not supported by this device.`,"NotSupportedError");if(!this[we].device.requestStageBounds())throw new DOMException(`${e} XRReferenceSpace not supported by this device.`,"NotSupportedError");throw new DOMException(`The WebXR polyfill does not support the ${e} reference space yet.`,"NotSupportedError")}return new Q(e,t)}requestAnimationFrame(e){if(this[we].ended)return;const t=++this[we].frameHandle;return this[we].frameCallbacks.push({handle:t,callback:e,cancelled:!1}),t}cancelAnimationFrame(e){let t=this[we].frameCallbacks,i=t.findIndex(t=>t&&t.handle===e);i>-1&&(t[i].cancelled=!0,t.splice(i,1)),(t=this[we].currentFrameCallbacks)&&(i=t.findIndex(t=>t&&t.handle===e))>-1&&(t[i].cancelled=!0)}get inputSources(){return this[we].device.getInputSources()}async end(){if(!this[we].ended)return this[we].immersive&&(this[we].ended=!0,this[we].device.removeEventListener("@@webvr-polyfill/vr-present-start",this[we].onPresentationStart),this[we].device.removeEventListener("@@webvr-polyfill/vr-present-end",this[we].onPresentationEnd),this[we].device.removeEventListener("@@webvr-polyfill/input-select-start",this[we].onSelectStart),this[we].device.removeEventListener("@@webvr-polyfill/input-select-end",this[we].onSelectEnd),this.dispatchEvent("end",new me("end",{session:this}))),this[we].stopDeviceFrameLoop(),this[we].device.endSession(this[we].id)}updateRenderState(e){if(this[we].ended){throw new Error("Can't call updateRenderState on an XRSession that has already ended.")}if(e.baseLayer&&e.baseLayer._session!==this){throw new Error("Called updateRenderState with a base layer that was created by a different session.")}if(null!==e.inlineVerticalFieldOfView&&void 0!==e.inlineVerticalFieldOfView){if(this[we].immersive){throw new Error("inlineVerticalFieldOfView must not be set for an XRRenderState passed to updateRenderState for an immersive session.")}e.inlineVerticalFieldOfView=Math.min(3.13,Math.max(.01,e.inlineVerticalFieldOfView))}if(null===this[we].pendingRenderState){const e=this[we].activeRenderState;this[we].pendingRenderState={depthNear:e.depthNear,depthFar:e.depthFar,inlineVerticalFieldOfView:e.inlineVerticalFieldOfView,baseLayer:e.baseLayer}}Object.assign(this[we].pendingRenderState,e)}_checkInputSourcesChange(){const e=[],t=[],i=this.inputSources,r=this[we].currentInputSources;for(const t of i)r.includes(t)||e.push(t);for(const e of r)i.includes(e)||t.push(e);(e.length>0||t.length>0)&&this.dispatchEvent("inputsourceschange",new ve("inputsourceschange",{session:this,added:e,removed:t})),this[we].currentInputSources.length=0;for(const e of i)this[we].currentInputSources.push(e)}}const Ee=Symbol("@@webxr-polyfill/XRInputSource");class Se{constructor(e){this[Ee]={impl:e,gripSpace:new L("grip",this),targetRaySpace:new L("target-ray",this)}}get handedness(){return this[Ee].impl.handedness}get targetRayMode(){return this[Ee].impl.targetRayMode}get gripSpace(){let e=this[Ee].impl.targetRayMode;return"gaze"===e||"screen"===e?null:this[Ee].gripSpace}get targetRaySpace(){return this[Ee].targetRaySpace}get profiles(){return this[Ee].impl.profiles}get gamepad(){return this[Ee].impl.gamepad}}const Me=Symbol("@@webxr-polyfill/XRReferenceSpaceEvent");var xe={XR:class extends i{constructor(e){super(),this[k]={device:null,devicePromise:e,immersiveSession:null,inlineSessions:new Set},e.then(e=>{this[k].device=e})}async isSessionSupported(e){return this[k].device||await this[k].devicePromise,"inline"!=e?Promise.resolve(this[k].device.isSessionSupported(e)):Promise.resolve(!0)}async requestSession(e,t){if(!this[k].device){if("inline"!=e)throw new Error(V);await this[k].devicePromise}if(!z.includes(e))throw new TypeError(`The provided value '${e}' is not a valid enum value of type XRSessionMode`);const i=U[e],r=i.requiredFeatures.concat(t&&t.requiredFeatures?t.requiredFeatures:[]),s=i.optionalFeatures.concat(t&&t.optionalFeatures?t.optionalFeatures:[]),n=new Set;let a=!1;for(let e of r)this[k].device.isFeatureSupported(e)?n.add(e):(console.error(`The required feature '${e}' is not supported`),a=!0);if(a)throw new DOMException("Session does not support some required features","NotSupportedError");for(let e of s)this[k].device.isFeatureSupported(e)?n.add(e):console.log(`The optional feature '${e}' is not supported`);const o=await this[k].device.requestSession(e,n),l=new XRSession(this[k].device,e,o);"inline"==e?this[k].inlineSessions.add(l):this[k].immersiveSession=l;const A=()=>{"inline"==e?this[k].inlineSessions.delete(l):this[k].immersiveSession=null,l.removeEventListener("end",A)};return l.addEventListener("end",A),l}},XRSession:be,XRSessionEvent:me,XRFrame:ne,XRView:ee,XRViewport:J,XRViewerPose:Y,XRWebGLLayer:class{constructor(e,t,i={}){const r=Object.assign({},de,i);if(!(e instanceof be))throw new Error("session must be a XRSession");if(e.ended)throw new Error("InvalidStateError");if(t[Ae]&&!0!==t[he])throw new Error("InvalidStateError");const s=t.getParameter(t.FRAMEBUFFER_BINDING);this[ce]={context:t,config:r,framebuffer:s,session:e}}get context(){return this[ce].context}get antialias(){return this[ce].config.antialias}get ignoreDepthValues(){return!0}get framebuffer(){return this[ce].framebuffer}get framebufferWidth(){return this[ce].context.drawingBufferWidth}get framebufferHeight(){return this[ce].context.drawingBufferHeight}get _session(){return this[ce].session}getViewport(e){return e._getViewport(this)}static getNativeFramebufferScaleFactor(e){if(!e)throw new TypeError("getNativeFramebufferScaleFactor must be passed a session.");return e[we].ended?0:1}},XRSpace:L,XRReferenceSpace:Q,XRReferenceSpaceEvent:class extends Event{constructor(e,t){super(e,t),this[Me]={referenceSpace:t.referenceSpace,transform:t.transform||null}}get referenceSpace(){return this[Me].referenceSpace}get transform(){return this[Me].transform}},XRInputSource:Se,XRInputSourceEvent:pe,XRInputSourcesChangeEvent:ve,XRRenderState:le,XRRigidTransform:D,XRPose:j};const _e=e=>"function"!=typeof e.prototype.makeXRCompatible&&(e.prototype.makeXRCompatible=function(){return this[he]=!0,Promise.resolve()},!0),Fe=e=>{const t=e.prototype.getContext;e.prototype.getContext=function(e,i){const r=t.call(this,e,i);return r&&(r[Ae]=!0,i&&"xrCompatible"in i&&(r[he]=i.xrCompatible)),r}},Re=e=>!(!e.ImageBitmapRenderingContext||!e.createImageBitmap);var Te;const Be=e=>{e.style.display="block",e.style.position="absolute",e.style.width=e.style.height="1px",e.style.top=e.style.left="0px"};var Pe="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var Ce,De,Ie=(function(e,t){e.exports=function(){var e,t,i,r=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},s=function(){function e(e,t){for(var i=0;ie.TEXTURE31){console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit"),r.push(null,null);break}s||(s=e.getParameter(e.ACTIVE_TEXTURE)),e.activeTexture(o),r.push(e.getParameter(a),null);break;case e.ACTIVE_TEXTURE:s=e.getParameter(e.ACTIVE_TEXTURE),r.push(null);break;default:r.push(e.getParameter(a))}}i(e);for(var n=0;ne.TEXTURE31)break;e.activeTexture(o),e.bindTexture(e.TEXTURE_2D,l);break;case e.TEXTURE_BINDING_CUBE_MAP:var o=t[++n];if(oe.TEXTURE31)break;e.activeTexture(o),e.bindTexture(e.TEXTURE_CUBE_MAP,l);break;case e.VIEWPORT:e.viewport(l[0],l[1],l[2],l[3]);break;case e.BLEND:case e.CULL_FACE:case e.DEPTH_TEST:case e.SCISSOR_TEST:case e.STENCIL_TEST:l?e.enable(a):e.disable(a);break;default:console.log("No GL restore behavior for 0x"+a.toString(16))}s&&e.activeTexture(s)}}else i(e)},F=["attribute vec2 position;","attribute vec3 texCoord;","varying vec2 vTexCoord;","uniform vec4 viewportOffsetScale[2];","void main() {"," vec4 viewport = viewportOffsetScale[int(texCoord.z)];"," vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;"," gl_Position = vec4( position, 1.0, 1.0 );","}"].join("\n"),R=["precision mediump float;","uniform sampler2D diffuse;","varying vec2 vTexCoord;","void main() {"," gl_FragColor = texture2D(diffuse, vTexCoord);","}"].join("\n");function T(e,t,i,r){this.gl=e,this.cardboardUI=t,this.bufferScale=i,this.dirtySubmitFrameBindings=r,this.ctxAttribs=e.getContextAttributes(),this.meshWidth=20,this.meshHeight=20,this.bufferWidth=e.drawingBufferWidth,this.bufferHeight=e.drawingBufferHeight,this.realBindFramebuffer=e.bindFramebuffer,this.realEnable=e.enable,this.realDisable=e.disable,this.realColorMask=e.colorMask,this.realClearColor=e.clearColor,this.realViewport=e.viewport,o()||(this.realCanvasWidth=Object.getOwnPropertyDescriptor(e.canvas.__proto__,"width"),this.realCanvasHeight=Object.getOwnPropertyDescriptor(e.canvas.__proto__,"height")),this.isPatched=!1,this.lastBoundFramebuffer=null,this.cullFace=!1,this.depthTest=!1,this.blend=!1,this.scissorTest=!1,this.stencilTest=!1,this.viewport=[0,0,0,0],this.colorMask=[!0,!0,!0,!0],this.clearColor=[0,0,0,0],this.attribs={position:0,texCoord:1},this.program=g(e,F,R,this.attribs),this.uniforms=v(e,this.program),this.viewportOffsetScale=new Float32Array(8),this.setTextureBounds(),this.vertexBuffer=e.createBuffer(),this.indexBuffer=e.createBuffer(),this.indexCount=0,this.renderTarget=e.createTexture(),this.framebuffer=e.createFramebuffer(),this.depthStencilBuffer=null,this.depthBuffer=null,this.stencilBuffer=null,this.ctxAttribs.depth&&this.ctxAttribs.stencil?this.depthStencilBuffer=e.createRenderbuffer():this.ctxAttribs.depth?this.depthBuffer=e.createRenderbuffer():this.ctxAttribs.stencil&&(this.stencilBuffer=e.createRenderbuffer()),this.patch(),this.onResize()}T.prototype.destroy=function(){var e=this.gl;this.unpatch(),e.deleteProgram(this.program),e.deleteBuffer(this.vertexBuffer),e.deleteBuffer(this.indexBuffer),e.deleteTexture(this.renderTarget),e.deleteFramebuffer(this.framebuffer),this.depthStencilBuffer&&e.deleteRenderbuffer(this.depthStencilBuffer),this.depthBuffer&&e.deleteRenderbuffer(this.depthBuffer),this.stencilBuffer&&e.deleteRenderbuffer(this.stencilBuffer),this.cardboardUI&&this.cardboardUI.destroy()},T.prototype.onResize=function(){var e=this.gl,t=this,i=[e.RENDERBUFFER_BINDING,e.TEXTURE_BINDING_2D,e.TEXTURE0];_(e,i,function(e){t.realBindFramebuffer.call(e,e.FRAMEBUFFER,null),t.scissorTest&&t.realDisable.call(e,e.SCISSOR_TEST),t.realColorMask.call(e,!0,!0,!0,!0),t.realViewport.call(e,0,0,e.drawingBufferWidth,e.drawingBufferHeight),t.realClearColor.call(e,0,0,0,1),e.clear(e.COLOR_BUFFER_BIT),t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.framebuffer),e.bindTexture(e.TEXTURE_2D,t.renderTarget),e.texImage2D(e.TEXTURE_2D,0,t.ctxAttribs.alpha?e.RGBA:e.RGB,t.bufferWidth,t.bufferHeight,0,t.ctxAttribs.alpha?e.RGBA:e.RGB,e.UNSIGNED_BYTE,null),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t.renderTarget,0),t.ctxAttribs.depth&&t.ctxAttribs.stencil?(e.bindRenderbuffer(e.RENDERBUFFER,t.depthStencilBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.DEPTH_STENCIL,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.DEPTH_STENCIL_ATTACHMENT,e.RENDERBUFFER,t.depthStencilBuffer)):t.ctxAttribs.depth?(e.bindRenderbuffer(e.RENDERBUFFER,t.depthBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.DEPTH_COMPONENT16,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.DEPTH_ATTACHMENT,e.RENDERBUFFER,t.depthBuffer)):t.ctxAttribs.stencil&&(e.bindRenderbuffer(e.RENDERBUFFER,t.stencilBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.STENCIL_INDEX8,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.STENCIL_ATTACHMENT,e.RENDERBUFFER,t.stencilBuffer)),!e.checkFramebufferStatus(e.FRAMEBUFFER)===e.FRAMEBUFFER_COMPLETE&&console.error("Framebuffer incomplete!"),t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.lastBoundFramebuffer),t.scissorTest&&t.realEnable.call(e,e.SCISSOR_TEST),t.realColorMask.apply(e,t.colorMask),t.realViewport.apply(e,t.viewport),t.realClearColor.apply(e,t.clearColor)}),this.cardboardUI&&this.cardboardUI.onResize()},T.prototype.patch=function(){if(!this.isPatched){var e=this,t=this.gl.canvas,i=this.gl;o()||(t.width=p()*this.bufferScale,t.height=f()*this.bufferScale,Object.defineProperty(t,"width",{configurable:!0,enumerable:!0,get:function(){return e.bufferWidth},set:function(i){e.bufferWidth=i,e.realCanvasWidth.set.call(t,i),e.onResize()}}),Object.defineProperty(t,"height",{configurable:!0,enumerable:!0,get:function(){return e.bufferHeight},set:function(i){e.bufferHeight=i,e.realCanvasHeight.set.call(t,i),e.onResize()}})),this.lastBoundFramebuffer=i.getParameter(i.FRAMEBUFFER_BINDING),null==this.lastBoundFramebuffer&&(this.lastBoundFramebuffer=this.framebuffer,this.gl.bindFramebuffer(i.FRAMEBUFFER,this.framebuffer)),this.gl.bindFramebuffer=function(t,r){e.lastBoundFramebuffer=r||e.framebuffer,e.realBindFramebuffer.call(i,t,e.lastBoundFramebuffer)},this.cullFace=i.getParameter(i.CULL_FACE),this.depthTest=i.getParameter(i.DEPTH_TEST),this.blend=i.getParameter(i.BLEND),this.scissorTest=i.getParameter(i.SCISSOR_TEST),this.stencilTest=i.getParameter(i.STENCIL_TEST),i.enable=function(t){switch(t){case i.CULL_FACE:e.cullFace=!0;break;case i.DEPTH_TEST:e.depthTest=!0;break;case i.BLEND:e.blend=!0;break;case i.SCISSOR_TEST:e.scissorTest=!0;break;case i.STENCIL_TEST:e.stencilTest=!0}e.realEnable.call(i,t)},i.disable=function(t){switch(t){case i.CULL_FACE:e.cullFace=!1;break;case i.DEPTH_TEST:e.depthTest=!1;break;case i.BLEND:e.blend=!1;break;case i.SCISSOR_TEST:e.scissorTest=!1;break;case i.STENCIL_TEST:e.stencilTest=!1}e.realDisable.call(i,t)},this.colorMask=i.getParameter(i.COLOR_WRITEMASK),i.colorMask=function(t,r,s,n){e.colorMask[0]=t,e.colorMask[1]=r,e.colorMask[2]=s,e.colorMask[3]=n,e.realColorMask.call(i,t,r,s,n)},this.clearColor=i.getParameter(i.COLOR_CLEAR_VALUE),i.clearColor=function(t,r,s,n){e.clearColor[0]=t,e.clearColor[1]=r,e.clearColor[2]=s,e.clearColor[3]=n,e.realClearColor.call(i,t,r,s,n)},this.viewport=i.getParameter(i.VIEWPORT),i.viewport=function(t,r,s,n){e.viewport[0]=t,e.viewport[1]=r,e.viewport[2]=s,e.viewport[3]=n,e.realViewport.call(i,t,r,s,n)},this.isPatched=!0,b(t)}},T.prototype.unpatch=function(){if(this.isPatched){var e=this.gl,t=this.gl.canvas;o()||(Object.defineProperty(t,"width",this.realCanvasWidth),Object.defineProperty(t,"height",this.realCanvasHeight)),t.width=this.bufferWidth,t.height=this.bufferHeight,e.bindFramebuffer=this.realBindFramebuffer,e.enable=this.realEnable,e.disable=this.realDisable,e.colorMask=this.realColorMask,e.clearColor=this.realClearColor,e.viewport=this.realViewport,this.lastBoundFramebuffer==this.framebuffer&&e.bindFramebuffer(e.FRAMEBUFFER,null),this.isPatched=!1,setTimeout(function(){b(t)},1)}},T.prototype.setTextureBounds=function(e,t){e||(e=[0,0,.5,1]),t||(t=[.5,0,.5,1]),this.viewportOffsetScale[0]=e[0],this.viewportOffsetScale[1]=e[1],this.viewportOffsetScale[2]=e[2],this.viewportOffsetScale[3]=e[3],this.viewportOffsetScale[4]=t[0],this.viewportOffsetScale[5]=t[1],this.viewportOffsetScale[6]=t[2],this.viewportOffsetScale[7]=t[3]},T.prototype.submitFrame=function(){var e=this.gl,t=this,i=[];if(this.dirtySubmitFrameBindings||i.push(e.CURRENT_PROGRAM,e.ARRAY_BUFFER_BINDING,e.ELEMENT_ARRAY_BUFFER_BINDING,e.TEXTURE_BINDING_2D,e.TEXTURE0),_(e,i,function(e){t.realBindFramebuffer.call(e,e.FRAMEBUFFER,null),t.cullFace&&t.realDisable.call(e,e.CULL_FACE),t.depthTest&&t.realDisable.call(e,e.DEPTH_TEST),t.blend&&t.realDisable.call(e,e.BLEND),t.scissorTest&&t.realDisable.call(e,e.SCISSOR_TEST),t.stencilTest&&t.realDisable.call(e,e.STENCIL_TEST),t.realColorMask.call(e,!0,!0,!0,!0),t.realViewport.call(e,0,0,e.drawingBufferWidth,e.drawingBufferHeight),(t.ctxAttribs.alpha||o())&&(t.realClearColor.call(e,0,0,0,1),e.clear(e.COLOR_BUFFER_BIT)),e.useProgram(t.program),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,t.indexBuffer),e.bindBuffer(e.ARRAY_BUFFER,t.vertexBuffer),e.enableVertexAttribArray(t.attribs.position),e.enableVertexAttribArray(t.attribs.texCoord),e.vertexAttribPointer(t.attribs.position,2,e.FLOAT,!1,20,0),e.vertexAttribPointer(t.attribs.texCoord,3,e.FLOAT,!1,20,8),e.activeTexture(e.TEXTURE0),e.uniform1i(t.uniforms.diffuse,0),e.bindTexture(e.TEXTURE_2D,t.renderTarget),e.uniform4fv(t.uniforms.viewportOffsetScale,t.viewportOffsetScale),e.drawElements(e.TRIANGLES,t.indexCount,e.UNSIGNED_SHORT,0),t.cardboardUI&&t.cardboardUI.renderNoState(),t.realBindFramebuffer.call(t.gl,e.FRAMEBUFFER,t.framebuffer),t.ctxAttribs.preserveDrawingBuffer||(t.realClearColor.call(e,0,0,0,0),e.clear(e.COLOR_BUFFER_BIT)),t.dirtySubmitFrameBindings||t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.lastBoundFramebuffer),t.cullFace&&t.realEnable.call(e,e.CULL_FACE),t.depthTest&&t.realEnable.call(e,e.DEPTH_TEST),t.blend&&t.realEnable.call(e,e.BLEND),t.scissorTest&&t.realEnable.call(e,e.SCISSOR_TEST),t.stencilTest&&t.realEnable.call(e,e.STENCIL_TEST),t.realColorMask.apply(e,t.colorMask),t.realViewport.apply(e,t.viewport),!t.ctxAttribs.alpha&&t.ctxAttribs.preserveDrawingBuffer||t.realClearColor.apply(e,t.clearColor)}),o()){var r=e.canvas;r.width==t.bufferWidth&&r.height==t.bufferHeight||(t.bufferWidth=r.width,t.bufferHeight=r.height,t.onResize())}},T.prototype.updateDeviceInfo=function(e){var t=this.gl,i=this,r=[t.ARRAY_BUFFER_BINDING,t.ELEMENT_ARRAY_BUFFER_BINDING];_(t,r,function(t){var r=i.computeMeshVertices_(i.meshWidth,i.meshHeight,e);if(t.bindBuffer(t.ARRAY_BUFFER,i.vertexBuffer),t.bufferData(t.ARRAY_BUFFER,r,t.STATIC_DRAW),!i.indexCount){var s=i.computeMeshIndices_(i.meshWidth,i.meshHeight);t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,i.indexBuffer),t.bufferData(t.ELEMENT_ARRAY_BUFFER,s,t.STATIC_DRAW),i.indexCount=s.length}})},T.prototype.computeMeshVertices_=function(e,t,i){for(var r=new Float32Array(2*e*t*5),s=i.getLeftEyeVisibleTanAngles(),n=i.getLeftEyeNoLensTanAngles(),o=i.getLeftEyeVisibleScreenRect(n),l=0,A=0;A<2;A++){for(var h=0;hs-42&&r.clientXi.clientHeight-42?e(r):r.clientX<42&&r.clientY<42&&t(r)},i.addEventListener("click",this.listener,!1)},I.prototype.onResize=function(){var e=this.gl,t=this,i=[e.ARRAY_BUFFER_BINDING];_(e,i,function(e){var i=[],r=e.drawingBufferWidth/2,s=Math.max(screen.width,screen.height)*window.devicePixelRatio,n=e.drawingBufferWidth/s,a=n*window.devicePixelRatio,o=4*a/2,l=42*a,A=28*a/2,h=14*a;function c(e,t){var s=(90-e)*C,n=Math.cos(s),a=Math.sin(s);i.push(D*n*A+r,D*a*A+A),i.push(t*n*A+r,t*a*A+A)}i.push(r-o,l),i.push(r-o,e.drawingBufferHeight),i.push(r+o,l),i.push(r+o,e.drawingBufferHeight),t.gearOffset=i.length/2;for(var d=0;d<=6;d++){var u=60*d;c(u,1),c(u+12,1),c(u+20,.75),c(u+40,.75),c(u+48,1)}function p(t,r){i.push(h+t,e.drawingBufferHeight-h-r)}t.gearVertexCount=i.length/2-t.gearOffset,t.arrowOffset=i.length/2;var f=o/Math.sin(45*C);p(0,A),p(A,0),p(A+f,f),p(f,A+f),p(f,A-f),p(0,A),p(A,2*A),p(A+f,2*A-f),p(f,A-f),p(0,A),p(f,A-o),p(28*a,A-o),p(f,A+o),p(28*a,A+o),t.arrowVertexCount=i.length/2-t.arrowOffset,e.bindBuffer(e.ARRAY_BUFFER,t.vertexBuffer),e.bufferData(e.ARRAY_BUFFER,new Float32Array(i),e.STATIC_DRAW)})},I.prototype.render=function(){var e=this.gl,t=this,i=[e.CULL_FACE,e.DEPTH_TEST,e.BLEND,e.SCISSOR_TEST,e.STENCIL_TEST,e.COLOR_WRITEMASK,e.VIEWPORT,e.CURRENT_PROGRAM,e.ARRAY_BUFFER_BINDING];_(e,i,function(e){e.disable(e.CULL_FACE),e.disable(e.DEPTH_TEST),e.disable(e.BLEND),e.disable(e.SCISSOR_TEST),e.disable(e.STENCIL_TEST),e.colorMask(!0,!0,!0,!0),e.viewport(0,0,e.drawingBufferWidth,e.drawingBufferHeight),t.renderNoState()})},I.prototype.renderNoState=function(){var e,t,i,r,s,n,a,o,l,A,h=this.gl;h.useProgram(this.program),h.bindBuffer(h.ARRAY_BUFFER,this.vertexBuffer),h.enableVertexAttribArray(this.attribs.position),h.vertexAttribPointer(this.attribs.position,2,h.FLOAT,!1,8,0),h.uniform4f(this.uniforms.color,1,1,1,1),e=this.projMat,t=0,i=h.drawingBufferWidth,r=0,s=h.drawingBufferHeight,o=1/(t-i),l=1/(r-s),A=1/((n=.1)-(a=1024)),e[0]=-2*o,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=-2*l,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=2*A,e[11]=0,e[12]=(t+i)*o,e[13]=(s+r)*l,e[14]=(a+n)*A,e[15]=1,h.uniformMatrix4fv(this.uniforms.projectionMat,!1,this.projMat),h.drawArrays(h.TRIANGLE_STRIP,0,4),h.drawArrays(h.TRIANGLE_STRIP,this.gearOffset,this.gearVertexCount),h.drawArrays(h.TRIANGLE_STRIP,this.arrowOffset,this.arrowVertexCount)},L.prototype.distortInverse=function(e){for(var t=0,i=1,r=e-this.distort(t);Math.abs(i-t)>1e-4;){var s=e-this.distort(i),n=i-s*((i-t)/(s-r));t=i,i=n,r=s}return i},L.prototype.distort=function(e){for(var t=e*e,i=0,r=0;r=1)return this.w=n,this.x=i,this.y=r,this.z=s,this;var o=Math.acos(a),l=Math.sqrt(1-a*a);if(Math.abs(l)<.001)return this.w=.5*(n+this.w),this.x=.5*(i+this.x),this.y=.5*(r+this.y),this.z=.5*(s+this.z),this;var A=Math.sin((1-t)*o)/l,h=Math.sin(t*o)/l;return this.w=n*A+this.w*h,this.x=i*A+this.x*h,this.y=r*A+this.y*h,this.z=s*A+this.z*h,this},setFromUnitVectors:function(e,t){return void 0===Q&&(Q=new G),(k=e.dot(t)+1)<1e-6?(k=0,Math.abs(e.x)>Math.abs(e.z)?Q.set(-e.y,e.x,0):Q.set(0,-e.z,e.y)):Q.crossVectors(e,t),this.x=Q.x,this.y=Q.y,this.z=Q.z,this.w=k,this.normalize(),this}};var V=new U({widthMeters:.11,heightMeters:.062,bevelMeters:.004}),H=new U({widthMeters:.1038,heightMeters:.0584,bevelMeters:.004}),X={CardboardV1:new j({id:"CardboardV1",label:"Cardboard I/O 2014",fov:40,interLensDistance:.06,baselineLensDistance:.035,screenLensDistance:.042,distortionCoefficients:[.441,.156],inverseCoefficients:[-.4410035,.42756155,-.4804439,.5460139,-.58821183,.5733938,-.48303202,.33299083,-.17573841,.0651772,-.01488963,.001559834]}),CardboardV2:new j({id:"CardboardV2",label:"Cardboard I/O 2015",fov:60,interLensDistance:.064,baselineLensDistance:.035,screenLensDistance:.039,distortionCoefficients:[.34,.55],inverseCoefficients:[-.33836704,-.18162185,.862655,-1.2462051,1.0560602,-.58208317,.21609078,-.05444823,.009177956,-.0009904169,6183535e-11,-16981803e-13]})};function W(e,t){this.viewer=X.CardboardV2,this.updateDeviceParams(e),this.distortion=new L(this.viewer.distortionCoefficients);for(var i=0;i=200&&i.status<=299?(r.dpdb=JSON.parse(i.response),r.recalculateDeviceParams_()):console.error("Error loading online DPDB!")}),i.send()}}function Z(e){this.xdpi=e.xdpi,this.ydpi=e.ydpi,this.bevelMm=e.bevelMm}function J(e,t){this.set(e,t)}function K(e,t){this.kFilter=e,this.isDebug=t,this.currentAccelMeasurement=new J,this.currentGyroMeasurement=new J,this.previousGyroMeasurement=new J,o()?this.filterQ=new z(-1,0,0,1):this.filterQ=new z(1,0,0,1),this.previousFilterQ=new z,this.previousFilterQ.copy(this.filterQ),this.accelQ=new z,this.isOrientationInitialized=!1,this.estimatedGravity=new G,this.measuredGravity=new G,this.gyroIntegralQ=new z}function $(e,t){this.predictionTimeS=e,this.isDebug=t,this.previousQ=new z,this.previousTimestampS=null,this.deltaQ=new z,this.outQ=new z}function ee(e,t,i,r){this.yawOnly=i,this.accelerometer=new G,this.gyroscope=new G,this.filter=new K(e,r),this.posePredictor=new $(t,r),this.isFirefoxAndroid=A(),this.isIOS=o();var s=h();this.isDeviceMotionInRadians=!this.isIOS&&s&&s<66,this.isWithoutDeviceMotion=c(),this.filterToWorldQ=new z,o()?this.filterToWorldQ.setFromAxisAngle(new G(1,0,0),Math.PI/2):this.filterToWorldQ.setFromAxisAngle(new G(1,0,0),-Math.PI/2),this.inverseWorldToScreenQ=new z,this.worldToScreenQ=new z,this.originalPoseAdjustQ=new z,this.originalPoseAdjustQ.setFromAxisAngle(new G(0,0,1),-window.orientation*Math.PI/180),this.setScreenTransform_(),u()&&this.filterToWorldQ.multiply(this.inverseWorldToScreenQ),this.resetQ=new z,this.orientationOut_=new Float32Array(4),this.start()}Y.prototype.getDeviceParams=function(){return this.deviceParams},Y.prototype.recalculateDeviceParams_=function(){var e=this.calcDeviceParams_();e?(this.deviceParams=e,this.onDeviceParamsUpdated&&this.onDeviceParamsUpdated(this.deviceParams)):console.error("Failed to recalculate device parameters.")},Y.prototype.calcDeviceParams_=function(){var e=this.dpdb;if(!e)return console.error("DPDB not available."),null;if(1!=e.format)return console.error("DPDB has unexpected format version."),null;if(!e.devices||!e.devices.length)return console.error("DPDB does not have a devices section."),null;var t=navigator.userAgent||navigator.vendor||window.opera,i=p(),r=f();if(!e.devices)return console.error("DPDB has no devices section."),null;for(var s=0;s1)&&this.run_(),this.previousGyroMeasurement.copy(this.currentGyroMeasurement)},K.prototype.run_=function(){if(!this.isOrientationInitialized)return this.accelQ=this.accelToQuaternion_(this.currentAccelMeasurement.sample),this.previousFilterQ.copy(this.accelQ),void(this.isOrientationInitialized=!0);var e=this.currentGyroMeasurement.timestampS-this.previousGyroMeasurement.timestampS,t=this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample,e);this.gyroIntegralQ.multiply(t),this.filterQ.copy(this.previousFilterQ),this.filterQ.multiply(t);var i=new z;i.copy(this.filterQ),i.inverse(),this.estimatedGravity.set(0,0,-1),this.estimatedGravity.applyQuaternion(i),this.estimatedGravity.normalize(),this.measuredGravity.copy(this.currentAccelMeasurement.sample),this.measuredGravity.normalize();var r,s=new z;s.setFromUnitVectors(this.estimatedGravity,this.measuredGravity),s.inverse(),this.isDebug&&console.log("Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)",N*((r=s).w>1?(console.warn("getQuaternionAngle: w > 1"),0):2*Math.acos(r.w)),this.estimatedGravity.x.toFixed(1),this.estimatedGravity.y.toFixed(1),this.estimatedGravity.z.toFixed(1),this.measuredGravity.x.toFixed(1),this.measuredGravity.y.toFixed(1),this.measuredGravity.z.toFixed(1));var n=new z;n.copy(this.filterQ),n.multiply(s),this.filterQ.slerp(n,1-this.kFilter),this.previousFilterQ.copy(this.filterQ)},K.prototype.getOrientation=function(){return this.filterQ},K.prototype.accelToQuaternion_=function(e){var t=new G;t.copy(e),t.normalize();var i=new z;return i.setFromUnitVectors(new G(0,0,-1),t),i.inverse(),i},K.prototype.gyroToQuaternionDelta_=function(e,t){var i=new z,r=new G;return r.copy(e),r.normalize(),i.setFromAxisAngle(r,e.length()*t),i},$.prototype.getPrediction=function(e,t,i){if(!this.previousTimestampS)return this.previousQ.copy(e),this.previousTimestampS=i,e;var r=new G;r.copy(t),r.normalize();var s=t.length();if(s<20*O)return this.isDebug&&console.log("Moving slowly, at %s deg/s: no prediction",(N*s).toFixed(1)),this.outQ.copy(e),this.previousQ.copy(e),this.outQ;var n=s*this.predictionTimeS;return this.deltaQ.setFromAxisAngle(r,n),this.outQ.copy(this.previousQ),this.outQ.multiply(this.deltaQ),this.previousQ.copy(e),this.previousTimestampS=i,this.outQ},ee.prototype.getPosition=function(){return null},ee.prototype.getOrientation=function(){var e=void 0;if(this.isWithoutDeviceMotion&&this._deviceOrientationQ){this.deviceOrientationFixQ=this.deviceOrientationFixQ||(r=(new z).setFromAxisAngle(new G(0,0,-1),0),s=new z,-90===window.orientation?s.setFromAxisAngle(new G(0,1,0),Math.PI/-2):s.setFromAxisAngle(new G(0,1,0),Math.PI/2),r.multiply(s)),this.deviceOrientationFilterToWorldQ=this.deviceOrientationFilterToWorldQ||((i=new z).setFromAxisAngle(new G(1,0,0),-Math.PI/2),i),e=this._deviceOrientationQ;var t=new z;return t.copy(e),t.multiply(this.deviceOrientationFilterToWorldQ),t.multiply(this.resetQ),t.multiply(this.worldToScreenQ),t.multiplyQuaternions(this.deviceOrientationFixQ,t),this.yawOnly&&(t.x=0,t.z=0,t.normalize()),this.orientationOut_[0]=t.x,this.orientationOut_[1]=t.y,this.orientationOut_[2]=t.z,this.orientationOut_[3]=t.w,this.orientationOut_}var i,r,s,n=this.filter.getOrientation();e=this.posePredictor.getPrediction(n,this.gyroscope,this.previousTimestampS);var t=new z;return t.copy(this.filterToWorldQ),t.multiply(this.resetQ),t.multiply(e),t.multiply(this.worldToScreenQ),this.yawOnly&&(t.x=0,t.z=0,t.normalize()),this.orientationOut_[0]=t.x,this.orientationOut_[1]=t.y,this.orientationOut_[2]=t.z,this.orientationOut_[3]=t.w,this.orientationOut_},ee.prototype.resetPose=function(){this.resetQ.copy(this.filter.getOrientation()),this.resetQ.x=0,this.resetQ.y=0,this.resetQ.z*=-1,this.resetQ.normalize(),u()&&this.resetQ.multiply(this.inverseWorldToScreenQ),this.resetQ.multiply(this.originalPoseAdjustQ)},ee.prototype.onDeviceOrientation_=function(e){this._deviceOrientationQ=this._deviceOrientationQ||new z;var t=e.alpha,i=e.beta,r=e.gamma;t=(t||0)*Math.PI/180,i=(i||0)*Math.PI/180,r=(r||0)*Math.PI/180,this._deviceOrientationQ.setFromEulerYXZ(i,t,-r)},ee.prototype.onDeviceMotion_=function(e){this.updateDeviceMotion_(e)},ee.prototype.updateDeviceMotion_=function(e){var t=e.accelerationIncludingGravity,i=e.rotationRate,r=e.timeStamp/1e3,s=r-this.previousTimestampS;return s<0?(M("fusion-pose-sensor:invalid:non-monotonic","Invalid timestamps detected: non-monotonic timestamp from devicemotion"),void(this.previousTimestampS=r)):s<=.001||s>1?(M("fusion-pose-sensor:invalid:outside-threshold","Invalid timestamps detected: Timestamp from devicemotion outside expected range."),void(this.previousTimestampS=r)):(this.accelerometer.set(-t.x,-t.y,-t.z),d()?this.gyroscope.set(-i.beta,i.alpha,i.gamma):this.gyroscope.set(i.alpha,i.beta,i.gamma),this.isDeviceMotionInRadians||this.gyroscope.multiplyScalar(Math.PI/180),this.filter.addAccelMeasurement(this.accelerometer,r),this.filter.addGyroMeasurement(this.gyroscope,r),void(this.previousTimestampS=r))},ee.prototype.onOrientationChange_=function(e){this.setScreenTransform_()},ee.prototype.onMessage_=function(e){var t=e.data;if(t&&t.type){var i=t.type.toLowerCase();"devicemotion"===i&&this.updateDeviceMotion_(t.deviceMotionEvent)}},ee.prototype.setScreenTransform_=function(){switch(this.worldToScreenQ.set(0,0,0,1),window.orientation){case 0:break;case 90:this.worldToScreenQ.setFromAxisAngle(new G(0,0,1),-Math.PI/2);break;case-90:this.worldToScreenQ.setFromAxisAngle(new G(0,0,1),Math.PI/2)}this.inverseWorldToScreenQ.copy(this.worldToScreenQ),this.inverseWorldToScreenQ.inverse()},ee.prototype.start=function(){var e,t,i;this.onDeviceMotionCallback_=this.onDeviceMotion_.bind(this),this.onOrientationChangeCallback_=this.onOrientationChange_.bind(this),this.onMessageCallback_=this.onMessage_.bind(this),this.onDeviceOrientationCallback_=this.onDeviceOrientation_.bind(this),o()&&(e=window.self!==window.top,t=S(document.referrer),i=S(window.location.href),e&&t!==i)&&window.addEventListener("message",this.onMessageCallback_),window.addEventListener("orientationchange",this.onOrientationChangeCallback_),this.isWithoutDeviceMotion?window.addEventListener("deviceorientation",this.onDeviceOrientationCallback_):window.addEventListener("devicemotion",this.onDeviceMotionCallback_)},ee.prototype.stop=function(){window.removeEventListener("devicemotion",this.onDeviceMotionCallback_),window.removeEventListener("deviceorientation",this.onDeviceOrientationCallback_),window.removeEventListener("orientationchange",this.onOrientationChangeCallback_),window.removeEventListener("message",this.onMessageCallback_)};var te=new G(1,0,0),ie=new G(0,0,1),re=new z;re.setFromAxisAngle(te,-Math.PI/2),re.multiply((new z).setFromAxisAngle(ie,Math.PI/2));var se=function(){function e(t){r(this,e),this.config=t,this.sensor=null,this.fusionSensor=null,this._out=new Float32Array(4),this.api=null,this.errors=[],this._sensorQ=new z,this._outQ=new z,this._onSensorRead=this._onSensorRead.bind(this),this._onSensorError=this._onSensorError.bind(this),this.init()}return s(e,[{key:"init",value:function(){var e=null;try{(e=new RelativeOrientationSensor({frequency:60,referenceFrame:"screen"})).addEventListener("error",this._onSensorError)}catch(e){this.errors.push(e),"SecurityError"===e.name?(console.error("Cannot construct sensors due to the Feature Policy"),console.warn('Attempting to fall back using "devicemotion"; however this will fail in the future without correct permissions.'),this.useDeviceMotion()):"ReferenceError"===e.name?this.useDeviceMotion():console.error(e)}e&&(this.api="sensor",this.sensor=e,this.sensor.addEventListener("reading",this._onSensorRead),this.sensor.start())}},{key:"useDeviceMotion",value:function(){this.api="devicemotion",this.fusionSensor=new ee(this.config.K_FILTER,this.config.PREDICTION_TIME_S,this.config.YAW_ONLY,this.config.DEBUG),this.sensor&&(this.sensor.removeEventListener("reading",this._onSensorRead),this.sensor.removeEventListener("error",this._onSensorError),this.sensor=null)}},{key:"getOrientation",value:function(){if(this.fusionSensor)return this.fusionSensor.getOrientation();if(!this.sensor||!this.sensor.quaternion)return this._out[0]=this._out[1]=this._out[2]=0,this._out[3]=1,this._out;var e=this.sensor.quaternion;this._sensorQ.set(e[0],e[1],e[2],e[3]);var t=this._outQ;return t.copy(re),t.multiply(this._sensorQ),this.config.YAW_ONLY&&(t.x=t.z=0,t.normalize()),this._out[0]=t.x,this._out[1]=t.y,this._out[2]=t.z,this._out[3]=t.w,this._out}},{key:"_onSensorError",value:function(e){this.errors.push(e.error),"NotAllowedError"===e.error.name?console.error("Permission to access sensor was denied"):"NotReadableError"===e.error.name?console.error("Sensor could not be read"):console.error(e.error),this.useDeviceMotion()}},{key:"_onSensorRead",value:function(){}}]),e}();function ne(){this.loadIcon_();var e=document.createElement("div"),t=e.style;t.position="fixed",t.top=0,t.right=0,t.bottom=0,t.left=0,t.backgroundColor="gray",t.fontFamily="sans-serif",t.zIndex=1e6;var i=document.createElement("img");i.src=this.icon;var t=i.style;t.marginLeft="25%",t.marginTop="25%",t.width="50%",e.appendChild(i);var r=document.createElement("div"),t=r.style;t.textAlign="center",t.fontSize="16px",t.lineHeight="24px",t.margin="24px 25%",t.width="50%",r.innerHTML="Place your phone into your Cardboard viewer.",e.appendChild(r);var s=document.createElement("div"),t=s.style;t.backgroundColor="#CFD8DC",t.position="fixed",t.bottom=0,t.width="100%",t.height="48px",t.padding="14px 24px",t.boxSizing="border-box",t.color="#656A6B",e.appendChild(s);var n=document.createElement("div");n.style.float="left",n.innerHTML="No Cardboard viewer?";var a=document.createElement("a");a.href="https://www.google.com/get/cardboard/get-cardboard/",a.innerHTML="get one",a.target="_blank";var t=a.style;t.float="right",t.fontWeight=600,t.textTransform="uppercase",t.borderLeft="1px solid gray",t.paddingLeft="24px",t.textDecoration="none",t.color="#656A6B",s.appendChild(n),s.appendChild(a),this.overlay=e,this.text=r,this.hide()}ne.prototype.show=function(e){e||this.overlay.parentElement?e&&(this.overlay.parentElement&&this.overlay.parentElement!=e&&this.overlay.parentElement.removeChild(this.overlay),e.appendChild(this.overlay)):document.body.appendChild(this.overlay),this.overlay.style.display="block";var t=this.overlay.querySelector("img"),i=t.style;u()?(i.width="20%",i.marginLeft="40%",i.marginTop="3%"):(i.width="50%",i.marginLeft="25%",i.marginTop="25%")},ne.prototype.hide=function(){this.overlay.style.display="none"},ne.prototype.showTemporarily=function(e,t){this.show(t),this.timer=setTimeout(this.hide.bind(this),e)},ne.prototype.disableShowTemporarily=function(){clearTimeout(this.timer)},ne.prototype.update=function(){this.disableShowTemporarily(),!u()&&w()?this.show():this.hide()},ne.prototype.loadIcon_=function(){this.icon="data:image/svg+xml,"+encodeURIComponent("")};var ae="CardboardV1",oe="WEBVR_CARDBOARD_VIEWER";function le(e){try{this.selectedKey=localStorage.getItem(oe)}catch(e){console.error("Failed to load viewer profile: %s",e)}this.selectedKey||(this.selectedKey=e||ae),this.dialog=this.createDialog_(W.Viewers),this.root=null,this.onChangeCallbacks_=[]}le.prototype.show=function(e){this.root=e,e.appendChild(this.dialog);var t=this.dialog.querySelector("#"+this.selectedKey);t.checked=!0,this.dialog.style.display="block"},le.prototype.hide=function(){this.root&&this.root.contains(this.dialog)&&this.root.removeChild(this.dialog),this.dialog.style.display="none"},le.prototype.getCurrentViewer=function(){return W.Viewers[this.selectedKey]},le.prototype.getSelectedKey_=function(){var e=this.dialog.querySelector("input[name=field]:checked");return e?e.id:null},le.prototype.onChange=function(e){this.onChangeCallbacks_.push(e)},le.prototype.fireOnChange_=function(e){for(var t=0;t.5&&(this.noSleepVideo.currentTime=Math.random())}.bind(this)))}return r(e,[{key:"enable",value:function(){n?(this.disable(),this.noSleepTimer=window.setInterval(function(){window.location.href="/",window.setTimeout(window.stop,0)},15e3)):this.noSleepVideo.play()}},{key:"disable",value:function(){n?this.noSleepTimer&&(window.clearInterval(this.noSleepTimer),this.noSleepTimer=null):this.noSleepVideo.pause()}}]),e}();e.exports=a},function(e,t,i){e.exports="data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA="}])},e.exports=i()}(he={exports:{}},he.exports),(Ae=he.exports)&&Ae.__esModule&&Object.prototype.hasOwnProperty.call(Ae,"default")?Ae.default:Ae),de=1e3,ue=[0,0,.5,1],pe=[.5,0,.5,1],fe=window.requestAnimationFrame,me=window.cancelAnimationFrame;function ge(e){Object.defineProperties(this,{hasPosition:{writable:!1,enumerable:!0,value:e.hasPosition},hasExternalDisplay:{writable:!1,enumerable:!0,value:e.hasExternalDisplay},canPresent:{writable:!1,enumerable:!0,value:e.canPresent},maxLayers:{writable:!1,enumerable:!0,value:e.maxLayers},hasOrientation:{enumerable:!0,get:function(){return x("VRDisplayCapabilities.prototype.hasOrientation","VRDisplay.prototype.getFrameData"),e.hasOrientation}}})}function ve(e){var t=!("wakelock"in(e=e||{}))||e.wakelock;this.isPolyfilled=!0,this.displayId=de++,this.displayName="",this.depthNear=.01,this.depthFar=1e4,this.isPresenting=!1,Object.defineProperty(this,"isConnected",{get:function(){return x("VRDisplay.prototype.isConnected","VRDisplayCapabilities.prototype.hasExternalDisplay"),!1}}),this.capabilities=new ge({hasPosition:!1,hasOrientation:!1,hasExternalDisplay:!1,canPresent:!1,maxLayers:1}),this.stageParameters=null,this.waitingForPresent_=!1,this.layer_=null,this.originalParent_=null,this.fullscreenElement_=null,this.fullscreenWrapper_=null,this.fullscreenElementCachedStyle_=null,this.fullscreenEventTarget_=null,this.fullscreenChangeHandler_=null,this.fullscreenErrorHandler_=null,t&&w()&&(this.wakelock_=new ce)}ve.prototype.getFrameData=function(e){return E(e,this._getPose(),this)},ve.prototype.getPose=function(){return x("VRDisplay.prototype.getPose","VRDisplay.prototype.getFrameData"),this._getPose()},ve.prototype.resetPose=function(){return x("VRDisplay.prototype.resetPose"),this._resetPose()},ve.prototype.getImmediatePose=function(){return x("VRDisplay.prototype.getImmediatePose","VRDisplay.prototype.getFrameData"),this._getPose()},ve.prototype.requestAnimationFrame=function(e){return fe(e)},ve.prototype.cancelAnimationFrame=function(e){return me(e)},ve.prototype.wrapForFullscreen=function(e){if(o())return e;if(!this.fullscreenWrapper_){this.fullscreenWrapper_=document.createElement("div");var t=["height: "+Math.min(screen.height,screen.width)+"px !important","top: 0 !important","left: 0 !important","right: 0 !important","border: 0","margin: 0","padding: 0","z-index: 999999 !important","position: fixed"];this.fullscreenWrapper_.setAttribute("style",t.join("; ")+";"),this.fullscreenWrapper_.classList.add("webvr-polyfill-fullscreen-wrapper")}if(this.fullscreenElement_==e)return this.fullscreenWrapper_;if(this.fullscreenElement_&&(this.originalParent_?this.originalParent_.appendChild(this.fullscreenElement_):this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_)),this.fullscreenElement_=e,this.originalParent_=e.parentElement,this.originalParent_||document.body.appendChild(e),!this.fullscreenWrapper_.parentElement){var i=this.fullscreenElement_.parentElement;i.insertBefore(this.fullscreenWrapper_,this.fullscreenElement_),i.removeChild(this.fullscreenElement_)}this.fullscreenWrapper_.insertBefore(this.fullscreenElement_,this.fullscreenWrapper_.firstChild),this.fullscreenElementCachedStyle_=this.fullscreenElement_.getAttribute("style");var r=this;return function(){if(r.fullscreenElement_){var e=["position: absolute","top: 0","left: 0","width: "+Math.max(screen.width,screen.height)+"px","height: "+Math.min(screen.height,screen.width)+"px","border: 0","margin: 0","padding: 0"];r.fullscreenElement_.setAttribute("style",e.join("; ")+";")}}(),this.fullscreenWrapper_},ve.prototype.removeFullscreenWrapper=function(){if(this.fullscreenElement_){var e=this.fullscreenElement_;this.fullscreenElementCachedStyle_?e.setAttribute("style",this.fullscreenElementCachedStyle_):e.removeAttribute("style"),this.fullscreenElement_=null,this.fullscreenElementCachedStyle_=null;var t=this.fullscreenWrapper_.parentElement;return this.fullscreenWrapper_.removeChild(e),this.originalParent_===t?t.insertBefore(e,this.fullscreenWrapper_):this.originalParent_&&this.originalParent_.appendChild(e),t.removeChild(this.fullscreenWrapper_),e}},ve.prototype.requestPresent=function(e){var t=this.isPresenting,i=this;return e instanceof Array||(x("VRDisplay.prototype.requestPresent with non-array argument","an array of VRLayers as the first argument"),e=[e]),new Promise(function(r,s){if(i.capabilities.canPresent)if(0==e.length||e.length>i.capabilities.maxLayers)s(new Error("Invalid number of layers."));else{var n=e[0];if(n.source){var a=n.leftBounds||ue,A=n.rightBounds||pe;if(t){var h=i.layer_;h.source!==n.source&&(h.source=n.source);for(var c=0;c<4;c++)h.leftBounds[c]=a[c],h.rightBounds[c]=A[c];return i.wrapForFullscreen(i.layer_.source),i.updatePresent_(),void r()}if(i.layer_={predistorted:n.predistorted,source:n.source,leftBounds:a.slice(0),rightBounds:A.slice(0)},i.waitingForPresent_=!1,i.layer_&&i.layer_.source){var d=i.wrapForFullscreen(i.layer_.source);i.addFullscreenListeners_(d,function(){var e=document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement;i.isPresenting=d===e,i.isPresenting?(screen.orientation&&screen.orientation.lock&&screen.orientation.lock("landscape-primary").catch(function(e){console.error("screen.orientation.lock() failed due to",e.message)}),i.waitingForPresent_=!1,i.beginPresent_(),r()):(screen.orientation&&screen.orientation.unlock&&screen.orientation.unlock(),i.removeFullscreenWrapper(),i.disableWakeLock(),i.endPresent_(),i.removeFullscreenListeners_()),i.fireVRDisplayPresentChange_()},function(){i.waitingForPresent_&&(i.removeFullscreenWrapper(),i.removeFullscreenListeners_(),i.disableWakeLock(),i.waitingForPresent_=!1,i.isPresenting=!1,s(new Error("Unable to present.")))}),function(e){if(l())return!1;if(e.requestFullscreen)e.requestFullscreen();else if(e.webkitRequestFullscreen)e.webkitRequestFullscreen();else if(e.mozRequestFullScreen)e.mozRequestFullScreen();else{if(!e.msRequestFullscreen)return!1;e.msRequestFullscreen()}return!0}(d)?(i.enableWakeLock(),i.waitingForPresent_=!0):(o()||l())&&(i.enableWakeLock(),i.isPresenting=!0,i.beginPresent_(),i.fireVRDisplayPresentChange_(),r())}i.waitingForPresent_||o()||(m(),s(new Error("Unable to present.")))}else r()}else s(new Error("VRDisplay is not capable of presenting."))})},ve.prototype.exitPresent=function(){var e=this.isPresenting,t=this;return this.isPresenting=!1,this.layer_=null,this.disableWakeLock(),new Promise(function(i,r){e?(!m()&&o()&&(t.endPresent_(),t.fireVRDisplayPresentChange_()),l()&&(t.removeFullscreenWrapper(),t.removeFullscreenListeners_(),t.endPresent_(),t.fireVRDisplayPresentChange_()),i()):r(new Error("Was not presenting to VRDisplay."))})},ve.prototype.getLayers=function(){return this.layer_?[this.layer_]:[]},ve.prototype.fireVRDisplayPresentChange_=function(){var e=new CustomEvent("vrdisplaypresentchange",{detail:{display:this}});window.dispatchEvent(e)},ve.prototype.fireVRDisplayConnect_=function(){var e=new CustomEvent("vrdisplayconnect",{detail:{display:this}});window.dispatchEvent(e)},ve.prototype.addFullscreenListeners_=function(e,t,i){this.removeFullscreenListeners_(),this.fullscreenEventTarget_=e,this.fullscreenChangeHandler_=t,this.fullscreenErrorHandler_=i,t&&(document.fullscreenEnabled?e.addEventListener("fullscreenchange",t,!1):document.webkitFullscreenEnabled?e.addEventListener("webkitfullscreenchange",t,!1):document.mozFullScreenEnabled?document.addEventListener("mozfullscreenchange",t,!1):document.msFullscreenEnabled&&e.addEventListener("msfullscreenchange",t,!1)),i&&(document.fullscreenEnabled?e.addEventListener("fullscreenerror",i,!1):document.webkitFullscreenEnabled?e.addEventListener("webkitfullscreenerror",i,!1):document.mozFullScreenEnabled?document.addEventListener("mozfullscreenerror",i,!1):document.msFullscreenEnabled&&e.addEventListener("msfullscreenerror",i,!1))},ve.prototype.removeFullscreenListeners_=function(){if(this.fullscreenEventTarget_){var e=this.fullscreenEventTarget_;if(this.fullscreenChangeHandler_){var t=this.fullscreenChangeHandler_;e.removeEventListener("fullscreenchange",t,!1),e.removeEventListener("webkitfullscreenchange",t,!1),document.removeEventListener("mozfullscreenchange",t,!1),e.removeEventListener("msfullscreenchange",t,!1)}if(this.fullscreenErrorHandler_){var i=this.fullscreenErrorHandler_;e.removeEventListener("fullscreenerror",i,!1),e.removeEventListener("webkitfullscreenerror",i,!1),document.removeEventListener("mozfullscreenerror",i,!1),e.removeEventListener("msfullscreenerror",i,!1)}this.fullscreenEventTarget_=null,this.fullscreenChangeHandler_=null,this.fullscreenErrorHandler_=null}},ve.prototype.enableWakeLock=function(){this.wakelock_&&this.wakelock_.enable()},ve.prototype.disableWakeLock=function(){this.wakelock_&&this.wakelock_.disable()},ve.prototype.beginPresent_=function(){},ve.prototype.endPresent_=function(){},ve.prototype.submitFrame=function(e){},ve.prototype.getEyeParameters=function(e){return null};var we={ADDITIONAL_VIEWERS:[],DEFAULT_VIEWER:"",MOBILE_WAKE_LOCK:!0,DEBUG:!1,DPDB_URL:"https://dpdb.webvr.rocks/dpdb.json",K_FILTER:.98,PREDICTION_TIME_S:.04,CARDBOARD_UI_DISABLED:!1,ROTATE_INSTRUCTIONS_DISABLED:!1,YAW_ONLY:!1,BUFFER_SCALE:.5,DIRTY_SUBMIT_FRAME_BINDINGS:!1},ye={LEFT:"left",RIGHT:"right"};function be(e){var t=y({},we);e=y(t,e||{}),ve.call(this,{wakelock:e.MOBILE_WAKE_LOCK}),this.config=e,this.displayName="Cardboard VRDisplay",this.capabilities=new ge({hasPosition:!1,hasOrientation:!0,hasExternalDisplay:!1,canPresent:!0,maxLayers:1}),this.stageParameters=null,this.bufferScale_=this.config.BUFFER_SCALE,this.poseSensor_=new se(this.config),this.distorter_=null,this.cardboardUI_=null,this.dpdb_=new Y(this.config.DPDB_URL,this.onDeviceParamsUpdated_.bind(this)),this.deviceInfo_=new W(this.dpdb_.getDeviceParams(),e.ADDITIONAL_VIEWERS),this.viewerSelector_=new le(e.DEFAULT_VIEWER),this.viewerSelector_.onChange(this.onViewerChanged_.bind(this)),this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer()),this.config.ROTATE_INSTRUCTIONS_DISABLED||(this.rotateInstructions_=new ne),o()&&window.addEventListener("resize",this.onResize_.bind(this))}return be.prototype=Object.create(ve.prototype),be.prototype._getPose=function(){return{position:null,orientation:this.poseSensor_.getOrientation(),linearVelocity:null,linearAcceleration:null,angularVelocity:null,angularAcceleration:null}},be.prototype._resetPose=function(){this.poseSensor_.resetPose&&this.poseSensor_.resetPose()},be.prototype._getFieldOfView=function(e){var t;if(e==ye.LEFT)t=this.deviceInfo_.getFieldOfViewLeftEye();else{if(e!=ye.RIGHT)return console.error("Invalid eye provided: %s",e),null;t=this.deviceInfo_.getFieldOfViewRightEye()}return t},be.prototype._getEyeOffset=function(e){var t;if(e==ye.LEFT)t=[.5*-this.deviceInfo_.viewer.interLensDistance,0,0];else{if(e!=ye.RIGHT)return console.error("Invalid eye provided: %s",e),null;t=[.5*this.deviceInfo_.viewer.interLensDistance,0,0]}return t},be.prototype.getEyeParameters=function(e){var t=this._getEyeOffset(e),i=this._getFieldOfView(e),r={offset:t,renderWidth:.5*this.deviceInfo_.device.width*this.bufferScale_,renderHeight:this.deviceInfo_.device.height*this.bufferScale_};return Object.defineProperty(r,"fieldOfView",{enumerable:!0,get:function(){return x("VRFieldOfView","VRFrameData's projection matrices"),i}}),r},be.prototype.onDeviceParamsUpdated_=function(e){this.config.DEBUG&&console.log("DPDB reported that device params were updated."),this.deviceInfo_.updateDeviceParams(e),this.distorter_&&this.distorter_.updateDeviceInfo(this.deviceInfo_)},be.prototype.updateBounds_=function(){this.layer_&&this.distorter_&&(this.layer_.leftBounds||this.layer_.rightBounds)&&this.distorter_.setTextureBounds(this.layer_.leftBounds,this.layer_.rightBounds)},be.prototype.beginPresent_=function(){var e=this.layer_.source.getContext("webgl");e||(e=this.layer_.source.getContext("experimental-webgl")),e||(e=this.layer_.source.getContext("webgl2")),e&&(this.layer_.predistorted?this.config.CARDBOARD_UI_DISABLED||(e.canvas.width=p()*this.bufferScale_,e.canvas.height=f()*this.bufferScale_,this.cardboardUI_=new I(e)):(this.config.CARDBOARD_UI_DISABLED||(this.cardboardUI_=new I(e)),this.distorter_=new T(e,this.cardboardUI_,this.config.BUFFER_SCALE,this.config.DIRTY_SUBMIT_FRAME_BINDINGS),this.distorter_.updateDeviceInfo(this.deviceInfo_)),this.cardboardUI_&&this.cardboardUI_.listen(function(e){this.viewerSelector_.show(this.layer_.source.parentElement),e.stopPropagation(),e.preventDefault()}.bind(this),function(e){this.exitPresent(),e.stopPropagation(),e.preventDefault()}.bind(this)),this.rotateInstructions_&&(u()&&w()?this.rotateInstructions_.showTemporarily(3e3,this.layer_.source.parentElement):this.rotateInstructions_.update()),this.orientationHandler=this.onOrientationChange_.bind(this),window.addEventListener("orientationchange",this.orientationHandler),this.vrdisplaypresentchangeHandler=this.updateBounds_.bind(this),window.addEventListener("vrdisplaypresentchange",this.vrdisplaypresentchangeHandler),this.fireVRDisplayDeviceParamsChange_())},be.prototype.endPresent_=function(){this.distorter_&&(this.distorter_.destroy(),this.distorter_=null),this.cardboardUI_&&(this.cardboardUI_.destroy(),this.cardboardUI_=null),this.rotateInstructions_&&this.rotateInstructions_.hide(),this.viewerSelector_.hide(),window.removeEventListener("orientationchange",this.orientationHandler),window.removeEventListener("vrdisplaypresentchange",this.vrdisplaypresentchangeHandler)},be.prototype.updatePresent_=function(){this.endPresent_(),this.beginPresent_()},be.prototype.submitFrame=function(e){if(this.distorter_)this.updateBounds_(),this.distorter_.submitFrame();else if(this.cardboardUI_&&this.layer_){var t=this.layer_.source.getContext("webgl");t||(t=this.layer_.source.getContext("experimental-webgl")),t||(t=this.layer_.source.getContext("webgl2"));var i=t.canvas;i.width==this.lastWidth&&i.height==this.lastHeight||this.cardboardUI_.onResize(),this.lastWidth=i.width,this.lastHeight=i.height,this.cardboardUI_.render()}},be.prototype.onOrientationChange_=function(e){this.viewerSelector_.hide(),this.rotateInstructions_&&this.rotateInstructions_.update(),this.onResize_()},be.prototype.onResize_=function(e){if(this.layer_){var t=this.layer_.source.getContext("webgl");t||(t=this.layer_.source.getContext("experimental-webgl")),t||(t=this.layer_.source.getContext("webgl2")),t.canvas.setAttribute("style",["position: absolute","top: 0","left: 0","width: 100vw","height: 100vh","border: 0","margin: 0","padding: 0px","box-sizing: content-box"].join("; ")+";"),b(t.canvas)}},be.prototype.onViewerChanged_=function(e){this.deviceInfo_.setViewer(e),this.distorter_&&this.distorter_.updateDeviceInfo(this.deviceInfo_),this.fireVRDisplayDeviceParamsChange_()},be.prototype.fireVRDisplayDeviceParamsChange_=function(){var e=new CustomEvent("vrdisplaydeviceparamschange",{detail:{vrdisplay:this,deviceInfo:this.deviceInfo_}});window.dispatchEvent(e)},be.VRFrameData=function(){this.leftProjectionMatrix=new Float32Array(16),this.leftViewMatrix=new Float32Array(16),this.rightProjectionMatrix=new Float32Array(16),this.rightViewMatrix=new Float32Array(16),this.pose=null},be.VRDisplay=ve,be}()}(Ce={exports:{}},Ce.exports),Ce.exports),Le=(De=Ie)&&De.__esModule&&Object.prototype.hasOwnProperty.call(De,"default")?De.default:De;class Oe extends i{constructor(e){super(),this.global=e,this.onWindowResize=this.onWindowResize.bind(this),this.global.window.addEventListener("resize",this.onWindowResize),this.environmentBlendMode="opaque"}onBaseLayerSet(e,t){throw new Error("Not implemented")}isSessionSupported(e){throw new Error("Not implemented")}isFeatureSupported(e){throw new Error("Not implemented")}async requestSession(e,t){throw new Error("Not implemented")}requestAnimationFrame(e){throw new Error("Not implemented")}onFrameStart(e){throw new Error("Not implemented")}onFrameEnd(e){throw new Error("Not implemented")}doesSessionSupportReferenceSpace(e,t){throw new Error("Not implemented")}requestStageBounds(){throw new Error("Not implemented")}async requestFrameOfReferenceTransform(e,t){}cancelAnimationFrame(e){throw new Error("Not implemented")}endSession(e){throw new Error("Not implemented")}getViewport(e,t,i,r){throw new Error("Not implemented")}getProjectionMatrix(e){throw new Error("Not implemented")}getBasePoseMatrix(){throw new Error("Not implemented")}getBaseViewMatrix(e){throw new Error("Not implemented")}getInputSources(){throw new Error("Not implemented")}getInputPose(e,t,i){throw new Error("Not implemented")}onWindowResize(){this.onWindowResize()}}let Ne={mapping:"xr-standard",profiles:["oculus-go","generic-trigger-touchpad"],buttons:{length:3,0:1,1:null,2:0},gripTransform:{orientation:[.11*Math.PI,0,0,1]}},Ge={mapping:"xr-standard",displayProfiles:{"Oculus Quest":["oculus-touch-v2","oculus-touch","generic-trigger-squeeze-thumbstick"]},profiles:["oculus-touch","generic-trigger-squeeze-thumbstick"],axes:{length:4,0:null,1:null,2:0,3:1},buttons:{length:7,0:1,1:2,2:null,3:0,4:3,5:4,6:null},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Qe={mapping:"xr-standard",profiles:["htc-vive","generic-trigger-squeeze-touchpad"],displayProfiles:{"HTC Vive":["htc-vive","generic-trigger-squeeze-touchpad"],"HTC Vive DVT":["htc-vive","generic-trigger-squeeze-touchpad"],"Valve Index":["valve-index","generic-trigger-squeeze-touchpad-thumbstick"]},buttons:{length:3,0:1,1:2,2:0},gripTransform:{position:[0,0,.05,1]},targetRayTransform:{orientation:[-.08*Math.PI,0,0,1]},userAgentOverrides:{Firefox:{axes:{invert:[1,3]}}}},ke={mapping:"xr-standard",profiles:["samsung-gearvr","generic-trigger-touchpad"],buttons:{length:3,0:1,1:null,2:0},gripTransform:{orientation:[.11*Math.PI,0,0,1]}},ze={mapping:"xr-standard",profiles:["samsung-odyssey","microsoft-mixed-reality","generic-trigger-squeeze-touchpad-thumbstick"],buttons:{length:4,0:1,1:0,2:2,3:4},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Ue={mapping:"xr-standard",profiles:["microsoft-mixed-reality","generic-trigger-squeeze-touchpad-thumbstick"],buttons:{length:4,0:1,1:0,2:2,3:4},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Ve={"Daydream Controller":{mapping:"",profiles:["google-daydream","generic-trigger-touchpad"],buttons:{length:3,0:null,1:null,2:0}},"Gear VR Controller":ke,"HTC Vive Focus Controller":{mapping:"xr-standard",profiles:["htc-vive-focus","generic-trigger-touchpad"],buttons:{length:3,0:1,1:null,2:0}},"Oculus Go Controller":Ne,"Oculus Touch (Right)":Ge,"Oculus Touch (Left)":Ge,"OpenVR Gamepad":Qe,"Spatial Controller (Spatial Interaction Source) 045E-065A":Ue,"Spatial Controller (Spatial Interaction Source) 045E-065D":ze,"Windows Mixed Reality (Right)":Ue,"Windows Mixed Reality (Left)":Ue};const He=f(.155,-.465,-.15),Xe=f(-.155,-.465,-.15),We=f(0,0,-.25),je=f(0,0,.05),qe=f(-.08,.14,.08),Ye=.4,Ze=.4,Je=.61,Ke=.175,$e=.12,et=.87,tt=180/Math.PI;class it{constructor(){this.hand="right",this.headElbowOffset=He,this.controllerQ=M(),this.lastControllerQ=M(),this.headQ=M(),this.headPos=u(),this.elbowPos=u(),this.wristPos=u(),this.time=null,this.lastTime=null,this.rootQ=M(),this.position=u()}setHandedness(e){this.hand!=e&&(this.hand=e,"left"==this.hand?this.headElbowOffset=Xe:this.headElbowOffset=He)}update(e,t){this.time=X(),e&&(B(this.lastControllerQ,this.controllerQ),B(this.controllerQ,e)),t&&(h(this.headPos,t),c(this.headQ,t));let i=this.getHeadYawOrientation_(),r=this.quatAngle_(this.lastControllerQ,this.controllerQ);r/((this.time-this.lastTime)/1e3)>Je?_(this.rootQ,this.rootQ,i,Math.min(r/Ke,1)):B(this.rootQ,i);let s=f(0,0,-1);E(s,s,this.controllerQ);let n=y(s,[0,1,0]),a=this.clamp_((n-$e)/et,0,1),o=R(this.rootQ);F(o,o),x(o,o,this.controllerQ);let l=this.elbowPos;m(l,this.headPos),g(l,l,this.headElbowOffset);let A=p(qe);v(A,A,a),g(l,l,A);let d=this.quatAngle_(o,M())*tt,u=(1-Math.pow(d/180,4))*(Ye+(1-Ye)*a*Ze),w=M();_(w,w,o,u);let b=F(M(),w),S=R(o);x(S,S,b);let T=this.wristPos;m(T,je),E(T,T,w),g(T,T,We),E(T,T,S),g(T,T,l);let P=p(qe);v(P,P,a),g(this.position,this.wristPos,P),E(this.position,this.position,this.rootQ),this.lastTime=this.time}getPosition(){return this.position}getHeadYawOrientation_(){let e=u();return function(e,t,i){function r(e,t,i){return ei?i:e}var s=t[0]*t[0],n=t[1]*t[1],a=t[2]*t[2],o=t[3]*t[3];if("XYZ"===i)e[0]=Math.atan2(2*(t[0]*t[3]-t[1]*t[2]),o-s-n+a),e[1]=Math.asin(r(2*(t[0]*t[2]+t[1]*t[3]),-1,1)),e[2]=Math.atan2(2*(t[2]*t[3]-t[0]*t[1]),o+s-n-a);else if("YXZ"===i)e[0]=Math.asin(r(2*(t[0]*t[3]-t[1]*t[2]),-1,1)),e[1]=Math.atan2(2*(t[0]*t[2]+t[1]*t[3]),o-s-n+a),e[2]=Math.atan2(2*(t[0]*t[1]+t[2]*t[3]),o-s+n-a);else if("ZXY"===i)e[0]=Math.asin(r(2*(t[0]*t[3]+t[1]*t[2]),-1,1)),e[1]=Math.atan2(2*(t[1]*t[3]-t[2]*t[0]),o-s-n+a),e[2]=Math.atan2(2*(t[2]*t[3]-t[0]*t[1]),o-s+n-a);else if("ZYX"===i)e[0]=Math.atan2(2*(t[0]*t[3]+t[2]*t[1]),o-s-n+a),e[1]=Math.asin(r(2*(t[1]*t[3]-t[0]*t[2]),-1,1)),e[2]=Math.atan2(2*(t[0]*t[1]+t[2]*t[3]),o+s-n-a);else if("YZX"===i)e[0]=Math.atan2(2*(t[0]*t[3]-t[2]*t[1]),o-s+n-a),e[1]=Math.atan2(2*(t[1]*t[3]-t[0]*t[2]),o+s-n-a),e[2]=Math.asin(r(2*(t[0]*t[1]+t[2]*t[3]),-1,1));else{if("XZY"!==i)return void console.log("No order given for quaternion to euler conversion.");e[0]=Math.atan2(2*(t[0]*t[3]+t[1]*t[2]),o-s+n-a),e[1]=Math.atan2(2*(t[0]*t[2]+t[1]*t[3]),o+s-n-a),e[2]=Math.asin(r(2*(t[2]*t[3]-t[0]*t[1]),-1,1))}}(e,this.headQ,"YXZ"),function(e,t,i,r){let s=.5*Math.PI/180;t*=s,i*=s,r*=s;let n=Math.sin(t),a=Math.cos(t),o=Math.sin(i),l=Math.cos(i),A=Math.sin(r),h=Math.cos(r);return e[0]=n*l*h-a*o*A,e[1]=a*o*h+n*l*A,e[2]=a*l*A-n*o*h,e[3]=a*l*h+n*o*A,e}(M(),0,e[1]*tt,0)}clamp_(e,t,i){return Math.min(Math.max(e,t),i)}quatAngle_(e,t){let i=[0,0,-1],r=[0,0,-1];return E(i,i,e),E(r,r,t),function(e,t){let i=f(e[0],e[1],e[2]),r=f(t[0],t[1],t[2]);w(i,i),w(r,r);let s=y(i,r);return s>1?0:s<-1?Math.PI:Math.acos(s)}(i,r)}}const rt=Symbol("@@webxr-polyfill/XRRemappedGamepad"),st={pressed:!1,touched:!1,value:0};Object.freeze(st);class nt{constructor(e,t,i){if(i||(i={}),i.userAgentOverrides)for(let e in i.userAgentOverrides)if(navigator.userAgent.includes(e)){let t=i.userAgentOverrides[e];for(let e in t)e in i?Object.assign(i[e],t[e]):i[e]=t[e];break}let r=new Array(i.axes&&i.axes.length?i.axes.length:e.axes.length),s=new Array(i.buttons&&i.buttons.length?i.buttons.length:e.buttons.length),a=null;if(i.gripTransform){let e=i.gripTransform.orientation||[0,0,0,1];A(a=n(),P(e,e),i.gripTransform.position||[0,0,0])}let o=null;if(i.targetRayTransform){let e=i.targetRayTransform.orientation||[0,0,0,1];A(o=n(),P(e,e),i.targetRayTransform.position||[0,0,0])}let l=i.profiles;i.displayProfiles&&t.displayName in i.displayProfiles&&(l=i.displayProfiles[t.displayName]),this[rt]={gamepad:e,map:i,profiles:l||[e.id],mapping:i.mapping||e.mapping,axes:r,buttons:s,gripTransform:a,targetRayTransform:o},this._update()}_update(){let e=this[rt].gamepad,t=this[rt].map,i=this[rt].axes;for(let r=0;r{ot||this.global.document.body.contains(r)||(i.modifiedCanvasLayer=!0,this.global.document.body.appendChild(r),Be(r)),i.baseLayer=t})}else i.baseLayer=t}isSessionSupported(e){return"immersive-ar"!=e&&("immersive-vr"!=e||!1!==this.canPresent)}isFeatureSupported(e){switch(e){case"viewer":case"local":case"local-floor":return!0;case"bounded":case"unbounded":default:return!1}}async requestSession(e,t){if(!this.isSessionSupported(e))return Promise.reject();let i="immersive-vr"==e;if(i){const e=this.global.document.createElement("canvas");if(!ot){e.getContext("webgl")}await this.display.requestPresent([{source:e,attributes:lt}])}const r=new ct(e,t,{renderContextType:this.HAS_BITMAP_SUPPORT?"bitmaprenderer":"2d"});return this.sessions.set(r.id,r),i&&(this.immersiveSession=r,this.dispatchEvent("@@webxr-polyfill/vr-present-start",r.id)),Promise.resolve(r.id)}requestAnimationFrame(e){return this.display.requestAnimationFrame(e)}getPrimaryButtonIndex(e){let t=0,i=e.id.toLowerCase();for(let e in At)if(i.includes(e)){t=At[e];break}return Math.min(t,e.buttons.length-1)}onFrameStart(e,t){this.display.depthNear=t.depthNear,this.display.depthFar=t.depthFar,this.display.getFrameData(this.frame);const i=this.sessions.get(e);if(i.immersive&&this.CAN_USE_GAMEPAD){let e=this.gamepadInputSources;this.gamepadInputSources={};let t=this.global.navigator.getGamepads();for(let r=0;r0){let t=e[r];if(t||(t=new at(this,this.display,this.getPrimaryButtonIndex(s))),t.updateFromGamepad(s),this.gamepadInputSources[r]=t,-1!=t.primaryButtonIndex){let e=s.buttons[t.primaryButtonIndex].pressed;e&&!t.primaryActionPressed?this.dispatchEvent("@@webxr-polyfill/input-select-start",{sessionId:i.id,inputSource:t.inputSource}):!e&&t.primaryActionPressed&&this.dispatchEvent("@@webxr-polyfill/input-select-end",{sessionId:i.id,inputSource:t.inputSource}),t.primaryActionPressed=e}if(-1!=t.primarySqueezeButtonIndex){let e=s.buttons[t.primarySqueezeButtonIndex].pressed;e&&!t.primarySqueezeActionPressed?this.dispatchEvent("@@webxr-polyfill/input-squeeze-start",{sessionId:i.id,inputSource:t.inputSource}):!e&&t.primarySqueezeActionPressed&&this.dispatchEvent("@@webxr-polyfill/input-squeeze-end",{sessionId:i.id,inputSource:t.inputSource}),t.primarySqueezeActionPressed=e}}}}if(!ot&&!i.immersive&&i.baseLayer){const e=i.baseLayer.context.canvas;d(this.frame.leftProjectionMatrix,t.inlineVerticalFieldOfView,e.width/e.height,t.depthNear,t.depthFar)}}onFrameEnd(e){const t=this.sessions.get(e);if(!t.ended&&t.baseLayer){if(t.outputContext&&(!t.immersive||this.display.capabilities.hasExternalDisplay)){const e=t.immersive&&this.display.capabilities.hasExternalDisplay,i=t.baseLayer.context.canvas,r=e?i.width/2:i.width,s=i.height;if(!ot){const e=t.outputContext.canvas,n=e.width,a=e.height,o=t.renderContext;this.HAS_BITMAP_SUPPORT?i.transferToImageBitmap?o.transferFromImageBitmap(i.transferToImageBitmap()):this.global.createImageBitmap(i,0,0,r,s,{resizeWidth:n,resizeHeight:a}).then(e=>o.transferFromImageBitmap(e)):o.drawImage(i,0,0,r,s,0,0,n,a)}}t.immersive&&t.baseLayer&&this.display.submitFrame()}}cancelAnimationFrame(e){this.display.cancelAnimationFrame(e)}async endSession(e){const t=this.sessions.get(e);if(!t.ended)return t.immersive?this.display.exitPresent():void(t.ended=!0)}doesSessionSupportReferenceSpace(e,t){const i=this.sessions.get(e);return!i.ended&&i.enabledFeatures.has(t)}requestStageBounds(){if(this.display.stageParameters){const e=this.display.stageParameters.sizeX,t=this.display.stageParameters.sizeZ,i=[];return i.push(-e/2),i.push(-t/2),i.push(e/2),i.push(-t/2),i.push(e/2),i.push(t/2),i.push(-e/2),i.push(t/2),i}return null}async requestFrameOfReferenceTransform(e,t){return("local-floor"===e||"bounded-floor"===e)&&this.display.stageParameters&&this.display.stageParameters.sittingToStandingTransform?this.display.stageParameters.sittingToStandingTransform:null}getProjectionMatrix(e){if("left"===e)return this.frame.leftProjectionMatrix;if("right"===e)return this.frame.rightProjectionMatrix;if("none"===e)return this.frame.leftProjectionMatrix;throw new Error("eye must be of type 'left' or 'right'")}getViewport(e,t,i,r){const s=this.sessions.get(e),{width:n,height:a}=i.context.canvas;if(!s.immersive)return r.x=r.y=0,r.width=n,r.height=a,!0;if("left"===t||"none"===t)r.x=0;else{if("right"!==t)return!1;r.x=n/2}return r.y=0,r.width=n/2,r.height=a,!0}getBasePoseMatrix(){let{position:e,orientation:t}=this.frame.pose;return e||t?(e||((e=this.tempVec3)[0]=e[1]=e[2]=0),A(this.baseModelMatrix,t,e),this.baseModelMatrix):this.baseModelMatrix}getBaseViewMatrix(e){if("left"===e||"none"===e)return this.frame.leftViewMatrix;if("right"===e)return this.frame.rightViewMatrix;throw new Error("eye must be of type 'left' or 'right'")}getInputSources(){let e=[];for(let t in this.gamepadInputSources)e.push(this.gamepadInputSources[t].inputSource);return e}getInputPose(e,t,i){if(!t)return null;for(let r in this.gamepadInputSources){let s=this.gamepadInputSources[r];if(s.inputSource===e)return s.getXRPose(t,i)}return null}onWindowResize(){}onVRDisplayPresentChange(e){this.display.isPresenting||this.sessions.forEach(e=>{if(e.immersive&&!e.ended){if(e.modifiedCanvasLayer){const t=e.baseLayer.context.canvas;document.body.removeChild(t),t.setAttribute("style","")}this.immersiveSession===e&&(this.immersiveSession=null),this.dispatchEvent("@@webxr-polyfill/vr-present-end",e.id)}})}}const ut=!1;let pt=0;class ft{constructor(e,t){this.mode=e,this.enabledFeatures=t,this.ended=null,this.baseLayer=null,this.id=++pt}}const mt=async function(e,t){if(t.webvr){let t=await async function(e){let t=null;if("getVRDisplays"in e.navigator)try{const i=await e.navigator.getVRDisplays();i&&i.length&&(t=new dt(e,i[0]))}catch(e){}return t}(e);if(t)return t}let i=(e=>{var t=!1;return Te=e.navigator.userAgent||e.navigator.vendor||e.opera,(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(Te)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(Te.substr(0,4)))&&(t=!0),t})(e);return i&&t.cardboard||!i&&t.allowCardboardOnDesktop?(e.VRFrameData||(e.VRFrameData=function(){this.rightViewMatrix=new Float32Array(16),this.leftViewMatrix=new Float32Array(16),this.rightProjectionMatrix=new Float32Array(16),this.leftProjectionMatrix=new Float32Array(16),this.pose=null}),new class extends dt{constructor(e,t){const i=new Le(t||{});super(e,i),this.display=i,this.frame={rightViewMatrix:new Float32Array(16),leftViewMatrix:new Float32Array(16),rightProjectionMatrix:new Float32Array(16),leftProjectionMatrix:new Float32Array(16),pose:null,timestamp:null}}}(e,t.cardboardConfig)):new class extends Oe{constructor(e){super(e),this.sessions=new Map,this.projectionMatrix=n(),this.identityMatrix=n()}onBaseLayerSet(e,t){this.sessions.get(e).baseLayer=t}isSessionSupported(e){return"inline"==e}isFeatureSupported(e){switch(e){case"viewer":return!0;default:return!1}}async requestSession(e,t){if(!this.isSessionSupported(e))return Promise.reject();const i=new ft(e,t);return this.sessions.set(i.id,i),Promise.resolve(i.id)}requestAnimationFrame(e){return window.requestAnimationFrame(e)}cancelAnimationFrame(e){window.cancelAnimationFrame(e)}onFrameStart(e,t){if(ut)return;const i=this.sessions.get(e);if(i.baseLayer){const e=i.baseLayer.context.canvas;d(this.projectionMatrix,t.inlineVerticalFieldOfView,e.width/e.height,t.depthNear,t.depthFar)}}onFrameEnd(e){}async endSession(e){this.sessions.get(e).ended=!0}doesSessionSupportReferenceSpace(e,t){const i=this.sessions.get(e);return!i.ended&&i.enabledFeatures.has(t)}requestStageBounds(){return null}async requestFrameOfReferenceTransform(e,t){return null}getProjectionMatrix(e){return this.projectionMatrix}getViewport(e,t,i,r){const{width:s,height:n}=i.context.canvas;return this.sessions.get(e),r.x=r.y=0,r.width=s,r.height=n,!0}getBasePoseMatrix(){return this.identityMatrix}getBaseViewMatrix(e){return this.identityMatrix}getInputSources(){return[]}getInputPose(e,t,i){return null}onWindowResize(){}}(e)},gt={global:e,webvr:!0,cardboard:!0,cardboardConfig:null,allowCardboardOnDesktop:!1},vt=["navigator","HTMLCanvasElement","WebGLRenderingContext"];return class{constructor(e={}){this.config=Object.freeze(Object.assign({},gt,e)),this.global=this.config.global,this.nativeWebXR="xr"in this.global.navigator,this.injected=!1,this.nativeWebXR?this._injectCompatibilityShims(this.global):this._injectPolyfill(this.global)}_injectPolyfill(e){if(!vt.every(t=>!!e[t]))throw new Error(`Global must have the following attributes : ${vt}`);for(const t of Object.keys(xe))void 0!==e[t]?console.warn(`${t} already defined on global.`):e[t]=xe[t];_e(e.WebGLRenderingContext)&&(Fe(e.HTMLCanvasElement),e.OffscreenCanvas&&Fe(e.OffscreenCanvas),e.WebGL2RenderingContext&&_e(e.WebGL2RenderingContext)),this.injected=!0,this._patchNavigatorXR()}_patchNavigatorXR(){let e=mt(this.global,this.config);this.xr=new xe.XR(e),Object.defineProperty(this.global.navigator,"xr",{value:this.xr,configurable:!0})}_injectCompatibilityShims(e){if(!vt.every(t=>!!e[t]))throw new Error(`Global must have the following attributes : ${vt}`);if(e.navigator.xr&&"supportsSession"in e.navigator.xr&&!("isSessionSupported"in e.navigator.xr)){let t=e.navigator.xr.supportsSession;e.navigator.xr.isSessionSupported=function(e){return t.call(this,e).then(()=>!0).catch(()=>!1)},e.navigator.xr.supportsSession=function(e){return console.warn("navigator.xr.supportsSession() is deprecated. Please call navigator.xr.isSessionSupported() instead and check the boolean value returned when the promise resolves."),t.call(this,e)}}}}}); diff --git a/build/webxr-polyfill.module.js b/build/webxr-polyfill.module.js index 70d5d53..07c3dc4 100644 --- a/build/webxr-polyfill.module.js +++ b/build/webxr-polyfill.module.js @@ -1640,7 +1640,7 @@ class XRSession$1 extends EventTarget { if (this[PRIVATE$15].ended) { return; } - if (this.immersive) { + if (this[PRIVATE$15].immersive) { this[PRIVATE$15].ended = true; this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/vr-present-start', this[PRIVATE$15].onPresentationStart); @@ -3489,8 +3489,8 @@ function CardboardViewer(params) { } DeviceInfo.Viewers = Viewers; var format = 1; -var last_updated = "2018-12-10T17:01:42Z"; -var devices = [{"type":"android","rules":[{"mdmh":"asus/*/Nexus 7/*"},{"ua":"Nexus 7"}],"dpi":[320.8,323],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_Z00AD/*"},{"ua":"ASUS_Z00AD"}],"dpi":[403,404.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2 XL/*"},{"ua":"Pixel 2 XL"}],"dpi":537.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3 XL/*"},{"ua":"Pixel 3 XL"}],"dpi":[558.5,553.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel XL/*"},{"ua":"Pixel XL"}],"dpi":[537.9,533],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3/*"},{"ua":"Pixel 3"}],"dpi":442.4,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2/*"},{"ua":"Pixel 2"}],"dpi":441,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Google/*/Pixel/*"},{"ua":"Pixel"}],"dpi":[432.6,436.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC6435LVW/*"},{"ua":"HTC6435LVW"}],"dpi":[449.7,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One XL/*"},{"ua":"HTC One XL"}],"dpi":[315.3,314.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"htc/*/Nexus 9/*"},{"ua":"Nexus 9"}],"dpi":289,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One M9/*"},{"ua":"HTC One M9"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One_M8/*"},{"ua":"HTC One_M8"}],"dpi":[449.7,447.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One/*"},{"ua":"HTC One"}],"dpi":472.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/Nexus 6P/*"},{"ua":"Nexus 6P"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/BLN-L24/*"},{"ua":"HONORBLN-L24"}],"dpi":480,"bw":4,"ac":500},{"type":"android","rules":[{"mdmh":"Huawei/*/BKL-L09/*"},{"ua":"BKL-L09"}],"dpi":403,"bw":3.47,"ac":500},{"type":"android","rules":[{"mdmh":"LENOVO/*/Lenovo PB2-690Y/*"},{"ua":"Lenovo PB2-690Y"}],"dpi":[457.2,454.713],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5X/*"},{"ua":"Nexus 5X"}],"dpi":[422,419.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS345/*"},{"ua":"LGMS345"}],"dpi":[221.7,219.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D800/*"},{"ua":"LG-D800"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D850/*"},{"ua":"LG-D850"}],"dpi":[537.9,541.9],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/VS985 4G/*"},{"ua":"VS985 4G"}],"dpi":[537.9,535.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5/*"},{"ua":"Nexus 5 B"}],"dpi":[442.4,444.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 4/*"},{"ua":"Nexus 4"}],"dpi":[319.8,318.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LG-P769/*"},{"ua":"LG-P769"}],"dpi":[240.6,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS323/*"},{"ua":"LGMS323"}],"dpi":[206.6,204.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGLS996/*"},{"ua":"LGLS996"}],"dpi":[403.4,401.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/4560MMX/*"},{"ua":"4560MMX"}],"dpi":[240,219.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/A250/*"},{"ua":"Micromax A250"}],"dpi":[480,446.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/Micromax AQ4501/*"},{"ua":"Micromax AQ4501"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/G5/*"},{"ua":"Moto G (5) Plus"}],"dpi":[403.4,403],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/DROID RAZR/*"},{"ua":"DROID RAZR"}],"dpi":[368.1,256.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT830C/*"},{"ua":"XT830C"}],"dpi":[254,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1021/*"},{"ua":"XT1021"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1023/*"},{"ua":"XT1023"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1028/*"},{"ua":"XT1028"}],"dpi":[326.6,327.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1034/*"},{"ua":"XT1034"}],"dpi":[326.6,328.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1053/*"},{"ua":"XT1053"}],"dpi":[315.3,316.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1562/*"},{"ua":"XT1562"}],"dpi":[403.4,402.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/Nexus 6/*"},{"ua":"Nexus 6 B"}],"dpi":[494.3,489.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1063/*"},{"ua":"XT1063"}],"dpi":[295,296.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1064/*"},{"ua":"XT1064"}],"dpi":[295,295.6],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1092/*"},{"ua":"XT1092"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1095/*"},{"ua":"XT1095"}],"dpi":[422,423.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/G4/*"},{"ua":"Moto G (4)"}],"dpi":401,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/A0001/*"},{"ua":"A0001"}],"dpi":[403.4,401],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1005/*"},{"ua":"ONE E1005"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2005/*"},{"ua":"ONE A2005"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A5000/*"},{"ua":"ONEPLUS A5000 "}],"dpi":[403.411,399.737],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A5010/*"},{"ua":"ONEPLUS A5010"}],"dpi":[403,400],"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"OPPO/*/X909/*"},{"ua":"X909"}],"dpi":[442.4,444.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9082/*"},{"ua":"GT-I9082"}],"dpi":[184.7,185.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G360P/*"},{"ua":"SM-G360P"}],"dpi":[196.7,205.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Nexus S/*"},{"ua":"Nexus S"}],"dpi":[234.5,229.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[304.8,303.9],"bw":5,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T230NU/*"},{"ua":"SM-T230NU"}],"dpi":216,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-T399/*"},{"ua":"SGH-T399"}],"dpi":[217.7,231.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-M919/*"},{"ua":"SGH-M919"}],"dpi":[440.8,437.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N9005/*"},{"ua":"SM-N9005"}],"dpi":[386.4,387],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SM-N900A/*"},{"ua":"SAMSUNG-SM-N900A"}],"dpi":[386.4,387.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9500/*"},{"ua":"GT-I9500"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9505/*"},{"ua":"GT-I9505"}],"dpi":439.4,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900F/*"},{"ua":"SM-G900F"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900M/*"},{"ua":"SM-G900M"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G800F/*"},{"ua":"SM-G800F"}],"dpi":326.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G906S/*"},{"ua":"SM-G906S"}],"dpi":[562.7,572.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[306.7,304.8],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T535/*"},{"ua":"SM-T535"}],"dpi":[142.6,136.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920C/*"},{"ua":"SM-N920C"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920P/*"},{"ua":"SM-N920P"}],"dpi":[386.3655,390.144],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920W8/*"},{"ua":"SM-N920W8"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300I/*"},{"ua":"GT-I9300I"}],"dpi":[304.8,305.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9195/*"},{"ua":"GT-I9195"}],"dpi":[249.4,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-L520/*"},{"ua":"SPH-L520"}],"dpi":[249.4,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SGH-I717/*"},{"ua":"SAMSUNG-SGH-I717"}],"dpi":285.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-D710/*"},{"ua":"SPH-D710"}],"dpi":[217.7,204.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-N7100/*"},{"ua":"GT-N7100"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SCH-I605/*"},{"ua":"SCH-I605"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Galaxy Nexus/*"},{"ua":"Galaxy Nexus"}],"dpi":[315.3,314.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910H/*"},{"ua":"SM-N910H"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910C/*"},{"ua":"SM-N910C"}],"dpi":[515.2,520.2],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G130M/*"},{"ua":"SM-G130M"}],"dpi":[165.9,164.8],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G928I/*"},{"ua":"SM-G928I"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920F/*"},{"ua":"SM-G920F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920P/*"},{"ua":"SM-G920P"}],"dpi":[522.5,577],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925F/*"},{"ua":"SM-G925F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925V/*"},{"ua":"SM-G925V"}],"dpi":[522.5,576.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G930F/*"},{"ua":"SM-G930F"}],"dpi":576.6,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G935F/*"},{"ua":"SM-G935F"}],"dpi":533,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G950F/*"},{"ua":"SM-G950F"}],"dpi":[562.707,565.293],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955U/*"},{"ua":"SM-G955U"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955F/*"},{"ua":"SM-G955F"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/C6903/*"},{"ua":"C6903"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/D6653/*"},{"ua":"D6653"}],"dpi":[428.6,427.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6653/*"},{"ua":"E6653"}],"dpi":[428.6,425.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6853/*"},{"ua":"E6853"}],"dpi":[403.4,401.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/SGP321/*"},{"ua":"SGP321"}],"dpi":[224.7,224.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{"ua":"ALCATEL ONE TOUCH Fierce"}],"dpi":[240,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"THL/*/thl 5000/*"},{"ua":"thl 5000"}],"dpi":[480,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Fly/*/IQ4412/*"},{"ua":"IQ4412"}],"dpi":307.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"ZTE/*/ZTE Blade L2/*"},{"ua":"ZTE Blade L2"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"BENEVE/*/VR518/*"},{"ua":"VR518"}],"dpi":480,"bw":3,"ac":500},{"type":"ios","rules":[{"res":[640,960]}],"dpi":[325.1,328.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[640,1136]}],"dpi":[317.1,320.2],"bw":3,"ac":1000},{"type":"ios","rules":[{"res":[750,1334]}],"dpi":326.4,"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1242,2208]}],"dpi":[453.6,458.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2001]}],"dpi":[410.9,415.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2436]}],"dpi":458,"bw":4,"ac":1000}]; +var last_updated = "2019-11-09T17:36:14Z"; +var devices = [{"type":"android","rules":[{"mdmh":"asus/*/Nexus 7/*"},{"ua":"Nexus 7"}],"dpi":[320.8,323],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_X00PD/*"},{"ua":"ASUS_X00PD"}],"dpi":245,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_X008D/*"},{"ua":"ASUS_X008D"}],"dpi":282,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_Z00AD/*"},{"ua":"ASUS_Z00AD"}],"dpi":[403,404.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2 XL/*"},{"ua":"Pixel 2 XL"}],"dpi":537.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3 XL/*"},{"ua":"Pixel 3 XL"}],"dpi":[558.5,553.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel XL/*"},{"ua":"Pixel XL"}],"dpi":[537.9,533],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3/*"},{"ua":"Pixel 3"}],"dpi":442.4,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2/*"},{"ua":"Pixel 2"}],"dpi":441,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Google/*/Pixel/*"},{"ua":"Pixel"}],"dpi":[432.6,436.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC6435LVW/*"},{"ua":"HTC6435LVW"}],"dpi":[449.7,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One XL/*"},{"ua":"HTC One XL"}],"dpi":[315.3,314.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"htc/*/Nexus 9/*"},{"ua":"Nexus 9"}],"dpi":289,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One M9/*"},{"ua":"HTC One M9"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One_M8/*"},{"ua":"HTC One_M8"}],"dpi":[449.7,447.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One/*"},{"ua":"HTC One"}],"dpi":472.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/Nexus 6P/*"},{"ua":"Nexus 6P"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/BLN-L24/*"},{"ua":"HONORBLN-L24"}],"dpi":480,"bw":4,"ac":500},{"type":"android","rules":[{"mdmh":"Huawei/*/BKL-L09/*"},{"ua":"BKL-L09"}],"dpi":403,"bw":3.47,"ac":500},{"type":"android","rules":[{"mdmh":"LENOVO/*/Lenovo PB2-690Y/*"},{"ua":"Lenovo PB2-690Y"}],"dpi":[457.2,454.713],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5X/*"},{"ua":"Nexus 5X"}],"dpi":[422,419.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS345/*"},{"ua":"LGMS345"}],"dpi":[221.7,219.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D800/*"},{"ua":"LG-D800"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D850/*"},{"ua":"LG-D850"}],"dpi":[537.9,541.9],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/VS985 4G/*"},{"ua":"VS985 4G"}],"dpi":[537.9,535.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5/*"},{"ua":"Nexus 5 B"}],"dpi":[442.4,444.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 4/*"},{"ua":"Nexus 4"}],"dpi":[319.8,318.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LG-P769/*"},{"ua":"LG-P769"}],"dpi":[240.6,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS323/*"},{"ua":"LGMS323"}],"dpi":[206.6,204.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGLS996/*"},{"ua":"LGLS996"}],"dpi":[403.4,401.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/4560MMX/*"},{"ua":"4560MMX"}],"dpi":[240,219.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/A250/*"},{"ua":"Micromax A250"}],"dpi":[480,446.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/Micromax AQ4501/*"},{"ua":"Micromax AQ4501"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/G5/*"},{"ua":"Moto G (5) Plus"}],"dpi":[403.4,403],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/DROID RAZR/*"},{"ua":"DROID RAZR"}],"dpi":[368.1,256.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT830C/*"},{"ua":"XT830C"}],"dpi":[254,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1021/*"},{"ua":"XT1021"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1023/*"},{"ua":"XT1023"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1028/*"},{"ua":"XT1028"}],"dpi":[326.6,327.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1034/*"},{"ua":"XT1034"}],"dpi":[326.6,328.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1053/*"},{"ua":"XT1053"}],"dpi":[315.3,316.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1562/*"},{"ua":"XT1562"}],"dpi":[403.4,402.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/Nexus 6/*"},{"ua":"Nexus 6 B"}],"dpi":[494.3,489.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1063/*"},{"ua":"XT1063"}],"dpi":[295,296.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1064/*"},{"ua":"XT1064"}],"dpi":[295,295.6],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1092/*"},{"ua":"XT1092"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1095/*"},{"ua":"XT1095"}],"dpi":[422,423.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/G4/*"},{"ua":"Moto G (4)"}],"dpi":401,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/A0001/*"},{"ua":"A0001"}],"dpi":[403.4,401],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1001/*"},{"ua":"ONE E1001"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1003/*"},{"ua":"ONE E1003"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1005/*"},{"ua":"ONE E1005"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2001/*"},{"ua":"ONE A2001"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2003/*"},{"ua":"ONE A2003"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2005/*"},{"ua":"ONE A2005"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A3000/*"},{"ua":"ONEPLUS A3000"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A3003/*"},{"ua":"ONEPLUS A3003"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A3010/*"},{"ua":"ONEPLUS A3010"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A5000/*"},{"ua":"ONEPLUS A5000 "}],"dpi":[403.411,399.737],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A5010/*"},{"ua":"ONEPLUS A5010"}],"dpi":[403,400],"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6000/*"},{"ua":"ONEPLUS A6000"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6003/*"},{"ua":"ONEPLUS A6003"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6010/*"},{"ua":"ONEPLUS A6010"}],"dpi":401,"bw":2,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6013/*"},{"ua":"ONEPLUS A6013"}],"dpi":401,"bw":2,"ac":500},{"type":"android","rules":[{"mdmh":"OPPO/*/X909/*"},{"ua":"X909"}],"dpi":[442.4,444.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9082/*"},{"ua":"GT-I9082"}],"dpi":[184.7,185.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G360P/*"},{"ua":"SM-G360P"}],"dpi":[196.7,205.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Nexus S/*"},{"ua":"Nexus S"}],"dpi":[234.5,229.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[304.8,303.9],"bw":5,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T230NU/*"},{"ua":"SM-T230NU"}],"dpi":216,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-T399/*"},{"ua":"SGH-T399"}],"dpi":[217.7,231.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-M919/*"},{"ua":"SGH-M919"}],"dpi":[440.8,437.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N9005/*"},{"ua":"SM-N9005"}],"dpi":[386.4,387],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SM-N900A/*"},{"ua":"SAMSUNG-SM-N900A"}],"dpi":[386.4,387.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9500/*"},{"ua":"GT-I9500"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9505/*"},{"ua":"GT-I9505"}],"dpi":439.4,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900F/*"},{"ua":"SM-G900F"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900M/*"},{"ua":"SM-G900M"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G800F/*"},{"ua":"SM-G800F"}],"dpi":326.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G906S/*"},{"ua":"SM-G906S"}],"dpi":[562.7,572.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[306.7,304.8],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T535/*"},{"ua":"SM-T535"}],"dpi":[142.6,136.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920C/*"},{"ua":"SM-N920C"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920P/*"},{"ua":"SM-N920P"}],"dpi":[386.3655,390.144],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920W8/*"},{"ua":"SM-N920W8"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300I/*"},{"ua":"GT-I9300I"}],"dpi":[304.8,305.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9195/*"},{"ua":"GT-I9195"}],"dpi":[249.4,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-L520/*"},{"ua":"SPH-L520"}],"dpi":[249.4,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SGH-I717/*"},{"ua":"SAMSUNG-SGH-I717"}],"dpi":285.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-D710/*"},{"ua":"SPH-D710"}],"dpi":[217.7,204.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-N7100/*"},{"ua":"GT-N7100"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SCH-I605/*"},{"ua":"SCH-I605"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Galaxy Nexus/*"},{"ua":"Galaxy Nexus"}],"dpi":[315.3,314.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910H/*"},{"ua":"SM-N910H"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910C/*"},{"ua":"SM-N910C"}],"dpi":[515.2,520.2],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G130M/*"},{"ua":"SM-G130M"}],"dpi":[165.9,164.8],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G928I/*"},{"ua":"SM-G928I"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920F/*"},{"ua":"SM-G920F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920P/*"},{"ua":"SM-G920P"}],"dpi":[522.5,577],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925F/*"},{"ua":"SM-G925F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925V/*"},{"ua":"SM-G925V"}],"dpi":[522.5,576.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G930F/*"},{"ua":"SM-G930F"}],"dpi":576.6,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G935F/*"},{"ua":"SM-G935F"}],"dpi":533,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G950F/*"},{"ua":"SM-G950F"}],"dpi":[562.707,565.293],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955U/*"},{"ua":"SM-G955U"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955F/*"},{"ua":"SM-G955F"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960F/*"},{"ua":"SM-G960F"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G9600/*"},{"ua":"SM-G9600"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960T/*"},{"ua":"SM-G960T"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960N/*"},{"ua":"SM-G960N"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960U/*"},{"ua":"SM-G960U"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G9608/*"},{"ua":"SM-G9608"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960FD/*"},{"ua":"SM-G960FD"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960W/*"},{"ua":"SM-G960W"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G965F/*"},{"ua":"SM-G965F"}],"dpi":529,"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/C6903/*"},{"ua":"C6903"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/D6653/*"},{"ua":"D6653"}],"dpi":[428.6,427.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6653/*"},{"ua":"E6653"}],"dpi":[428.6,425.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6853/*"},{"ua":"E6853"}],"dpi":[403.4,401.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/SGP321/*"},{"ua":"SGP321"}],"dpi":[224.7,224.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{"ua":"ALCATEL ONE TOUCH Fierce"}],"dpi":[240,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"THL/*/thl 5000/*"},{"ua":"thl 5000"}],"dpi":[480,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Fly/*/IQ4412/*"},{"ua":"IQ4412"}],"dpi":307.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"ZTE/*/ZTE Blade L2/*"},{"ua":"ZTE Blade L2"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"BENEVE/*/VR518/*"},{"ua":"VR518"}],"dpi":480,"bw":3,"ac":500},{"type":"ios","rules":[{"res":[640,960]}],"dpi":[325.1,328.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[640,1136]}],"dpi":[317.1,320.2],"bw":3,"ac":1000},{"type":"ios","rules":[{"res":[750,1334]}],"dpi":326.4,"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1242,2208]}],"dpi":[453.6,458.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2001]}],"dpi":[410.9,415.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2436]}],"dpi":458,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/EML-L29/*"},{"ua":"EML-L29"}],"dpi":428,"bw":3.45,"ac":500},{"type":"android","rules":[{"mdmh":"Nokia/*/Nokia 7.1/*"},{"ua":"Nokia 7.1"}],"dpi":[432,431.9],"bw":3,"ac":500},{"type":"ios","rules":[{"res":[1242,2688]}],"dpi":458,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G570M/*"},{"ua":"SM-G570M"}],"dpi":320,"bw":3.684,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G970F/*"},{"ua":"SM-G970F"}],"dpi":438,"bw":2.281,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G973F/*"},{"ua":"SM-G973F"}],"dpi":550,"bw":2.002,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G975F/*"},{"ua":"SM-G975F"}],"dpi":522,"bw":2.054,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G977F/*"},{"ua":"SM-G977F"}],"dpi":505,"bw":2.334,"ac":500},{"type":"ios","rules":[{"res":[828,1792]}],"dpi":326,"bw":5,"ac":500}]; var DPDB_CACHE = { format: format, last_updated: last_updated, @@ -4918,7 +4918,10 @@ CardboardVRDisplay.prototype.submitFrame = function (pose) { this.updateBounds_(); this.distorter_.submitFrame(); } else if (this.cardboardUI_ && this.layer_) { - var canvas = this.layer_.source.getContext('webgl').canvas; + var gl = this.layer_.source.getContext('webgl'); + if (!gl) gl = this.layer_.source.getContext('experimental-webgl'); + if (!gl) gl = this.layer_.source.getContext('webgl2'); + var canvas = gl.canvas; if (canvas.width != this.lastWidth || canvas.height != this.lastHeight) { this.cardboardUI_.onResize(); } @@ -4937,6 +4940,8 @@ CardboardVRDisplay.prototype.onOrientationChange_ = function (e) { CardboardVRDisplay.prototype.onResize_ = function (e) { if (this.layer_) { var gl = this.layer_.source.getContext('webgl'); + if (!gl) gl = this.layer_.source.getContext('experimental-webgl'); + if (!gl) gl = this.layer_.source.getContext('webgl2'); var cssProperties = ['position: absolute', 'top: 0', 'left: 0', 'width: 100vw', 'height: 100vh', 'border: 0', 'margin: 0', 'padding: 0px', 'box-sizing: content-box']; diff --git a/src/api/XRSession.js b/src/api/XRSession.js index 29c6dd6..8b8d3ff 100644 --- a/src/api/XRSession.js +++ b/src/api/XRSession.js @@ -407,7 +407,7 @@ export default class XRSession extends EventTarget { // If this is an immersive session, trigger the platform to end, which // will call the `onPresentationEnd` handler, wrapping this up. - if (this.immersive) { + if (this[PRIVATE].immersive) { this[PRIVATE].ended = true; this[PRIVATE].device.removeEventListener('@@webvr-polyfill/vr-present-start', this[PRIVATE].onPresentationStart); From d27cab1cbae89a1a093f7373eeed43764ad7ce68 Mon Sep 17 00:00:00 2001 From: Blair MacIntyre Date: Wed, 1 Jan 2020 19:53:09 -0500 Subject: [PATCH 2/7] remove for PR --- build/webxr-polyfill.js | 6122 -------------------------------- build/webxr-polyfill.min.js | 95 - build/webxr-polyfill.module.js | 6114 ------------------------------- 3 files changed, 12331 deletions(-) delete mode 100644 build/webxr-polyfill.js delete mode 100644 build/webxr-polyfill.min.js delete mode 100644 build/webxr-polyfill.module.js diff --git a/build/webxr-polyfill.js b/build/webxr-polyfill.js deleted file mode 100644 index 3fd4b81..0000000 --- a/build/webxr-polyfill.js +++ /dev/null @@ -1,6122 +0,0 @@ -/** - * @license - * webxr-polyfill - * Copyright (c) 2017 Google - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @license - * cardboard-vr-display - * Copyright (c) 2015-2017 Google - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @license - * webvr-polyfill-dpdb - * Copyright (c) 2017 Google - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @license - * wglu-preserve-state - * Copyright (c) 2016, Brandon Jones. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/** - * @license - * nosleep.js - * Copyright (c) 2017, Rich Tibbett - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global.WebXRPolyfill = factory()); -}(this, (function () { 'use strict'; - -const _global = typeof global !== 'undefined' ? global : - typeof self !== 'undefined' ? self : - typeof window !== 'undefined' ? window : {}; - -const PRIVATE = Symbol('@@webxr-polyfill/EventTarget'); -class EventTarget { - constructor() { - this[PRIVATE] = { - listeners: new Map(), - }; - } - addEventListener(type, listener) { - if (typeof type !== 'string') { throw new Error('`type` must be a string'); } - if (typeof listener !== 'function') { throw new Error('`listener` must be a function'); } - const typedListeners = this[PRIVATE].listeners.get(type) || []; - typedListeners.push(listener); - this[PRIVATE].listeners.set(type, typedListeners); - } - removeEventListener(type, listener) { - if (typeof type !== 'string') { throw new Error('`type` must be a string'); } - if (typeof listener !== 'function') { throw new Error('`listener` must be a function'); } - const typedListeners = this[PRIVATE].listeners.get(type) || []; - for (let i = typedListeners.length; i >= 0; i--) { - if (typedListeners[i] === listener) { - typedListeners.pop(); - } - } - } - dispatchEvent(type, event) { - const typedListeners = this[PRIVATE].listeners.get(type) || []; - const queue = []; - for (let i = 0; i < typedListeners.length; i++) { - queue[i] = typedListeners[i]; - } - for (let listener of queue) { - listener(event); - } - if (typeof this[`on${type}`] === 'function') { - this[`on${type}`](event); - } - } -} - -const EPSILON = 0.000001; -let ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; - - -const degree = Math.PI / 180; - -function create() { - let out = new ARRAY_TYPE(16); - if(ARRAY_TYPE != Float32Array) { - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - } - out[0] = 1; - out[5] = 1; - out[10] = 1; - out[15] = 1; - return out; -} - -function copy(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - out[9] = a[9]; - out[10] = a[10]; - out[11] = a[11]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - return out; -} - - -function identity(out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = 1; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 1; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - return out; -} - -function invert(out, a) { - let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; - let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; - let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; - let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; - let b00 = a00 * a11 - a01 * a10; - let b01 = a00 * a12 - a02 * a10; - let b02 = a00 * a13 - a03 * a10; - let b03 = a01 * a12 - a02 * a11; - let b04 = a01 * a13 - a03 * a11; - let b05 = a02 * a13 - a03 * a12; - let b06 = a20 * a31 - a21 * a30; - let b07 = a20 * a32 - a22 * a30; - let b08 = a20 * a33 - a23 * a30; - let b09 = a21 * a32 - a22 * a31; - let b10 = a21 * a33 - a23 * a31; - let b11 = a22 * a33 - a23 * a32; - let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; - if (!det) { - return null; - } - det = 1.0 / det; - out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; - out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; - out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; - out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; - out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; - out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; - out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; - out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; - out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; - out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; - out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; - out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; - out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; - out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; - out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; - out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; - return out; -} - - -function multiply(out, a, b) { - let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; - let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; - let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; - let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; - let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; - out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; - out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; - out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; - out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - return out; -} - - - - - - - - - - - - -function fromRotationTranslation(out, q, v) { - let x = q[0], y = q[1], z = q[2], w = q[3]; - let x2 = x + x; - let y2 = y + y; - let z2 = z + z; - let xx = x * x2; - let xy = x * y2; - let xz = x * z2; - let yy = y * y2; - let yz = y * z2; - let zz = z * z2; - let wx = w * x2; - let wy = w * y2; - let wz = w * z2; - out[0] = 1 - (yy + zz); - out[1] = xy + wz; - out[2] = xz - wy; - out[3] = 0; - out[4] = xy - wz; - out[5] = 1 - (xx + zz); - out[6] = yz + wx; - out[7] = 0; - out[8] = xz + wy; - out[9] = yz - wx; - out[10] = 1 - (xx + yy); - out[11] = 0; - out[12] = v[0]; - out[13] = v[1]; - out[14] = v[2]; - out[15] = 1; - return out; -} - -function getTranslation(out, mat) { - out[0] = mat[12]; - out[1] = mat[13]; - out[2] = mat[14]; - return out; -} - -function getRotation(out, mat) { - let trace = mat[0] + mat[5] + mat[10]; - let S = 0; - if (trace > 0) { - S = Math.sqrt(trace + 1.0) * 2; - out[3] = 0.25 * S; - out[0] = (mat[6] - mat[9]) / S; - out[1] = (mat[8] - mat[2]) / S; - out[2] = (mat[1] - mat[4]) / S; - } else if ((mat[0] > mat[5]) && (mat[0] > mat[10])) { - S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2; - out[3] = (mat[6] - mat[9]) / S; - out[0] = 0.25 * S; - out[1] = (mat[1] + mat[4]) / S; - out[2] = (mat[8] + mat[2]) / S; - } else if (mat[5] > mat[10]) { - S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2; - out[3] = (mat[8] - mat[2]) / S; - out[0] = (mat[1] + mat[4]) / S; - out[1] = 0.25 * S; - out[2] = (mat[6] + mat[9]) / S; - } else { - S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2; - out[3] = (mat[1] - mat[4]) / S; - out[0] = (mat[8] + mat[2]) / S; - out[1] = (mat[6] + mat[9]) / S; - out[2] = 0.25 * S; - } - return out; -} - - - - -function perspective(out, fovy, aspect, near, far) { - let f = 1.0 / Math.tan(fovy / 2), nf; - out[0] = f / aspect; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = f; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[11] = -1; - out[12] = 0; - out[13] = 0; - out[15] = 0; - if (far != null && far !== Infinity) { - nf = 1 / (near - far); - out[10] = (far + near) * nf; - out[14] = (2 * far * near) * nf; - } else { - out[10] = -1; - out[14] = -2 * near; - } - return out; -} - -function create$1() { - let out = new ARRAY_TYPE(3); - if(ARRAY_TYPE != Float32Array) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - } - return out; -} -function clone$1(a) { - var out = new ARRAY_TYPE(3); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - return out; -} -function length(a) { - let x = a[0]; - let y = a[1]; - let z = a[2]; - return Math.sqrt(x*x + y*y + z*z); -} -function fromValues$1(x, y, z) { - let out = new ARRAY_TYPE(3); - out[0] = x; - out[1] = y; - out[2] = z; - return out; -} -function copy$1(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - return out; -} - -function add$1(out, a, b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - return out; -} - - - - - - - - -function scale$1(out, a, b) { - out[0] = a[0] * b; - out[1] = a[1] * b; - out[2] = a[2] * b; - return out; -} - - - - - - -function normalize(out, a) { - let x = a[0]; - let y = a[1]; - let z = a[2]; - let len = x*x + y*y + z*z; - if (len > 0) { - len = 1 / Math.sqrt(len); - out[0] = a[0] * len; - out[1] = a[1] * len; - out[2] = a[2] * len; - } - return out; -} -function dot(a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; -} -function cross(out, a, b) { - let ax = a[0], ay = a[1], az = a[2]; - let bx = b[0], by = b[1], bz = b[2]; - out[0] = ay * bz - az * by; - out[1] = az * bx - ax * bz; - out[2] = ax * by - ay * bx; - return out; -} - - - - - - -function transformQuat(out, a, q) { - let qx = q[0], qy = q[1], qz = q[2], qw = q[3]; - let x = a[0], y = a[1], z = a[2]; - let uvx = qy * z - qz * y, - uvy = qz * x - qx * z, - uvz = qx * y - qy * x; - let uuvx = qy * uvz - qz * uvy, - uuvy = qz * uvx - qx * uvz, - uuvz = qx * uvy - qy * uvx; - let w2 = qw * 2; - uvx *= w2; - uvy *= w2; - uvz *= w2; - uuvx *= 2; - uuvy *= 2; - uuvz *= 2; - out[0] = x + uvx + uuvx; - out[1] = y + uvy + uuvy; - out[2] = z + uvz + uuvz; - return out; -} - - - -function angle(a, b) { - let tempA = fromValues$1(a[0], a[1], a[2]); - let tempB = fromValues$1(b[0], b[1], b[2]); - normalize(tempA, tempA); - normalize(tempB, tempB); - let cosine = dot(tempA, tempB); - if(cosine > 1.0) { - return 0; - } - else if(cosine < -1.0) { - return Math.PI; - } else { - return Math.acos(cosine); - } -} - - - - - - - - -const len = length; - -const forEach = (function() { - let vec = create$1(); - return function(a, stride, offset, count, fn, arg) { - let i, l; - if(!stride) { - stride = 3; - } - if(!offset) { - offset = 0; - } - if(count) { - l = Math.min((count * stride) + offset, a.length); - } else { - l = a.length; - } - for(i = offset; i < l; i += stride) { - vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; - fn(vec, vec, arg); - a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; - } - return a; - }; -})(); - -function create$2() { - let out = new ARRAY_TYPE(9); - if(ARRAY_TYPE != Float32Array) { - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[5] = 0; - out[6] = 0; - out[7] = 0; - } - out[0] = 1; - out[4] = 1; - out[8] = 1; - return out; -} - -function create$3() { - let out = new ARRAY_TYPE(4); - if(ARRAY_TYPE != Float32Array) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 0; - } - return out; -} -function clone$3(a) { - let out = new ARRAY_TYPE(4); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; -} -function fromValues$3(x, y, z, w) { - let out = new ARRAY_TYPE(4); - out[0] = x; - out[1] = y; - out[2] = z; - out[3] = w; - return out; -} -function copy$3(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; -} - - - - - - - - - - - - - - - - - - -function normalize$1(out, a) { - let x = a[0]; - let y = a[1]; - let z = a[2]; - let w = a[3]; - let len = x*x + y*y + z*z + w*w; - if (len > 0) { - len = 1 / Math.sqrt(len); - out[0] = x * len; - out[1] = y * len; - out[2] = z * len; - out[3] = w * len; - } - return out; -} - - - - - - - - - - - - - - - -const forEach$1 = (function() { - let vec = create$3(); - return function(a, stride, offset, count, fn, arg) { - let i, l; - if(!stride) { - stride = 4; - } - if(!offset) { - offset = 0; - } - if(count) { - l = Math.min((count * stride) + offset, a.length); - } else { - l = a.length; - } - for(i = offset; i < l; i += stride) { - vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3]; - fn(vec, vec, arg); - a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3]; - } - return a; - }; -})(); - -function create$4() { - let out = new ARRAY_TYPE(4); - if(ARRAY_TYPE != Float32Array) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - } - out[3] = 1; - return out; -} - -function setAxisAngle(out, axis, rad) { - rad = rad * 0.5; - let s = Math.sin(rad); - out[0] = s * axis[0]; - out[1] = s * axis[1]; - out[2] = s * axis[2]; - out[3] = Math.cos(rad); - return out; -} - -function multiply$4(out, a, b) { - let ax = a[0], ay = a[1], az = a[2], aw = a[3]; - let bx = b[0], by = b[1], bz = b[2], bw = b[3]; - out[0] = ax * bw + aw * bx + ay * bz - az * by; - out[1] = ay * bw + aw * by + az * bx - ax * bz; - out[2] = az * bw + aw * bz + ax * by - ay * bx; - out[3] = aw * bw - ax * bx - ay * by - az * bz; - return out; -} - - - - -function slerp(out, a, b, t) { - let ax = a[0], ay = a[1], az = a[2], aw = a[3]; - let bx = b[0], by = b[1], bz = b[2], bw = b[3]; - let omega, cosom, sinom, scale0, scale1; - cosom = ax * bx + ay * by + az * bz + aw * bw; - if ( cosom < 0.0 ) { - cosom = -cosom; - bx = - bx; - by = - by; - bz = - bz; - bw = - bw; - } - if ( (1.0 - cosom) > EPSILON ) { - omega = Math.acos(cosom); - sinom = Math.sin(omega); - scale0 = Math.sin((1.0 - t) * omega) / sinom; - scale1 = Math.sin(t * omega) / sinom; - } else { - scale0 = 1.0 - t; - scale1 = t; - } - out[0] = scale0 * ax + scale1 * bx; - out[1] = scale0 * ay + scale1 * by; - out[2] = scale0 * az + scale1 * bz; - out[3] = scale0 * aw + scale1 * bw; - return out; -} - -function invert$2(out, a) { - let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; - let dot$$1 = a0*a0 + a1*a1 + a2*a2 + a3*a3; - let invDot = dot$$1 ? 1.0/dot$$1 : 0; - out[0] = -a0*invDot; - out[1] = -a1*invDot; - out[2] = -a2*invDot; - out[3] = a3*invDot; - return out; -} - -function fromMat3(out, m) { - let fTrace = m[0] + m[4] + m[8]; - let fRoot; - if ( fTrace > 0.0 ) { - fRoot = Math.sqrt(fTrace + 1.0); - out[3] = 0.5 * fRoot; - fRoot = 0.5/fRoot; - out[0] = (m[5]-m[7])*fRoot; - out[1] = (m[6]-m[2])*fRoot; - out[2] = (m[1]-m[3])*fRoot; - } else { - let i = 0; - if ( m[4] > m[0] ) - i = 1; - if ( m[8] > m[i*3+i] ) - i = 2; - let j = (i+1)%3; - let k = (i+2)%3; - fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); - out[i] = 0.5 * fRoot; - fRoot = 0.5 / fRoot; - out[3] = (m[j*3+k] - m[k*3+j]) * fRoot; - out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; - out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; - } - return out; -} -function fromEuler(out, x, y, z) { - let halfToRad = 0.5 * Math.PI / 180.0; - x *= halfToRad; - y *= halfToRad; - z *= halfToRad; - let sx = Math.sin(x); - let cx = Math.cos(x); - let sy = Math.sin(y); - let cy = Math.cos(y); - let sz = Math.sin(z); - let cz = Math.cos(z); - out[0] = sx * cy * cz - cx * sy * sz; - out[1] = cx * sy * cz + sx * cy * sz; - out[2] = cx * cy * sz - sx * sy * cz; - out[3] = cx * cy * cz + sx * sy * sz; - return out; -} - -const clone$4 = clone$3; -const fromValues$4 = fromValues$3; -const copy$4 = copy$3; - - - - - - - - - - -const normalize$2 = normalize$1; - - -const rotationTo = (function() { - let tmpvec3 = create$1(); - let xUnitVec3 = fromValues$1(1,0,0); - let yUnitVec3 = fromValues$1(0,1,0); - return function(out, a, b) { - let dot$$1 = dot(a, b); - if (dot$$1 < -0.999999) { - cross(tmpvec3, xUnitVec3, a); - if (len(tmpvec3) < 0.000001) - cross(tmpvec3, yUnitVec3, a); - normalize(tmpvec3, tmpvec3); - setAxisAngle(out, tmpvec3, Math.PI); - return out; - } else if (dot$$1 > 0.999999) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 1; - return out; - } else { - cross(tmpvec3, a, b); - out[0] = tmpvec3[0]; - out[1] = tmpvec3[1]; - out[2] = tmpvec3[2]; - out[3] = 1 + dot$$1; - return normalize$2(out, out); - } - }; -})(); -const sqlerp = (function () { - let temp1 = create$4(); - let temp2 = create$4(); - return function (out, a, b, c, d, t) { - slerp(temp1, a, d, t); - slerp(temp2, b, c, t); - slerp(out, temp1, temp2, 2 * t * (1 - t)); - return out; - }; -}()); -const setAxes = (function() { - let matr = create$2(); - return function(out, view, right, up) { - matr[0] = right[0]; - matr[3] = right[1]; - matr[6] = right[2]; - matr[1] = up[0]; - matr[4] = up[1]; - matr[7] = up[2]; - matr[2] = -view[0]; - matr[5] = -view[1]; - matr[8] = -view[2]; - return normalize$2(out, fromMat3(out, matr)); - }; -})(); - -const PRIVATE$1 = Symbol('@@webxr-polyfill/XRRigidTransform'); -class XRRigidTransform$1 { - constructor() { - this[PRIVATE$1] = { - matrix: null, - position: null, - orientation: null, - inverse: null, - }; - if (arguments.length === 0) { - this[PRIVATE$1].matrix = identity(new Float32Array(16)); - } else if (arguments.length === 1) { - if (arguments[0] instanceof Float32Array) { - this[PRIVATE$1].matrix = arguments[0]; - } else { - this[PRIVATE$1].position = this._getPoint(arguments[0]); - this[PRIVATE$1].orientation = DOMPointReadOnly.fromPoint({ - x: 0, y: 0, z: 0, w: 1 - }); - } - } else if (arguments.length === 2) { - this[PRIVATE$1].position = this._getPoint(arguments[0]); - this[PRIVATE$1].orientation = this._getPoint(arguments[1]); - } else { - throw new Error("Too many arguments!"); - } - if (this[PRIVATE$1].matrix) { - let position = create$1(); - getTranslation(position, this[PRIVATE$1].matrix); - this[PRIVATE$1].position = DOMPointReadOnly.fromPoint({ - x: position[0], - y: position[1], - z: position[2] - }); - let orientation = create$4(); - getRotation(orientation, this[PRIVATE$1].matrix); - this[PRIVATE$1].orientation = DOMPointReadOnly.fromPoint({ - x: orientation[0], - y: orientation[1], - z: orientation[2], - w: orientation[3] - }); - } else { - this[PRIVATE$1].matrix = identity(new Float32Array(16)); - fromRotationTranslation( - this[PRIVATE$1].matrix, - fromValues$4( - this[PRIVATE$1].orientation.x, - this[PRIVATE$1].orientation.y, - this[PRIVATE$1].orientation.z, - this[PRIVATE$1].orientation.w), - fromValues$1( - this[PRIVATE$1].position.x, - this[PRIVATE$1].position.y, - this[PRIVATE$1].position.z) - ); - } - } - _getPoint(arg) { - if (arg instanceof DOMPointReadOnly) { - return arg; - } - return DOMPointReadOnly.fromPoint(arg); - } - get matrix() { return this[PRIVATE$1].matrix; } - get position() { return this[PRIVATE$1].position; } - get orientation() { return this[PRIVATE$1].orientation; } - get inverse() { - if (this[PRIVATE$1].inverse === null) { - let invMatrix = identity(new Float32Array(16)); - invert(invMatrix, this[PRIVATE$1].matrix); - this[PRIVATE$1].inverse = new XRRigidTransform$1(invMatrix); - this[PRIVATE$1].inverse[PRIVATE$1].inverse = this; - } - return this[PRIVATE$1].inverse; - } -} - -const PRIVATE$2 = Symbol('@@webxr-polyfill/XRSpace'); - -class XRSpace { - constructor(specialType = null, inputSource = null) { - this[PRIVATE$2] = { - specialType, - inputSource, - baseMatrix: null, - inverseBaseMatrix: null, - lastFrameId: -1 - }; - } - get _specialType() { - return this[PRIVATE$2].specialType; - } - get _inputSource() { - return this[PRIVATE$2].inputSource; - } - _ensurePoseUpdated(device, frameId) { - if (frameId == this[PRIVATE$2].lastFrameId) return; - this[PRIVATE$2].lastFrameId = frameId; - this._onPoseUpdate(device); - } - _onPoseUpdate(device) { - if (this[PRIVATE$2].specialType == 'viewer') { - this._baseMatrix = device.getBasePoseMatrix(); - } - } - set _baseMatrix(matrix) { - this[PRIVATE$2].baseMatrix = matrix; - this[PRIVATE$2].inverseBaseMatrix = null; - } - get _baseMatrix() { - if (!this[PRIVATE$2].baseMatrix) { - if (this[PRIVATE$2].inverseBaseMatrix) { - this[PRIVATE$2].baseMatrix = new Float32Array(16); - invert(this[PRIVATE$2].baseMatrix, this[PRIVATE$2].inverseBaseMatrix); - } - } - return this[PRIVATE$2].baseMatrix; - } - set _inverseBaseMatrix(matrix) { - this[PRIVATE$2].inverseBaseMatrix = matrix; - this[PRIVATE$2].baseMatrix = null; - } - get _inverseBaseMatrix() { - if (!this[PRIVATE$2].inverseBaseMatrix) { - if (this[PRIVATE$2].baseMatrix) { - this[PRIVATE$2].inverseBaseMatrix = new Float32Array(16); - invert(this[PRIVATE$2].inverseBaseMatrix, this[PRIVATE$2].baseMatrix); - } - } - return this[PRIVATE$2].inverseBaseMatrix; - } - _getSpaceRelativeTransform(space) { - if (!this._inverseBaseMatrix || !space._baseMatrix) { - return null; - } - let out = new Float32Array(16); - multiply(out, this._inverseBaseMatrix, space._baseMatrix); - return new XRRigidTransform$1(out); - } -} - -const DEFAULT_EMULATION_HEIGHT = 1.6; -const PRIVATE$3 = Symbol('@@webxr-polyfill/XRReferenceSpace'); -const XRReferenceSpaceTypes = [ - 'viewer', - 'local', - 'local-floor', - 'bounded-floor', - 'unbounded' -]; -function isFloor(type) { - return type === 'bounded-floor' || type === 'local-floor'; -} -class XRReferenceSpace extends XRSpace { - constructor(type, transform = null) { - if (!XRReferenceSpaceTypes.includes(type)) { - throw new Error(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`); - } - super(type); - if (type === 'bounded-floor' && !transform) { - throw new Error(`XRReferenceSpace cannot use 'bounded-floor' type if the platform does not provide the floor level`); - } - if (isFloor(type) && !transform) { - transform = identity(new Float32Array(16)); - transform[13] = DEFAULT_EMULATION_HEIGHT; - } - this._inverseBaseMatrix = transform || identity(new Float32Array(16)); - this[PRIVATE$3] = { - type, - transform, - originOffset : identity(new Float32Array(16)), - }; - } - _transformBasePoseMatrix(out, pose) { - multiply(out, this._inverseBaseMatrix, pose); - } - _originOffsetMatrix() { - return this[PRIVATE$3].originOffset; - } - _adjustForOriginOffset(transformMatrix) { - let inverseOriginOffsetMatrix = new Float32Array(16); - invert(inverseOriginOffsetMatrix, this[PRIVATE$3].originOffset); - multiply(transformMatrix, inverseOriginOffsetMatrix, transformMatrix); - } - _getSpaceRelativeTransform(space) { - let transform = super._getSpaceRelativeTransform(space); - this._adjustForOriginOffset(transform.matrix); - return new XRRigidTransform(transform.matrix); - } - getOffsetReferenceSpace(additionalOffset) { - let newSpace = new XRReferenceSpace( - this[PRIVATE$3].type, - this[PRIVATE$3].transform, - this[PRIVATE$3].bounds); - multiply(newSpace[PRIVATE$3].originOffset, this[PRIVATE$3].originOffset, additionalOffset.matrix); - return newSpace; - } -} - -const PRIVATE$4 = Symbol('@@webxr-polyfill/XR'); -const XRSessionModes = ['inline', 'immersive-vr', 'immersive-ar']; -const DEFAULT_SESSION_OPTIONS = { - 'inline': { - requiredFeatures: ['viewer'], - optionalFeatures: [], - }, - 'immersive-vr': { - requiredFeatures: ['viewer', 'local'], - optionalFeatures: [], - }, - 'immersive-ar': { - requiredFeatures: ['viewer', 'local'], - optionalFeatures: [], - } -}; -const POLYFILL_REQUEST_SESSION_ERROR = -`Polyfill Error: Must call navigator.xr.isSessionSupported() with any XRSessionMode -or navigator.xr.requestSession('inline') prior to requesting an immersive -session. This is a limitation specific to the WebXR Polyfill and does not apply -to native implementations of the API.`; -class XR extends EventTarget { - constructor(devicePromise) { - super(); - this[PRIVATE$4] = { - device: null, - devicePromise, - immersiveSession: null, - inlineSessions: new Set(), - }; - devicePromise.then((device) => { this[PRIVATE$4].device = device; }); - } - async isSessionSupported(mode) { - if (!this[PRIVATE$4].device) { - await this[PRIVATE$4].devicePromise; - } - if (mode != 'inline') { - return Promise.resolve(this[PRIVATE$4].device.isSessionSupported(mode)); - } - return Promise.resolve(true); - } - async requestSession(mode, options) { - if (!this[PRIVATE$4].device) { - if (mode != 'inline') { - throw new Error(POLYFILL_REQUEST_SESSION_ERROR); - } else { - await this[PRIVATE$4].devicePromise; - } - } - if (!XRSessionModes.includes(mode)) { - throw new TypeError( - `The provided value '${mode}' is not a valid enum value of type XRSessionMode`); - } - const defaultOptions = DEFAULT_SESSION_OPTIONS[mode]; - const requiredFeatures = defaultOptions.requiredFeatures.concat( - options && options.requiredFeatures ? options.requiredFeatures : []); - const optionalFeatures = defaultOptions.optionalFeatures.concat( - options && options.optionalFeatures ? options.optionalFeatures : []); - const enabledFeatures = new Set(); - let requirementsFailed = false; - for (let feature of requiredFeatures) { - if (!this[PRIVATE$4].device.isFeatureSupported(feature)) { - console.error(`The required feature '${feature}' is not supported`); - requirementsFailed = true; - } else { - enabledFeatures.add(feature); - } - } - if (requirementsFailed) { - throw new DOMException('Session does not support some required features', 'NotSupportedError'); - } - for (let feature of optionalFeatures) { - if (!this[PRIVATE$4].device.isFeatureSupported(feature)) { - console.log(`The optional feature '${feature}' is not supported`); - } else { - enabledFeatures.add(feature); - } - } - const sessionId = await this[PRIVATE$4].device.requestSession(mode, enabledFeatures); - const session = new XRSession(this[PRIVATE$4].device, mode, sessionId); - if (mode == 'inline') { - this[PRIVATE$4].inlineSessions.add(session); - } else { - this[PRIVATE$4].immersiveSession = session; - } - const onSessionEnd = () => { - if (mode == 'inline') { - this[PRIVATE$4].inlineSessions.delete(session); - } else { - this[PRIVATE$4].immersiveSession = null; - } - session.removeEventListener('end', onSessionEnd); - }; - session.addEventListener('end', onSessionEnd); - return session; - } -} - -let now; -if ('performance' in _global === false) { - let startTime = Date.now(); - now = () => Date.now() - startTime; -} else { - now = () => performance.now(); -} -var now$1 = now; - -const PRIVATE$5 = Symbol('@@webxr-polyfill/XRPose'); -class XRPose$1 { - constructor(transform, emulatedPosition) { - this[PRIVATE$5] = { - transform, - emulatedPosition, - }; - } - get transform() { return this[PRIVATE$5].transform; } - get emulatedPosition() { return this[PRIVATE$5].emulatedPosition; } -} - -const PRIVATE$6 = Symbol('@@webxr-polyfill/XRViewerPose'); -class XRViewerPose extends XRPose$1 { - constructor(transform, views, emulatedPosition = false) { - super(transform, emulatedPosition); - this[PRIVATE$6] = { - views - }; - } - get views() { - return this[PRIVATE$6].views; - } -} - -const PRIVATE$7 = Symbol('@@webxr-polyfill/XRViewport'); -class XRViewport { - constructor(target) { - this[PRIVATE$7] = { target }; - } - get x() { return this[PRIVATE$7].target.x; } - get y() { return this[PRIVATE$7].target.y; } - get width() { return this[PRIVATE$7].target.width; } - get height() { return this[PRIVATE$7].target.height; } -} - -const XREyes = ['left', 'right', 'none']; -const PRIVATE$8 = Symbol('@@webxr-polyfill/XRView'); -class XRView { - constructor(device, transform, eye, sessionId) { - if (!XREyes.includes(eye)) { - throw new Error(`XREye must be one of: ${XREyes}`); - } - const temp = Object.create(null); - const viewport = new XRViewport(temp); - this[PRIVATE$8] = { - device, - eye, - viewport, - temp, - sessionId, - transform, - }; - } - get eye() { return this[PRIVATE$8].eye; } - get projectionMatrix() { return this[PRIVATE$8].device.getProjectionMatrix(this.eye); } - get transform() { return this[PRIVATE$8].transform; } - _getViewport(layer) { - if (this[PRIVATE$8].device.getViewport(this[PRIVATE$8].sessionId, - this.eye, - layer, - this[PRIVATE$8].temp)) { - return this[PRIVATE$8].viewport; - } - return undefined; - } -} - -const PRIVATE$9 = Symbol('@@webxr-polyfill/XRFrame'); -const NON_ACTIVE_MSG = "XRFrame access outside the callback that produced it is invalid."; -const NON_ANIMFRAME_MSG = "getViewerPose can only be called on XRFrame objects passed to XRSession.requestAnimationFrame callbacks."; -let NEXT_FRAME_ID = 0; -class XRFrame { - constructor(device, session, sessionId) { - this[PRIVATE$9] = { - id: ++NEXT_FRAME_ID, - active: false, - animationFrame: false, - device, - session, - sessionId - }; - } - get session() { return this[PRIVATE$9].session; } - getViewerPose(referenceSpace) { - if (!this[PRIVATE$9].animationFrame) { - throw new DOMException(NON_ANIMFRAME_MSG, 'InvalidStateError'); - } - if (!this[PRIVATE$9].active) { - throw new DOMException(NON_ACTIVE_MSG, 'InvalidStateError'); - } - const device = this[PRIVATE$9].device; - const session = this[PRIVATE$9].session; - session[PRIVATE$15].viewerSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); - referenceSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); - let viewerTransform = referenceSpace._getSpaceRelativeTransform(session[PRIVATE$15].viewerSpace); - const views = []; - for (let viewSpace of session[PRIVATE$15].viewSpaces) { - viewSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); - let viewTransform = referenceSpace._getSpaceRelativeTransform(viewSpace); - let view = new XRView(device, viewTransform, viewSpace.eye, this[PRIVATE$9].sessionId); - views.push(view); - } - let viewerPose = new XRViewerPose(viewerTransform, views, false ); - return viewerPose; - } - getPose(space, baseSpace) { - if (!this[PRIVATE$9].active) { - throw new DOMException(NON_ACTIVE_MSG, 'InvalidStateError'); - } - const device = this[PRIVATE$9].device; - if (space._specialType === "target-ray" || space._specialType === "grip") { - return device.getInputPose( - space._inputSource, baseSpace, space._specialType); - } else { - space._ensurePoseUpdated(device, this[PRIVATE$9].id); - baseSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); - let transform = baseSpace._getSpaceRelativeTransform(space); - if (!transform) { return null; } - return new XRPose(transform, false ); - } - return null; - } -} - -const PRIVATE$10 = Symbol('@@webxr-polyfill/XRRenderState'); -const XRRenderStateInit = Object.freeze({ - depthNear: 0.1, - depthFar: 1000.0, - inlineVerticalFieldOfView: null, - baseLayer: null -}); -class XRRenderState { - constructor(stateInit = {}) { - const config = Object.assign({}, XRRenderStateInit, stateInit); - this[PRIVATE$10] = { config }; - } - get depthNear() { return this[PRIVATE$10].config.depthNear; } - get depthFar() { return this[PRIVATE$10].config.depthFar; } - get inlineVerticalFieldOfView() { return this[PRIVATE$10].config.inlineVerticalFieldOfView; } - get baseLayer() { return this[PRIVATE$10].config.baseLayer; } -} - -const POLYFILLED_XR_COMPATIBLE = Symbol('@@webxr-polyfill/polyfilled-xr-compatible'); -const XR_COMPATIBLE = Symbol('@@webxr-polyfill/xr-compatible'); - -const PRIVATE$11 = Symbol('@@webxr-polyfill/XRWebGLLayer'); -const XRWebGLLayerInit = Object.freeze({ - antialias: true, - depth: false, - stencil: false, - alpha: true, - multiview: false, - ignoreDepthValues: false, - framebufferScaleFactor: 1.0, -}); -class XRWebGLLayer { - constructor(session, context, layerInit={}) { - const config = Object.assign({}, XRWebGLLayerInit, layerInit); - if (!(session instanceof XRSession$1)) { - throw new Error('session must be a XRSession'); - } - if (session.ended) { - throw new Error(`InvalidStateError`); - } - if (context[POLYFILLED_XR_COMPATIBLE]) { - if (context[XR_COMPATIBLE] !== true) { - throw new Error(`InvalidStateError`); - } - } - const framebuffer = context.getParameter(context.FRAMEBUFFER_BINDING); - this[PRIVATE$11] = { - context, - config, - framebuffer, - session, - }; - } - get context() { return this[PRIVATE$11].context; } - get antialias() { return this[PRIVATE$11].config.antialias; } - get ignoreDepthValues() { return true; } - get framebuffer() { return this[PRIVATE$11].framebuffer; } - get framebufferWidth() { return this[PRIVATE$11].context.drawingBufferWidth; } - get framebufferHeight() { return this[PRIVATE$11].context.drawingBufferHeight; } - get _session() { return this[PRIVATE$11].session; } - getViewport(view) { - return view._getViewport(this); - } - static getNativeFramebufferScaleFactor(session) { - if (!session) { - throw new TypeError('getNativeFramebufferScaleFactor must be passed a session.') - } - if (session[PRIVATE$15].ended) { return 0.0; } - return 1.0; - } -} - -const PRIVATE$12 = Symbol('@@webxr-polyfill/XRInputSourceEvent'); -class XRInputSourceEvent extends Event { - constructor(type, eventInitDict) { - super(type, eventInitDict); - this[PRIVATE$12] = { - frame: eventInitDict.frame, - inputSource: eventInitDict.inputSource - }; - } - get frame() { return this[PRIVATE$12].frame; } - get inputSource() { return this[PRIVATE$12].inputSource; } -} - -const PRIVATE$13 = Symbol('@@webxr-polyfill/XRSessionEvent'); -class XRSessionEvent extends Event { - constructor(type, eventInitDict) { - super(type, eventInitDict); - this[PRIVATE$13] = { - session: eventInitDict.session - }; - } - get session() { return this[PRIVATE$13].session; } -} - -const PRIVATE$14 = Symbol('@@webxr-polyfill/XRInputSourcesChangeEvent'); -class XRInputSourcesChangeEvent extends Event { - constructor(type, eventInitDict) { - super(type, eventInitDict); - this[PRIVATE$14] = { - session: eventInitDict.session, - added: eventInitDict.added, - removed: eventInitDict.removed - }; - } - get session() { return this[PRIVATE$14].session; } - get added() { return this[PRIVATE$14].added; } - get removed() { return this[PRIVATE$14].removed; } -} - -const PRIVATE$15 = Symbol('@@webxr-polyfill/XRSession'); -class XRViewSpace extends XRSpace { - constructor(eye) { - super(eye); - } - get eye() { - return this._specialType; - } - _onPoseUpdate(device) { - this._inverseBaseMatrix = device.getBaseViewMatrix(this._specialType); - } -} -class XRSession$1 extends EventTarget { - constructor(device, mode, id) { - super(); - let immersive = mode != 'inline'; - let initialRenderState = new XRRenderState({ - inlineVerticalFieldOfView: immersive ? null : Math.PI * 0.5 - }); - this[PRIVATE$15] = { - device, - mode, - immersive, - ended: false, - suspended: false, - frameCallbacks: [], - currentFrameCallbacks: null, - frameHandle: 0, - deviceFrameHandle: null, - id, - activeRenderState: initialRenderState, - pendingRenderState: null, - viewerSpace: new XRReferenceSpace("viewer"), - viewSpaces: [], - currentInputSources: [] - }; - if (immersive) { - this[PRIVATE$15].viewSpaces.push(new XRViewSpace('left'), - new XRViewSpace('right')); - } else { - this[PRIVATE$15].viewSpaces.push(new XRViewSpace('none')); - } - this[PRIVATE$15].onDeviceFrame = () => { - if (this[PRIVATE$15].ended || this[PRIVATE$15].suspended) { - return; - } - this[PRIVATE$15].deviceFrameHandle = null; - this[PRIVATE$15].startDeviceFrameLoop(); - if (this[PRIVATE$15].pendingRenderState !== null) { - this[PRIVATE$15].activeRenderState = new XRRenderState(this[PRIVATE$15].pendingRenderState); - this[PRIVATE$15].pendingRenderState = null; - if (this[PRIVATE$15].activeRenderState.baseLayer) { - this[PRIVATE$15].device.onBaseLayerSet( - this[PRIVATE$15].id, - this[PRIVATE$15].activeRenderState.baseLayer); - } - } - if (this[PRIVATE$15].activeRenderState.baseLayer === null) { - return; - } - const frame = new XRFrame(device, this, this[PRIVATE$15].id); - const callbacks = this[PRIVATE$15].currentFrameCallbacks = this[PRIVATE$15].frameCallbacks; - this[PRIVATE$15].frameCallbacks = []; - frame[PRIVATE$9].active = true; - frame[PRIVATE$9].animationFrame = true; - this[PRIVATE$15].device.onFrameStart(this[PRIVATE$15].id, this[PRIVATE$15].activeRenderState); - this._checkInputSourcesChange(); - const rightNow = now$1(); - for (let i = 0; i < callbacks.length; i++) { - try { - if (!callbacks[i].cancelled && typeof callbacks[i].callback === 'function') { - callbacks[i].callback(rightNow, frame); - } - } catch(err) { - console.error(err); - } - } - this[PRIVATE$15].currentFrameCallbacks = null; - frame[PRIVATE$9].active = false; - this[PRIVATE$15].device.onFrameEnd(this[PRIVATE$15].id); - }; - this[PRIVATE$15].startDeviceFrameLoop = () => { - if (this[PRIVATE$15].deviceFrameHandle === null) { - this[PRIVATE$15].deviceFrameHandle = this[PRIVATE$15].device.requestAnimationFrame( - this[PRIVATE$15].onDeviceFrame - ); - } - }; - this[PRIVATE$15].stopDeviceFrameLoop = () => { - const handle = this[PRIVATE$15].deviceFrameHandle; - if (handle !== null) { - this[PRIVATE$15].device.cancelAnimationFrame(handle); - this[PRIVATE$15].deviceFrameHandle = null; - } - }; - this[PRIVATE$15].onPresentationEnd = sessionId => { - if (sessionId !== this[PRIVATE$15].id) { - this[PRIVATE$15].suspended = false; - this[PRIVATE$15].startDeviceFrameLoop(); - this.dispatchEvent('focus', { session: this }); - return; - } - this[PRIVATE$15].ended = true; - this[PRIVATE$15].stopDeviceFrameLoop(); - device.removeEventListener('@webvr-polyfill/vr-present-end', this[PRIVATE$15].onPresentationEnd); - device.removeEventListener('@webvr-polyfill/vr-present-start', this[PRIVATE$15].onPresentationStart); - device.removeEventListener('@@webvr-polyfill/input-select-start', this[PRIVATE$15].onSelectStart); - device.removeEventListener('@@webvr-polyfill/input-select-end', this[PRIVATE$15].onSelectEnd); - this.dispatchEvent('end', new XRSessionEvent('end', { session: this })); - }; - device.addEventListener('@@webxr-polyfill/vr-present-end', this[PRIVATE$15].onPresentationEnd); - this[PRIVATE$15].onPresentationStart = sessionId => { - if (sessionId === this[PRIVATE$15].id) { - return; - } - this[PRIVATE$15].suspended = true; - this[PRIVATE$15].stopDeviceFrameLoop(); - this.dispatchEvent('blur', { session: this }); - }; - device.addEventListener('@@webxr-polyfill/vr-present-start', this[PRIVATE$15].onPresentationStart); - this[PRIVATE$15].onSelectStart = evt => { - if (evt.sessionId !== this[PRIVATE$15].id) { - return; - } - this[PRIVATE$15].dispatchInputSourceEvent('selectstart', evt.inputSource); - }; - device.addEventListener('@@webxr-polyfill/input-select-start', this[PRIVATE$15].onSelectStart); - this[PRIVATE$15].onSelectEnd = evt => { - if (evt.sessionId !== this[PRIVATE$15].id) { - return; - } - this[PRIVATE$15].dispatchInputSourceEvent('selectend', evt.inputSource); - this[PRIVATE$15].dispatchInputSourceEvent('select', evt.inputSource); - }; - device.addEventListener('@@webxr-polyfill/input-select-end', this[PRIVATE$15].onSelectEnd); - this[PRIVATE$15].onSqueezeStart = evt => { - if (evt.sessionId !== this[PRIVATE$15].id) { - return; - } - this[PRIVATE$15].dispatchInputSourceEvent('squeezestart', evt.inputSource); - }; - device.addEventListener('@@webxr-polyfill/input-squeeze-start', this[PRIVATE$15].onSqueezeStart); - this[PRIVATE$15].onSqueezeEnd = evt => { - if (evt.sessionId !== this[PRIVATE$15].id) { - return; - } - this[PRIVATE$15].dispatchInputSourceEvent('squeezeend', evt.inputSource); - this[PRIVATE$15].dispatchInputSourceEvent('squeeze', evt.inputSource); - }; - device.addEventListener('@@webxr-polyfill/input-squeeze-end', this[PRIVATE$15].onSqueezeEnd); - this[PRIVATE$15].dispatchInputSourceEvent = (type, inputSource) => { - const frame = new XRFrame(device, this, this[PRIVATE$15].id); - const event = new XRInputSourceEvent(type, { frame, inputSource }); - frame[PRIVATE$9].active = true; - this.dispatchEvent(type, event); - frame[PRIVATE$9].active = false; - }; - this[PRIVATE$15].startDeviceFrameLoop(); - this.onblur = undefined; - this.onfocus = undefined; - this.onresetpose = undefined; - this.onend = undefined; - this.onselect = undefined; - this.onselectstart = undefined; - this.onselectend = undefined; - } - get renderState() { return this[PRIVATE$15].activeRenderState; } - get environmentBlendMode() { - return this[PRIVATE$15].device.environmentBlendMode || 'opaque'; - } - async requestReferenceSpace(type) { - if (this[PRIVATE$15].ended) { - return; - } - if (!XRReferenceSpaceTypes.includes(type)) { - throw new TypeError(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`); - } - if (!this[PRIVATE$15].device.doesSessionSupportReferenceSpace(this[PRIVATE$15].id, type)) { - throw new DOMException(`The ${type} reference space is not supported by this session.`, 'NotSupportedError'); - } - if (type === 'viewer') { - return this[PRIVATE$15].viewerSpace; - } - let transform = await this[PRIVATE$15].device.requestFrameOfReferenceTransform(type); - if (type === 'bounded-floor') { - if (!transform) { - throw new DOMException(`${type} XRReferenceSpace not supported by this device.`, 'NotSupportedError'); - } - let bounds = this[PRIVATE$15].device.requestStageBounds(); - if (!bounds) { - throw new DOMException(`${type} XRReferenceSpace not supported by this device.`, 'NotSupportedError'); - } - throw new DOMException(`The WebXR polyfill does not support the ${type} reference space yet.`, 'NotSupportedError'); - } - return new XRReferenceSpace(type, transform); - } - requestAnimationFrame(callback) { - if (this[PRIVATE$15].ended) { - return; - } - const handle = ++this[PRIVATE$15].frameHandle; - this[PRIVATE$15].frameCallbacks.push({ - handle, - callback, - cancelled: false - }); - return handle; - } - cancelAnimationFrame(handle) { - let callbacks = this[PRIVATE$15].frameCallbacks; - let index = callbacks.findIndex(d => d && d.handle === handle); - if (index > -1) { - callbacks[index].cancelled = true; - callbacks.splice(index, 1); - } - callbacks = this[PRIVATE$15].currentFrameCallbacks; - if (callbacks) { - index = callbacks.findIndex(d => d && d.handle === handle); - if (index > -1) { - callbacks[index].cancelled = true; - } - } - } - get inputSources() { - return this[PRIVATE$15].device.getInputSources(); - } - async end() { - if (this[PRIVATE$15].ended) { - return; - } - if (this[PRIVATE$15].immersive) { - this[PRIVATE$15].ended = true; - this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/vr-present-start', - this[PRIVATE$15].onPresentationStart); - this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/vr-present-end', - this[PRIVATE$15].onPresentationEnd); - this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/input-select-start', - this[PRIVATE$15].onSelectStart); - this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/input-select-end', - this[PRIVATE$15].onSelectEnd); - this.dispatchEvent('end', new XRSessionEvent('end', { session: this })); - } - this[PRIVATE$15].stopDeviceFrameLoop(); - return this[PRIVATE$15].device.endSession(this[PRIVATE$15].id); - } - updateRenderState(newState) { - if (this[PRIVATE$15].ended) { - const message = "Can't call updateRenderState on an XRSession " + - "that has already ended."; - throw new Error(message); - } - if (newState.baseLayer && (newState.baseLayer._session !== this)) { - const message = "Called updateRenderState with a base layer that was " + - "created by a different session."; - throw new Error(message); - } - const fovSet = (newState.inlineVerticalFieldOfView !== null) && - (newState.inlineVerticalFieldOfView !== undefined); - if (fovSet) { - if (this[PRIVATE$15].immersive) { - const message = "inlineVerticalFieldOfView must not be set for an " + - "XRRenderState passed to updateRenderState for an " + - "immersive session."; - throw new Error(message); - } else { - newState.inlineVerticalFieldOfView = Math.min( - 3.13, Math.max(0.01, newState.inlineVerticalFieldOfView)); - } - } - if (this[PRIVATE$15].pendingRenderState === null) { - const activeRenderState = this[PRIVATE$15].activeRenderState; - this[PRIVATE$15].pendingRenderState = { - depthNear: activeRenderState.depthNear, - depthFar: activeRenderState.depthFar, - inlineVerticalFieldOfView: activeRenderState.inlineVerticalFieldOfView, - baseLayer: activeRenderState.baseLayer - }; - } - Object.assign(this[PRIVATE$15].pendingRenderState, newState); - } - _checkInputSourcesChange() { - const added = []; - const removed = []; - const newInputSources = this.inputSources; - const oldInputSources = this[PRIVATE$15].currentInputSources; - for (const newInputSource of newInputSources) { - if (!oldInputSources.includes(newInputSource)) { - added.push(newInputSource); - } - } - for (const oldInputSource of oldInputSources) { - if (!newInputSources.includes(oldInputSource)) { - removed.push(oldInputSource); - } - } - if (added.length > 0 || removed.length > 0) { - this.dispatchEvent('inputsourceschange', new XRInputSourcesChangeEvent('inputsourceschange', { - session: this, - added: added, - removed: removed - })); - } - this[PRIVATE$15].currentInputSources.length = 0; - for (const newInputSource of newInputSources) { - this[PRIVATE$15].currentInputSources.push(newInputSource); - } - } -} - -const PRIVATE$16 = Symbol('@@webxr-polyfill/XRInputSource'); -class XRInputSource { - constructor(impl) { - this[PRIVATE$16] = { - impl, - gripSpace: new XRSpace("grip", this), - targetRaySpace: new XRSpace("target-ray", this) - }; - } - get handedness() { return this[PRIVATE$16].impl.handedness; } - get targetRayMode() { return this[PRIVATE$16].impl.targetRayMode; } - get gripSpace() { - let mode = this[PRIVATE$16].impl.targetRayMode; - if (mode === "gaze" || mode === "screen") { - return null; - } - return this[PRIVATE$16].gripSpace; - } - get targetRaySpace() { return this[PRIVATE$16].targetRaySpace; } - get profiles() { return this[PRIVATE$16].impl.profiles; } - get gamepad() { return this[PRIVATE$16].impl.gamepad; } -} - -const PRIVATE$17 = Symbol('@@webxr-polyfill/XRReferenceSpaceEvent'); -class XRReferenceSpaceEvent extends Event { - constructor(type, eventInitDict) { - super(type, eventInitDict); - this[PRIVATE$17] = { - referenceSpace: eventInitDict.referenceSpace, - transform: eventInitDict.transform || null - }; - } - get referenceSpace() { return this[PRIVATE$17].referenceSpace; } - get transform() { return this[PRIVATE$17].transform; } -} - -var API = { - XR, - XRSession: XRSession$1, - XRSessionEvent, - XRFrame, - XRView, - XRViewport, - XRViewerPose, - XRWebGLLayer, - XRSpace, - XRReferenceSpace, - XRReferenceSpaceEvent, - XRInputSource, - XRInputSourceEvent, - XRInputSourcesChangeEvent, - XRRenderState, - XRRigidTransform: XRRigidTransform$1, - XRPose: XRPose$1, -}; - -const polyfillMakeXRCompatible = Context => { - if (typeof Context.prototype.makeXRCompatible === 'function') { - return false; - } - Context.prototype.makeXRCompatible = function () { - this[XR_COMPATIBLE] = true; - return Promise.resolve(); - }; - return true; -}; -const polyfillGetContext = (Canvas) => { - const getContext = Canvas.prototype.getContext; - Canvas.prototype.getContext = function (contextType, glAttribs) { - const ctx = getContext.call(this, contextType, glAttribs); - if (ctx) { - ctx[POLYFILLED_XR_COMPATIBLE] = true; - if (glAttribs && ('xrCompatible' in glAttribs)) { - ctx[XR_COMPATIBLE] = glAttribs.xrCompatible; - } - } - return ctx; - }; -}; - -const isImageBitmapSupported = global => - !!(global.ImageBitmapRenderingContext && - global.createImageBitmap); -const isMobile = global => { - var check = false; - (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true;})(global.navigator.userAgent||global.navigator.vendor||global.opera); - return check; -}; -const applyCanvasStylesForMinimalRendering = canvas => { - canvas.style.display = 'block'; - canvas.style.position = 'absolute'; - canvas.style.width = canvas.style.height = '1px'; - canvas.style.top = canvas.style.left = '0px'; -}; - -var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - - - -function unwrapExports (x) { - return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; -} - -function createCommonjsModule(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; -} - -var cardboardVrDisplay = createCommonjsModule(function (module, exports) { -(function (global, factory) { - module.exports = factory(); -}(commonjsGlobal, (function () { var classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -}; -var createClass = function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; -}(); -var slicedToArray = function () { - function sliceIterator(arr, i) { - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"]) _i["return"](); - } finally { - if (_d) throw _e; - } - } - return _arr; - } - return function (arr, i) { - if (Array.isArray(arr)) { - return arr; - } else if (Symbol.iterator in Object(arr)) { - return sliceIterator(arr, i); - } else { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - }; -}(); -var MIN_TIMESTEP = 0.001; -var MAX_TIMESTEP = 1; -var dataUri = function dataUri(mimeType, svg) { - return 'data:' + mimeType + ',' + encodeURIComponent(svg); -}; -var lerp = function lerp(a, b, t) { - return a + (b - a) * t; -}; -var isIOS = function () { - var isIOS = /iPad|iPhone|iPod/.test(navigator.platform); - return function () { - return isIOS; - }; -}(); -var isWebViewAndroid = function () { - var isWebViewAndroid = navigator.userAgent.indexOf('Version') !== -1 && navigator.userAgent.indexOf('Android') !== -1 && navigator.userAgent.indexOf('Chrome') !== -1; - return function () { - return isWebViewAndroid; - }; -}(); -var isSafari = function () { - var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); - return function () { - return isSafari; - }; -}(); -var isFirefoxAndroid = function () { - var isFirefoxAndroid = navigator.userAgent.indexOf('Firefox') !== -1 && navigator.userAgent.indexOf('Android') !== -1; - return function () { - return isFirefoxAndroid; - }; -}(); -var getChromeVersion = function () { - var match = navigator.userAgent.match(/.*Chrome\/([0-9]+)/); - var value = match ? parseInt(match[1], 10) : null; - return function () { - return value; - }; -}(); -var isChromeWithoutDeviceMotion = function () { - var value = false; - if (getChromeVersion() === 65) { - var match = navigator.userAgent.match(/.*Chrome\/([0-9\.]*)/); - if (match) { - var _match$1$split = match[1].split('.'), - _match$1$split2 = slicedToArray(_match$1$split, 4), - major = _match$1$split2[0], - minor = _match$1$split2[1], - branch = _match$1$split2[2], - build = _match$1$split2[3]; - value = parseInt(branch, 10) === 3325 && parseInt(build, 10) < 148; - } - } - return function () { - return value; - }; -}(); -var isR7 = function () { - var isR7 = navigator.userAgent.indexOf('R7 Build') !== -1; - return function () { - return isR7; - }; -}(); -var isLandscapeMode = function isLandscapeMode() { - var rtn = window.orientation == 90 || window.orientation == -90; - return isR7() ? !rtn : rtn; -}; -var isTimestampDeltaValid = function isTimestampDeltaValid(timestampDeltaS) { - if (isNaN(timestampDeltaS)) { - return false; - } - if (timestampDeltaS <= MIN_TIMESTEP) { - return false; - } - if (timestampDeltaS > MAX_TIMESTEP) { - return false; - } - return true; -}; -var getScreenWidth = function getScreenWidth() { - return Math.max(window.screen.width, window.screen.height) * window.devicePixelRatio; -}; -var getScreenHeight = function getScreenHeight() { - return Math.min(window.screen.width, window.screen.height) * window.devicePixelRatio; -}; -var requestFullscreen = function requestFullscreen(element) { - if (isWebViewAndroid()) { - return false; - } - if (element.requestFullscreen) { - element.requestFullscreen(); - } else if (element.webkitRequestFullscreen) { - element.webkitRequestFullscreen(); - } else if (element.mozRequestFullScreen) { - element.mozRequestFullScreen(); - } else if (element.msRequestFullscreen) { - element.msRequestFullscreen(); - } else { - return false; - } - return true; -}; -var exitFullscreen = function exitFullscreen() { - if (document.exitFullscreen) { - document.exitFullscreen(); - } else if (document.webkitExitFullscreen) { - document.webkitExitFullscreen(); - } else if (document.mozCancelFullScreen) { - document.mozCancelFullScreen(); - } else if (document.msExitFullscreen) { - document.msExitFullscreen(); - } else { - return false; - } - return true; -}; -var getFullscreenElement = function getFullscreenElement() { - return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement; -}; -var linkProgram = function linkProgram(gl, vertexSource, fragmentSource, attribLocationMap) { - var vertexShader = gl.createShader(gl.VERTEX_SHADER); - gl.shaderSource(vertexShader, vertexSource); - gl.compileShader(vertexShader); - var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); - gl.shaderSource(fragmentShader, fragmentSource); - gl.compileShader(fragmentShader); - var program = gl.createProgram(); - gl.attachShader(program, vertexShader); - gl.attachShader(program, fragmentShader); - for (var attribName in attribLocationMap) { - gl.bindAttribLocation(program, attribLocationMap[attribName], attribName); - }gl.linkProgram(program); - gl.deleteShader(vertexShader); - gl.deleteShader(fragmentShader); - return program; -}; -var getProgramUniforms = function getProgramUniforms(gl, program) { - var uniforms = {}; - var uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); - var uniformName = ''; - for (var i = 0; i < uniformCount; i++) { - var uniformInfo = gl.getActiveUniform(program, i); - uniformName = uniformInfo.name.replace('[0]', ''); - uniforms[uniformName] = gl.getUniformLocation(program, uniformName); - } - return uniforms; -}; -var orthoMatrix = function orthoMatrix(out, left, right, bottom, top, near, far) { - var lr = 1 / (left - right), - bt = 1 / (bottom - top), - nf = 1 / (near - far); - out[0] = -2 * lr; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = -2 * bt; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 2 * nf; - out[11] = 0; - out[12] = (left + right) * lr; - out[13] = (top + bottom) * bt; - out[14] = (far + near) * nf; - out[15] = 1; - return out; -}; -var isMobile = function isMobile() { - var check = false; - (function (a) { - if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true; - })(navigator.userAgent || navigator.vendor || window.opera); - return check; -}; -var extend = function extend(dest, src) { - for (var key in src) { - if (src.hasOwnProperty(key)) { - dest[key] = src[key]; - } - } - return dest; -}; -var safariCssSizeWorkaround = function safariCssSizeWorkaround(canvas) { - if (isIOS()) { - var width = canvas.style.width; - var height = canvas.style.height; - canvas.style.width = parseInt(width) + 1 + 'px'; - canvas.style.height = parseInt(height) + 'px'; - setTimeout(function () { - canvas.style.width = width; - canvas.style.height = height; - }, 100); - } - window.canvas = canvas; -}; -var frameDataFromPose = function () { - var piOver180 = Math.PI / 180.0; - var rad45 = Math.PI * 0.25; - function mat4_perspectiveFromFieldOfView(out, fov, near, far) { - var upTan = Math.tan(fov ? fov.upDegrees * piOver180 : rad45), - downTan = Math.tan(fov ? fov.downDegrees * piOver180 : rad45), - leftTan = Math.tan(fov ? fov.leftDegrees * piOver180 : rad45), - rightTan = Math.tan(fov ? fov.rightDegrees * piOver180 : rad45), - xScale = 2.0 / (leftTan + rightTan), - yScale = 2.0 / (upTan + downTan); - out[0] = xScale; - out[1] = 0.0; - out[2] = 0.0; - out[3] = 0.0; - out[4] = 0.0; - out[5] = yScale; - out[6] = 0.0; - out[7] = 0.0; - out[8] = -((leftTan - rightTan) * xScale * 0.5); - out[9] = (upTan - downTan) * yScale * 0.5; - out[10] = far / (near - far); - out[11] = -1.0; - out[12] = 0.0; - out[13] = 0.0; - out[14] = far * near / (near - far); - out[15] = 0.0; - return out; - } - function mat4_fromRotationTranslation(out, q, v) { - var x = q[0], - y = q[1], - z = q[2], - w = q[3], - x2 = x + x, - y2 = y + y, - z2 = z + z, - xx = x * x2, - xy = x * y2, - xz = x * z2, - yy = y * y2, - yz = y * z2, - zz = z * z2, - wx = w * x2, - wy = w * y2, - wz = w * z2; - out[0] = 1 - (yy + zz); - out[1] = xy + wz; - out[2] = xz - wy; - out[3] = 0; - out[4] = xy - wz; - out[5] = 1 - (xx + zz); - out[6] = yz + wx; - out[7] = 0; - out[8] = xz + wy; - out[9] = yz - wx; - out[10] = 1 - (xx + yy); - out[11] = 0; - out[12] = v[0]; - out[13] = v[1]; - out[14] = v[2]; - out[15] = 1; - return out; - } - function mat4_translate(out, a, v) { - var x = v[0], - y = v[1], - z = v[2], - a00, - a01, - a02, - a03, - a10, - a11, - a12, - a13, - a20, - a21, - a22, - a23; - if (a === out) { - out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; - out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; - out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; - out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; - } else { - a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3]; - a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7]; - a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11]; - out[0] = a00;out[1] = a01;out[2] = a02;out[3] = a03; - out[4] = a10;out[5] = a11;out[6] = a12;out[7] = a13; - out[8] = a20;out[9] = a21;out[10] = a22;out[11] = a23; - out[12] = a00 * x + a10 * y + a20 * z + a[12]; - out[13] = a01 * x + a11 * y + a21 * z + a[13]; - out[14] = a02 * x + a12 * y + a22 * z + a[14]; - out[15] = a03 * x + a13 * y + a23 * z + a[15]; - } - return out; - } - function mat4_invert(out, a) { - var a00 = a[0], - a01 = a[1], - a02 = a[2], - a03 = a[3], - a10 = a[4], - a11 = a[5], - a12 = a[6], - a13 = a[7], - a20 = a[8], - a21 = a[9], - a22 = a[10], - a23 = a[11], - a30 = a[12], - a31 = a[13], - a32 = a[14], - a33 = a[15], - b00 = a00 * a11 - a01 * a10, - b01 = a00 * a12 - a02 * a10, - b02 = a00 * a13 - a03 * a10, - b03 = a01 * a12 - a02 * a11, - b04 = a01 * a13 - a03 * a11, - b05 = a02 * a13 - a03 * a12, - b06 = a20 * a31 - a21 * a30, - b07 = a20 * a32 - a22 * a30, - b08 = a20 * a33 - a23 * a30, - b09 = a21 * a32 - a22 * a31, - b10 = a21 * a33 - a23 * a31, - b11 = a22 * a33 - a23 * a32, - det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; - if (!det) { - return null; - } - det = 1.0 / det; - out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; - out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; - out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; - out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; - out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; - out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; - out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; - out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; - out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; - out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; - out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; - out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; - out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; - out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; - out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; - out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; - return out; - } - var defaultOrientation = new Float32Array([0, 0, 0, 1]); - var defaultPosition = new Float32Array([0, 0, 0]); - function updateEyeMatrices(projection, view, pose, fov, offset, vrDisplay) { - mat4_perspectiveFromFieldOfView(projection, fov || null, vrDisplay.depthNear, vrDisplay.depthFar); - var orientation = pose.orientation || defaultOrientation; - var position = pose.position || defaultPosition; - mat4_fromRotationTranslation(view, orientation, position); - if (offset) mat4_translate(view, view, offset); - mat4_invert(view, view); - } - return function (frameData, pose, vrDisplay) { - if (!frameData || !pose) return false; - frameData.pose = pose; - frameData.timestamp = pose.timestamp; - updateEyeMatrices(frameData.leftProjectionMatrix, frameData.leftViewMatrix, pose, vrDisplay._getFieldOfView("left"), vrDisplay._getEyeOffset("left"), vrDisplay); - updateEyeMatrices(frameData.rightProjectionMatrix, frameData.rightViewMatrix, pose, vrDisplay._getFieldOfView("right"), vrDisplay._getEyeOffset("right"), vrDisplay); - return true; - }; -}(); -var isInsideCrossOriginIFrame = function isInsideCrossOriginIFrame() { - var isFramed = window.self !== window.top; - var refOrigin = getOriginFromUrl(document.referrer); - var thisOrigin = getOriginFromUrl(window.location.href); - return isFramed && refOrigin !== thisOrigin; -}; -var getOriginFromUrl = function getOriginFromUrl(url) { - var domainIdx; - var protoSepIdx = url.indexOf("://"); - if (protoSepIdx !== -1) { - domainIdx = protoSepIdx + 3; - } else { - domainIdx = 0; - } - var domainEndIdx = url.indexOf('/', domainIdx); - if (domainEndIdx === -1) { - domainEndIdx = url.length; - } - return url.substring(0, domainEndIdx); -}; -var getQuaternionAngle = function getQuaternionAngle(quat) { - if (quat.w > 1) { - console.warn('getQuaternionAngle: w > 1'); - return 0; - } - var angle = 2 * Math.acos(quat.w); - return angle; -}; -var warnOnce = function () { - var observedWarnings = {}; - return function (key, message) { - if (observedWarnings[key] === undefined) { - console.warn('webvr-polyfill: ' + message); - observedWarnings[key] = true; - } - }; -}(); -var deprecateWarning = function deprecateWarning(deprecated, suggested) { - var alternative = suggested ? 'Please use ' + suggested + ' instead.' : ''; - warnOnce(deprecated, deprecated + ' has been deprecated. ' + 'This may not work on native WebVR displays. ' + alternative); -}; -function WGLUPreserveGLState(gl, bindings, callback) { - if (!bindings) { - callback(gl); - return; - } - var boundValues = []; - var activeTexture = null; - for (var i = 0; i < bindings.length; ++i) { - var binding = bindings[i]; - switch (binding) { - case gl.TEXTURE_BINDING_2D: - case gl.TEXTURE_BINDING_CUBE_MAP: - var textureUnit = bindings[++i]; - if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) { - console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit"); - boundValues.push(null, null); - break; - } - if (!activeTexture) { - activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE); - } - gl.activeTexture(textureUnit); - boundValues.push(gl.getParameter(binding), null); - break; - case gl.ACTIVE_TEXTURE: - activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE); - boundValues.push(null); - break; - default: - boundValues.push(gl.getParameter(binding)); - break; - } - } - callback(gl); - for (var i = 0; i < bindings.length; ++i) { - var binding = bindings[i]; - var boundValue = boundValues[i]; - switch (binding) { - case gl.ACTIVE_TEXTURE: - break; - case gl.ARRAY_BUFFER_BINDING: - gl.bindBuffer(gl.ARRAY_BUFFER, boundValue); - break; - case gl.COLOR_CLEAR_VALUE: - gl.clearColor(boundValue[0], boundValue[1], boundValue[2], boundValue[3]); - break; - case gl.COLOR_WRITEMASK: - gl.colorMask(boundValue[0], boundValue[1], boundValue[2], boundValue[3]); - break; - case gl.CURRENT_PROGRAM: - gl.useProgram(boundValue); - break; - case gl.ELEMENT_ARRAY_BUFFER_BINDING: - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boundValue); - break; - case gl.FRAMEBUFFER_BINDING: - gl.bindFramebuffer(gl.FRAMEBUFFER, boundValue); - break; - case gl.RENDERBUFFER_BINDING: - gl.bindRenderbuffer(gl.RENDERBUFFER, boundValue); - break; - case gl.TEXTURE_BINDING_2D: - var textureUnit = bindings[++i]; - if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) - break; - gl.activeTexture(textureUnit); - gl.bindTexture(gl.TEXTURE_2D, boundValue); - break; - case gl.TEXTURE_BINDING_CUBE_MAP: - var textureUnit = bindings[++i]; - if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) - break; - gl.activeTexture(textureUnit); - gl.bindTexture(gl.TEXTURE_CUBE_MAP, boundValue); - break; - case gl.VIEWPORT: - gl.viewport(boundValue[0], boundValue[1], boundValue[2], boundValue[3]); - break; - case gl.BLEND: - case gl.CULL_FACE: - case gl.DEPTH_TEST: - case gl.SCISSOR_TEST: - case gl.STENCIL_TEST: - if (boundValue) { - gl.enable(binding); - } else { - gl.disable(binding); - } - break; - default: - console.log("No GL restore behavior for 0x" + binding.toString(16)); - break; - } - if (activeTexture) { - gl.activeTexture(activeTexture); - } - } -} -var glPreserveState = WGLUPreserveGLState; -var distortionVS = ['attribute vec2 position;', 'attribute vec3 texCoord;', 'varying vec2 vTexCoord;', 'uniform vec4 viewportOffsetScale[2];', 'void main() {', ' vec4 viewport = viewportOffsetScale[int(texCoord.z)];', ' vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;', ' gl_Position = vec4( position, 1.0, 1.0 );', '}'].join('\n'); -var distortionFS = ['precision mediump float;', 'uniform sampler2D diffuse;', 'varying vec2 vTexCoord;', 'void main() {', ' gl_FragColor = texture2D(diffuse, vTexCoord);', '}'].join('\n'); -function CardboardDistorter(gl, cardboardUI, bufferScale, dirtySubmitFrameBindings) { - this.gl = gl; - this.cardboardUI = cardboardUI; - this.bufferScale = bufferScale; - this.dirtySubmitFrameBindings = dirtySubmitFrameBindings; - this.ctxAttribs = gl.getContextAttributes(); - this.meshWidth = 20; - this.meshHeight = 20; - this.bufferWidth = gl.drawingBufferWidth; - this.bufferHeight = gl.drawingBufferHeight; - this.realBindFramebuffer = gl.bindFramebuffer; - this.realEnable = gl.enable; - this.realDisable = gl.disable; - this.realColorMask = gl.colorMask; - this.realClearColor = gl.clearColor; - this.realViewport = gl.viewport; - if (!isIOS()) { - this.realCanvasWidth = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'width'); - this.realCanvasHeight = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'height'); - } - this.isPatched = false; - this.lastBoundFramebuffer = null; - this.cullFace = false; - this.depthTest = false; - this.blend = false; - this.scissorTest = false; - this.stencilTest = false; - this.viewport = [0, 0, 0, 0]; - this.colorMask = [true, true, true, true]; - this.clearColor = [0, 0, 0, 0]; - this.attribs = { - position: 0, - texCoord: 1 - }; - this.program = linkProgram(gl, distortionVS, distortionFS, this.attribs); - this.uniforms = getProgramUniforms(gl, this.program); - this.viewportOffsetScale = new Float32Array(8); - this.setTextureBounds(); - this.vertexBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - this.indexCount = 0; - this.renderTarget = gl.createTexture(); - this.framebuffer = gl.createFramebuffer(); - this.depthStencilBuffer = null; - this.depthBuffer = null; - this.stencilBuffer = null; - if (this.ctxAttribs.depth && this.ctxAttribs.stencil) { - this.depthStencilBuffer = gl.createRenderbuffer(); - } else if (this.ctxAttribs.depth) { - this.depthBuffer = gl.createRenderbuffer(); - } else if (this.ctxAttribs.stencil) { - this.stencilBuffer = gl.createRenderbuffer(); - } - this.patch(); - this.onResize(); -} -CardboardDistorter.prototype.destroy = function () { - var gl = this.gl; - this.unpatch(); - gl.deleteProgram(this.program); - gl.deleteBuffer(this.vertexBuffer); - gl.deleteBuffer(this.indexBuffer); - gl.deleteTexture(this.renderTarget); - gl.deleteFramebuffer(this.framebuffer); - if (this.depthStencilBuffer) { - gl.deleteRenderbuffer(this.depthStencilBuffer); - } - if (this.depthBuffer) { - gl.deleteRenderbuffer(this.depthBuffer); - } - if (this.stencilBuffer) { - gl.deleteRenderbuffer(this.stencilBuffer); - } - if (this.cardboardUI) { - this.cardboardUI.destroy(); - } -}; -CardboardDistorter.prototype.onResize = function () { - var gl = this.gl; - var self = this; - var glState = [gl.RENDERBUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0]; - glPreserveState(gl, glState, function (gl) { - self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null); - if (self.scissorTest) { - self.realDisable.call(gl, gl.SCISSOR_TEST); - } - self.realColorMask.call(gl, true, true, true, true); - self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - self.realClearColor.call(gl, 0, 0, 0, 1); - gl.clear(gl.COLOR_BUFFER_BIT); - self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.framebuffer); - gl.bindTexture(gl.TEXTURE_2D, self.renderTarget); - gl.texImage2D(gl.TEXTURE_2D, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, self.bufferWidth, self.bufferHeight, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, gl.UNSIGNED_BYTE, null); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, self.renderTarget, 0); - if (self.ctxAttribs.depth && self.ctxAttribs.stencil) { - gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthStencilBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, self.bufferWidth, self.bufferHeight); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.depthStencilBuffer); - } else if (self.ctxAttribs.depth) { - gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, self.bufferWidth, self.bufferHeight); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, self.depthBuffer); - } else if (self.ctxAttribs.stencil) { - gl.bindRenderbuffer(gl.RENDERBUFFER, self.stencilBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, self.bufferWidth, self.bufferHeight); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.stencilBuffer); - } - if (!gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) { - console.error('Framebuffer incomplete!'); - } - self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer); - if (self.scissorTest) { - self.realEnable.call(gl, gl.SCISSOR_TEST); - } - self.realColorMask.apply(gl, self.colorMask); - self.realViewport.apply(gl, self.viewport); - self.realClearColor.apply(gl, self.clearColor); - }); - if (this.cardboardUI) { - this.cardboardUI.onResize(); - } -}; -CardboardDistorter.prototype.patch = function () { - if (this.isPatched) { - return; - } - var self = this; - var canvas = this.gl.canvas; - var gl = this.gl; - if (!isIOS()) { - canvas.width = getScreenWidth() * this.bufferScale; - canvas.height = getScreenHeight() * this.bufferScale; - Object.defineProperty(canvas, 'width', { - configurable: true, - enumerable: true, - get: function get() { - return self.bufferWidth; - }, - set: function set(value) { - self.bufferWidth = value; - self.realCanvasWidth.set.call(canvas, value); - self.onResize(); - } - }); - Object.defineProperty(canvas, 'height', { - configurable: true, - enumerable: true, - get: function get() { - return self.bufferHeight; - }, - set: function set(value) { - self.bufferHeight = value; - self.realCanvasHeight.set.call(canvas, value); - self.onResize(); - } - }); - } - this.lastBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING); - if (this.lastBoundFramebuffer == null) { - this.lastBoundFramebuffer = this.framebuffer; - this.gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer); - } - this.gl.bindFramebuffer = function (target, framebuffer) { - self.lastBoundFramebuffer = framebuffer ? framebuffer : self.framebuffer; - self.realBindFramebuffer.call(gl, target, self.lastBoundFramebuffer); - }; - this.cullFace = gl.getParameter(gl.CULL_FACE); - this.depthTest = gl.getParameter(gl.DEPTH_TEST); - this.blend = gl.getParameter(gl.BLEND); - this.scissorTest = gl.getParameter(gl.SCISSOR_TEST); - this.stencilTest = gl.getParameter(gl.STENCIL_TEST); - gl.enable = function (pname) { - switch (pname) { - case gl.CULL_FACE: - self.cullFace = true;break; - case gl.DEPTH_TEST: - self.depthTest = true;break; - case gl.BLEND: - self.blend = true;break; - case gl.SCISSOR_TEST: - self.scissorTest = true;break; - case gl.STENCIL_TEST: - self.stencilTest = true;break; - } - self.realEnable.call(gl, pname); - }; - gl.disable = function (pname) { - switch (pname) { - case gl.CULL_FACE: - self.cullFace = false;break; - case gl.DEPTH_TEST: - self.depthTest = false;break; - case gl.BLEND: - self.blend = false;break; - case gl.SCISSOR_TEST: - self.scissorTest = false;break; - case gl.STENCIL_TEST: - self.stencilTest = false;break; - } - self.realDisable.call(gl, pname); - }; - this.colorMask = gl.getParameter(gl.COLOR_WRITEMASK); - gl.colorMask = function (r, g, b, a) { - self.colorMask[0] = r; - self.colorMask[1] = g; - self.colorMask[2] = b; - self.colorMask[3] = a; - self.realColorMask.call(gl, r, g, b, a); - }; - this.clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE); - gl.clearColor = function (r, g, b, a) { - self.clearColor[0] = r; - self.clearColor[1] = g; - self.clearColor[2] = b; - self.clearColor[3] = a; - self.realClearColor.call(gl, r, g, b, a); - }; - this.viewport = gl.getParameter(gl.VIEWPORT); - gl.viewport = function (x, y, w, h) { - self.viewport[0] = x; - self.viewport[1] = y; - self.viewport[2] = w; - self.viewport[3] = h; - self.realViewport.call(gl, x, y, w, h); - }; - this.isPatched = true; - safariCssSizeWorkaround(canvas); -}; -CardboardDistorter.prototype.unpatch = function () { - if (!this.isPatched) { - return; - } - var gl = this.gl; - var canvas = this.gl.canvas; - if (!isIOS()) { - Object.defineProperty(canvas, 'width', this.realCanvasWidth); - Object.defineProperty(canvas, 'height', this.realCanvasHeight); - } - canvas.width = this.bufferWidth; - canvas.height = this.bufferHeight; - gl.bindFramebuffer = this.realBindFramebuffer; - gl.enable = this.realEnable; - gl.disable = this.realDisable; - gl.colorMask = this.realColorMask; - gl.clearColor = this.realClearColor; - gl.viewport = this.realViewport; - if (this.lastBoundFramebuffer == this.framebuffer) { - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - } - this.isPatched = false; - setTimeout(function () { - safariCssSizeWorkaround(canvas); - }, 1); -}; -CardboardDistorter.prototype.setTextureBounds = function (leftBounds, rightBounds) { - if (!leftBounds) { - leftBounds = [0, 0, 0.5, 1]; - } - if (!rightBounds) { - rightBounds = [0.5, 0, 0.5, 1]; - } - this.viewportOffsetScale[0] = leftBounds[0]; - this.viewportOffsetScale[1] = leftBounds[1]; - this.viewportOffsetScale[2] = leftBounds[2]; - this.viewportOffsetScale[3] = leftBounds[3]; - this.viewportOffsetScale[4] = rightBounds[0]; - this.viewportOffsetScale[5] = rightBounds[1]; - this.viewportOffsetScale[6] = rightBounds[2]; - this.viewportOffsetScale[7] = rightBounds[3]; -}; -CardboardDistorter.prototype.submitFrame = function () { - var gl = this.gl; - var self = this; - var glState = []; - if (!this.dirtySubmitFrameBindings) { - glState.push(gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0); - } - glPreserveState(gl, glState, function (gl) { - self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null); - if (self.cullFace) { - self.realDisable.call(gl, gl.CULL_FACE); - } - if (self.depthTest) { - self.realDisable.call(gl, gl.DEPTH_TEST); - } - if (self.blend) { - self.realDisable.call(gl, gl.BLEND); - } - if (self.scissorTest) { - self.realDisable.call(gl, gl.SCISSOR_TEST); - } - if (self.stencilTest) { - self.realDisable.call(gl, gl.STENCIL_TEST); - } - self.realColorMask.call(gl, true, true, true, true); - self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - if (self.ctxAttribs.alpha || isIOS()) { - self.realClearColor.call(gl, 0, 0, 0, 1); - gl.clear(gl.COLOR_BUFFER_BIT); - } - gl.useProgram(self.program); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer); - gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer); - gl.enableVertexAttribArray(self.attribs.position); - gl.enableVertexAttribArray(self.attribs.texCoord); - gl.vertexAttribPointer(self.attribs.position, 2, gl.FLOAT, false, 20, 0); - gl.vertexAttribPointer(self.attribs.texCoord, 3, gl.FLOAT, false, 20, 8); - gl.activeTexture(gl.TEXTURE0); - gl.uniform1i(self.uniforms.diffuse, 0); - gl.bindTexture(gl.TEXTURE_2D, self.renderTarget); - gl.uniform4fv(self.uniforms.viewportOffsetScale, self.viewportOffsetScale); - gl.drawElements(gl.TRIANGLES, self.indexCount, gl.UNSIGNED_SHORT, 0); - if (self.cardboardUI) { - self.cardboardUI.renderNoState(); - } - self.realBindFramebuffer.call(self.gl, gl.FRAMEBUFFER, self.framebuffer); - if (!self.ctxAttribs.preserveDrawingBuffer) { - self.realClearColor.call(gl, 0, 0, 0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - } - if (!self.dirtySubmitFrameBindings) { - self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer); - } - if (self.cullFace) { - self.realEnable.call(gl, gl.CULL_FACE); - } - if (self.depthTest) { - self.realEnable.call(gl, gl.DEPTH_TEST); - } - if (self.blend) { - self.realEnable.call(gl, gl.BLEND); - } - if (self.scissorTest) { - self.realEnable.call(gl, gl.SCISSOR_TEST); - } - if (self.stencilTest) { - self.realEnable.call(gl, gl.STENCIL_TEST); - } - self.realColorMask.apply(gl, self.colorMask); - self.realViewport.apply(gl, self.viewport); - if (self.ctxAttribs.alpha || !self.ctxAttribs.preserveDrawingBuffer) { - self.realClearColor.apply(gl, self.clearColor); - } - }); - if (isIOS()) { - var canvas = gl.canvas; - if (canvas.width != self.bufferWidth || canvas.height != self.bufferHeight) { - self.bufferWidth = canvas.width; - self.bufferHeight = canvas.height; - self.onResize(); - } - } -}; -CardboardDistorter.prototype.updateDeviceInfo = function (deviceInfo) { - var gl = this.gl; - var self = this; - var glState = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING]; - glPreserveState(gl, glState, function (gl) { - var vertices = self.computeMeshVertices_(self.meshWidth, self.meshHeight, deviceInfo); - gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); - if (!self.indexCount) { - var indices = self.computeMeshIndices_(self.meshWidth, self.meshHeight); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); - self.indexCount = indices.length; - } - }); -}; -CardboardDistorter.prototype.computeMeshVertices_ = function (width, height, deviceInfo) { - var vertices = new Float32Array(2 * width * height * 5); - var lensFrustum = deviceInfo.getLeftEyeVisibleTanAngles(); - var noLensFrustum = deviceInfo.getLeftEyeNoLensTanAngles(); - var viewport = deviceInfo.getLeftEyeVisibleScreenRect(noLensFrustum); - var vidx = 0; - for (var e = 0; e < 2; e++) { - for (var j = 0; j < height; j++) { - for (var i = 0; i < width; i++, vidx++) { - var u = i / (width - 1); - var v = j / (height - 1); - var s = u; - var t = v; - var x = lerp(lensFrustum[0], lensFrustum[2], u); - var y = lerp(lensFrustum[3], lensFrustum[1], v); - var d = Math.sqrt(x * x + y * y); - var r = deviceInfo.distortion.distortInverse(d); - var p = x * r / d; - var q = y * r / d; - u = (p - noLensFrustum[0]) / (noLensFrustum[2] - noLensFrustum[0]); - v = (q - noLensFrustum[3]) / (noLensFrustum[1] - noLensFrustum[3]); - u = (viewport.x + u * viewport.width - 0.5) * 2.0; - v = (viewport.y + v * viewport.height - 0.5) * 2.0; - vertices[vidx * 5 + 0] = u; - vertices[vidx * 5 + 1] = v; - vertices[vidx * 5 + 2] = s; - vertices[vidx * 5 + 3] = t; - vertices[vidx * 5 + 4] = e; - } - } - var w = lensFrustum[2] - lensFrustum[0]; - lensFrustum[0] = -(w + lensFrustum[0]); - lensFrustum[2] = w - lensFrustum[2]; - w = noLensFrustum[2] - noLensFrustum[0]; - noLensFrustum[0] = -(w + noLensFrustum[0]); - noLensFrustum[2] = w - noLensFrustum[2]; - viewport.x = 1 - (viewport.x + viewport.width); - } - return vertices; -}; -CardboardDistorter.prototype.computeMeshIndices_ = function (width, height) { - var indices = new Uint16Array(2 * (width - 1) * (height - 1) * 6); - var halfwidth = width / 2; - var halfheight = height / 2; - var vidx = 0; - var iidx = 0; - for (var e = 0; e < 2; e++) { - for (var j = 0; j < height; j++) { - for (var i = 0; i < width; i++, vidx++) { - if (i == 0 || j == 0) continue; - if (i <= halfwidth == j <= halfheight) { - indices[iidx++] = vidx; - indices[iidx++] = vidx - width - 1; - indices[iidx++] = vidx - width; - indices[iidx++] = vidx - width - 1; - indices[iidx++] = vidx; - indices[iidx++] = vidx - 1; - } else { - indices[iidx++] = vidx - 1; - indices[iidx++] = vidx - width; - indices[iidx++] = vidx; - indices[iidx++] = vidx - width; - indices[iidx++] = vidx - 1; - indices[iidx++] = vidx - width - 1; - } - } - } - } - return indices; -}; -CardboardDistorter.prototype.getOwnPropertyDescriptor_ = function (proto, attrName) { - var descriptor = Object.getOwnPropertyDescriptor(proto, attrName); - if (descriptor.get === undefined || descriptor.set === undefined) { - descriptor.configurable = true; - descriptor.enumerable = true; - descriptor.get = function () { - return this.getAttribute(attrName); - }; - descriptor.set = function (val) { - this.setAttribute(attrName, val); - }; - } - return descriptor; -}; -var uiVS = ['attribute vec2 position;', 'uniform mat4 projectionMat;', 'void main() {', ' gl_Position = projectionMat * vec4( position, -1.0, 1.0 );', '}'].join('\n'); -var uiFS = ['precision mediump float;', 'uniform vec4 color;', 'void main() {', ' gl_FragColor = color;', '}'].join('\n'); -var DEG2RAD = Math.PI / 180.0; -var kAnglePerGearSection = 60; -var kOuterRimEndAngle = 12; -var kInnerRimBeginAngle = 20; -var kOuterRadius = 1; -var kMiddleRadius = 0.75; -var kInnerRadius = 0.3125; -var kCenterLineThicknessDp = 4; -var kButtonWidthDp = 28; -var kTouchSlopFactor = 1.5; -function CardboardUI(gl) { - this.gl = gl; - this.attribs = { - position: 0 - }; - this.program = linkProgram(gl, uiVS, uiFS, this.attribs); - this.uniforms = getProgramUniforms(gl, this.program); - this.vertexBuffer = gl.createBuffer(); - this.gearOffset = 0; - this.gearVertexCount = 0; - this.arrowOffset = 0; - this.arrowVertexCount = 0; - this.projMat = new Float32Array(16); - this.listener = null; - this.onResize(); -} -CardboardUI.prototype.destroy = function () { - var gl = this.gl; - if (this.listener) { - gl.canvas.removeEventListener('click', this.listener, false); - } - gl.deleteProgram(this.program); - gl.deleteBuffer(this.vertexBuffer); -}; -CardboardUI.prototype.listen = function (optionsCallback, backCallback) { - var canvas = this.gl.canvas; - this.listener = function (event) { - var midline = canvas.clientWidth / 2; - var buttonSize = kButtonWidthDp * kTouchSlopFactor; - if (event.clientX > midline - buttonSize && event.clientX < midline + buttonSize && event.clientY > canvas.clientHeight - buttonSize) { - optionsCallback(event); - } - else if (event.clientX < buttonSize && event.clientY < buttonSize) { - backCallback(event); - } - }; - canvas.addEventListener('click', this.listener, false); -}; -CardboardUI.prototype.onResize = function () { - var gl = this.gl; - var self = this; - var glState = [gl.ARRAY_BUFFER_BINDING]; - glPreserveState(gl, glState, function (gl) { - var vertices = []; - var midline = gl.drawingBufferWidth / 2; - var physicalPixels = Math.max(screen.width, screen.height) * window.devicePixelRatio; - var scalingRatio = gl.drawingBufferWidth / physicalPixels; - var dps = scalingRatio * window.devicePixelRatio; - var lineWidth = kCenterLineThicknessDp * dps / 2; - var buttonSize = kButtonWidthDp * kTouchSlopFactor * dps; - var buttonScale = kButtonWidthDp * dps / 2; - var buttonBorder = (kButtonWidthDp * kTouchSlopFactor - kButtonWidthDp) * dps; - vertices.push(midline - lineWidth, buttonSize); - vertices.push(midline - lineWidth, gl.drawingBufferHeight); - vertices.push(midline + lineWidth, buttonSize); - vertices.push(midline + lineWidth, gl.drawingBufferHeight); - self.gearOffset = vertices.length / 2; - function addGearSegment(theta, r) { - var angle = (90 - theta) * DEG2RAD; - var x = Math.cos(angle); - var y = Math.sin(angle); - vertices.push(kInnerRadius * x * buttonScale + midline, kInnerRadius * y * buttonScale + buttonScale); - vertices.push(r * x * buttonScale + midline, r * y * buttonScale + buttonScale); - } - for (var i = 0; i <= 6; i++) { - var segmentTheta = i * kAnglePerGearSection; - addGearSegment(segmentTheta, kOuterRadius); - addGearSegment(segmentTheta + kOuterRimEndAngle, kOuterRadius); - addGearSegment(segmentTheta + kInnerRimBeginAngle, kMiddleRadius); - addGearSegment(segmentTheta + (kAnglePerGearSection - kInnerRimBeginAngle), kMiddleRadius); - addGearSegment(segmentTheta + (kAnglePerGearSection - kOuterRimEndAngle), kOuterRadius); - } - self.gearVertexCount = vertices.length / 2 - self.gearOffset; - self.arrowOffset = vertices.length / 2; - function addArrowVertex(x, y) { - vertices.push(buttonBorder + x, gl.drawingBufferHeight - buttonBorder - y); - } - var angledLineWidth = lineWidth / Math.sin(45 * DEG2RAD); - addArrowVertex(0, buttonScale); - addArrowVertex(buttonScale, 0); - addArrowVertex(buttonScale + angledLineWidth, angledLineWidth); - addArrowVertex(angledLineWidth, buttonScale + angledLineWidth); - addArrowVertex(angledLineWidth, buttonScale - angledLineWidth); - addArrowVertex(0, buttonScale); - addArrowVertex(buttonScale, buttonScale * 2); - addArrowVertex(buttonScale + angledLineWidth, buttonScale * 2 - angledLineWidth); - addArrowVertex(angledLineWidth, buttonScale - angledLineWidth); - addArrowVertex(0, buttonScale); - addArrowVertex(angledLineWidth, buttonScale - lineWidth); - addArrowVertex(kButtonWidthDp * dps, buttonScale - lineWidth); - addArrowVertex(angledLineWidth, buttonScale + lineWidth); - addArrowVertex(kButtonWidthDp * dps, buttonScale + lineWidth); - self.arrowVertexCount = vertices.length / 2 - self.arrowOffset; - gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); - }); -}; -CardboardUI.prototype.render = function () { - var gl = this.gl; - var self = this; - var glState = [gl.CULL_FACE, gl.DEPTH_TEST, gl.BLEND, gl.SCISSOR_TEST, gl.STENCIL_TEST, gl.COLOR_WRITEMASK, gl.VIEWPORT, gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING]; - glPreserveState(gl, glState, function (gl) { - gl.disable(gl.CULL_FACE); - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.BLEND); - gl.disable(gl.SCISSOR_TEST); - gl.disable(gl.STENCIL_TEST); - gl.colorMask(true, true, true, true); - gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - self.renderNoState(); - }); -}; -CardboardUI.prototype.renderNoState = function () { - var gl = this.gl; - gl.useProgram(this.program); - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.enableVertexAttribArray(this.attribs.position); - gl.vertexAttribPointer(this.attribs.position, 2, gl.FLOAT, false, 8, 0); - gl.uniform4f(this.uniforms.color, 1.0, 1.0, 1.0, 1.0); - orthoMatrix(this.projMat, 0, gl.drawingBufferWidth, 0, gl.drawingBufferHeight, 0.1, 1024.0); - gl.uniformMatrix4fv(this.uniforms.projectionMat, false, this.projMat); - gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); - gl.drawArrays(gl.TRIANGLE_STRIP, this.gearOffset, this.gearVertexCount); - gl.drawArrays(gl.TRIANGLE_STRIP, this.arrowOffset, this.arrowVertexCount); -}; -function Distortion(coefficients) { - this.coefficients = coefficients; -} -Distortion.prototype.distortInverse = function (radius) { - var r0 = 0; - var r1 = 1; - var dr0 = radius - this.distort(r0); - while (Math.abs(r1 - r0) > 0.0001 ) { - var dr1 = radius - this.distort(r1); - var r2 = r1 - dr1 * ((r1 - r0) / (dr1 - dr0)); - r0 = r1; - r1 = r2; - dr0 = dr1; - } - return r1; -}; -Distortion.prototype.distort = function (radius) { - var r2 = radius * radius; - var ret = 0; - for (var i = 0; i < this.coefficients.length; i++) { - ret = r2 * (ret + this.coefficients[i]); - } - return (ret + 1) * radius; -}; -var degToRad = Math.PI / 180; -var radToDeg = 180 / Math.PI; -var Vector3 = function Vector3(x, y, z) { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; -}; -Vector3.prototype = { - constructor: Vector3, - set: function set(x, y, z) { - this.x = x; - this.y = y; - this.z = z; - return this; - }, - copy: function copy(v) { - this.x = v.x; - this.y = v.y; - this.z = v.z; - return this; - }, - length: function length() { - return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); - }, - normalize: function normalize() { - var scalar = this.length(); - if (scalar !== 0) { - var invScalar = 1 / scalar; - this.multiplyScalar(invScalar); - } else { - this.x = 0; - this.y = 0; - this.z = 0; - } - return this; - }, - multiplyScalar: function multiplyScalar(scalar) { - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - }, - applyQuaternion: function applyQuaternion(q) { - var x = this.x; - var y = this.y; - var z = this.z; - var qx = q.x; - var qy = q.y; - var qz = q.z; - var qw = q.w; - var ix = qw * x + qy * z - qz * y; - var iy = qw * y + qz * x - qx * z; - var iz = qw * z + qx * y - qy * x; - var iw = -qx * x - qy * y - qz * z; - this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; - this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; - this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; - return this; - }, - dot: function dot(v) { - return this.x * v.x + this.y * v.y + this.z * v.z; - }, - crossVectors: function crossVectors(a, b) { - var ax = a.x, - ay = a.y, - az = a.z; - var bx = b.x, - by = b.y, - bz = b.z; - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; - return this; - } -}; -var Quaternion = function Quaternion(x, y, z, w) { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = w !== undefined ? w : 1; -}; -Quaternion.prototype = { - constructor: Quaternion, - set: function set(x, y, z, w) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - return this; - }, - copy: function copy(quaternion) { - this.x = quaternion.x; - this.y = quaternion.y; - this.z = quaternion.z; - this.w = quaternion.w; - return this; - }, - setFromEulerXYZ: function setFromEulerXYZ(x, y, z) { - var c1 = Math.cos(x / 2); - var c2 = Math.cos(y / 2); - var c3 = Math.cos(z / 2); - var s1 = Math.sin(x / 2); - var s2 = Math.sin(y / 2); - var s3 = Math.sin(z / 2); - this.x = s1 * c2 * c3 + c1 * s2 * s3; - this.y = c1 * s2 * c3 - s1 * c2 * s3; - this.z = c1 * c2 * s3 + s1 * s2 * c3; - this.w = c1 * c2 * c3 - s1 * s2 * s3; - return this; - }, - setFromEulerYXZ: function setFromEulerYXZ(x, y, z) { - var c1 = Math.cos(x / 2); - var c2 = Math.cos(y / 2); - var c3 = Math.cos(z / 2); - var s1 = Math.sin(x / 2); - var s2 = Math.sin(y / 2); - var s3 = Math.sin(z / 2); - this.x = s1 * c2 * c3 + c1 * s2 * s3; - this.y = c1 * s2 * c3 - s1 * c2 * s3; - this.z = c1 * c2 * s3 - s1 * s2 * c3; - this.w = c1 * c2 * c3 + s1 * s2 * s3; - return this; - }, - setFromAxisAngle: function setFromAxisAngle(axis, angle) { - var halfAngle = angle / 2, - s = Math.sin(halfAngle); - this.x = axis.x * s; - this.y = axis.y * s; - this.z = axis.z * s; - this.w = Math.cos(halfAngle); - return this; - }, - multiply: function multiply(q) { - return this.multiplyQuaternions(this, q); - }, - multiplyQuaternions: function multiplyQuaternions(a, b) { - var qax = a.x, - qay = a.y, - qaz = a.z, - qaw = a.w; - var qbx = b.x, - qby = b.y, - qbz = b.z, - qbw = b.w; - this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; - this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; - this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; - this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - return this; - }, - inverse: function inverse() { - this.x *= -1; - this.y *= -1; - this.z *= -1; - this.normalize(); - return this; - }, - normalize: function normalize() { - var l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); - if (l === 0) { - this.x = 0; - this.y = 0; - this.z = 0; - this.w = 1; - } else { - l = 1 / l; - this.x = this.x * l; - this.y = this.y * l; - this.z = this.z * l; - this.w = this.w * l; - } - return this; - }, - slerp: function slerp(qb, t) { - if (t === 0) return this; - if (t === 1) return this.copy(qb); - var x = this.x, - y = this.y, - z = this.z, - w = this.w; - var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z; - if (cosHalfTheta < 0) { - this.w = -qb.w; - this.x = -qb.x; - this.y = -qb.y; - this.z = -qb.z; - cosHalfTheta = -cosHalfTheta; - } else { - this.copy(qb); - } - if (cosHalfTheta >= 1.0) { - this.w = w; - this.x = x; - this.y = y; - this.z = z; - return this; - } - var halfTheta = Math.acos(cosHalfTheta); - var sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); - if (Math.abs(sinHalfTheta) < 0.001) { - this.w = 0.5 * (w + this.w); - this.x = 0.5 * (x + this.x); - this.y = 0.5 * (y + this.y); - this.z = 0.5 * (z + this.z); - return this; - } - var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta, - ratioB = Math.sin(t * halfTheta) / sinHalfTheta; - this.w = w * ratioA + this.w * ratioB; - this.x = x * ratioA + this.x * ratioB; - this.y = y * ratioA + this.y * ratioB; - this.z = z * ratioA + this.z * ratioB; - return this; - }, - setFromUnitVectors: function () { - var v1, r; - var EPS = 0.000001; - return function (vFrom, vTo) { - if (v1 === undefined) v1 = new Vector3(); - r = vFrom.dot(vTo) + 1; - if (r < EPS) { - r = 0; - if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) { - v1.set(-vFrom.y, vFrom.x, 0); - } else { - v1.set(0, -vFrom.z, vFrom.y); - } - } else { - v1.crossVectors(vFrom, vTo); - } - this.x = v1.x; - this.y = v1.y; - this.z = v1.z; - this.w = r; - this.normalize(); - return this; - }; - }() -}; -function Device(params) { - this.width = params.width || getScreenWidth(); - this.height = params.height || getScreenHeight(); - this.widthMeters = params.widthMeters; - this.heightMeters = params.heightMeters; - this.bevelMeters = params.bevelMeters; -} -var DEFAULT_ANDROID = new Device({ - widthMeters: 0.110, - heightMeters: 0.062, - bevelMeters: 0.004 -}); -var DEFAULT_IOS = new Device({ - widthMeters: 0.1038, - heightMeters: 0.0584, - bevelMeters: 0.004 -}); -var Viewers = { - CardboardV1: new CardboardViewer({ - id: 'CardboardV1', - label: 'Cardboard I/O 2014', - fov: 40, - interLensDistance: 0.060, - baselineLensDistance: 0.035, - screenLensDistance: 0.042, - distortionCoefficients: [0.441, 0.156], - inverseCoefficients: [-0.4410035, 0.42756155, -0.4804439, 0.5460139, -0.58821183, 0.5733938, -0.48303202, 0.33299083, -0.17573841, 0.0651772, -0.01488963, 0.001559834] - }), - CardboardV2: new CardboardViewer({ - id: 'CardboardV2', - label: 'Cardboard I/O 2015', - fov: 60, - interLensDistance: 0.064, - baselineLensDistance: 0.035, - screenLensDistance: 0.039, - distortionCoefficients: [0.34, 0.55], - inverseCoefficients: [-0.33836704, -0.18162185, 0.862655, -1.2462051, 1.0560602, -0.58208317, 0.21609078, -0.05444823, 0.009177956, -9.904169E-4, 6.183535E-5, -1.6981803E-6] - }) -}; -function DeviceInfo(deviceParams, additionalViewers) { - this.viewer = Viewers.CardboardV2; - this.updateDeviceParams(deviceParams); - this.distortion = new Distortion(this.viewer.distortionCoefficients); - for (var i = 0; i < additionalViewers.length; i++) { - var viewer = additionalViewers[i]; - Viewers[viewer.id] = new CardboardViewer(viewer); - } -} -DeviceInfo.prototype.updateDeviceParams = function (deviceParams) { - this.device = this.determineDevice_(deviceParams) || this.device; -}; -DeviceInfo.prototype.getDevice = function () { - return this.device; -}; -DeviceInfo.prototype.setViewer = function (viewer) { - this.viewer = viewer; - this.distortion = new Distortion(this.viewer.distortionCoefficients); -}; -DeviceInfo.prototype.determineDevice_ = function (deviceParams) { - if (!deviceParams) { - if (isIOS()) { - console.warn('Using fallback iOS device measurements.'); - return DEFAULT_IOS; - } else { - console.warn('Using fallback Android device measurements.'); - return DEFAULT_ANDROID; - } - } - var METERS_PER_INCH = 0.0254; - var metersPerPixelX = METERS_PER_INCH / deviceParams.xdpi; - var metersPerPixelY = METERS_PER_INCH / deviceParams.ydpi; - var width = getScreenWidth(); - var height = getScreenHeight(); - return new Device({ - widthMeters: metersPerPixelX * width, - heightMeters: metersPerPixelY * height, - bevelMeters: deviceParams.bevelMm * 0.001 - }); -}; -DeviceInfo.prototype.getDistortedFieldOfViewLeftEye = function () { - var viewer = this.viewer; - var device = this.device; - var distortion = this.distortion; - var eyeToScreenDistance = viewer.screenLensDistance; - var outerDist = (device.widthMeters - viewer.interLensDistance) / 2; - var innerDist = viewer.interLensDistance / 2; - var bottomDist = viewer.baselineLensDistance - device.bevelMeters; - var topDist = device.heightMeters - bottomDist; - var outerAngle = radToDeg * Math.atan(distortion.distort(outerDist / eyeToScreenDistance)); - var innerAngle = radToDeg * Math.atan(distortion.distort(innerDist / eyeToScreenDistance)); - var bottomAngle = radToDeg * Math.atan(distortion.distort(bottomDist / eyeToScreenDistance)); - var topAngle = radToDeg * Math.atan(distortion.distort(topDist / eyeToScreenDistance)); - return { - leftDegrees: Math.min(outerAngle, viewer.fov), - rightDegrees: Math.min(innerAngle, viewer.fov), - downDegrees: Math.min(bottomAngle, viewer.fov), - upDegrees: Math.min(topAngle, viewer.fov) - }; -}; -DeviceInfo.prototype.getLeftEyeVisibleTanAngles = function () { - var viewer = this.viewer; - var device = this.device; - var distortion = this.distortion; - var fovLeft = Math.tan(-degToRad * viewer.fov); - var fovTop = Math.tan(degToRad * viewer.fov); - var fovRight = Math.tan(degToRad * viewer.fov); - var fovBottom = Math.tan(-degToRad * viewer.fov); - var halfWidth = device.widthMeters / 4; - var halfHeight = device.heightMeters / 2; - var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight; - var centerX = viewer.interLensDistance / 2 - halfWidth; - var centerY = -verticalLensOffset; - var centerZ = viewer.screenLensDistance; - var screenLeft = distortion.distort((centerX - halfWidth) / centerZ); - var screenTop = distortion.distort((centerY + halfHeight) / centerZ); - var screenRight = distortion.distort((centerX + halfWidth) / centerZ); - var screenBottom = distortion.distort((centerY - halfHeight) / centerZ); - var result = new Float32Array(4); - result[0] = Math.max(fovLeft, screenLeft); - result[1] = Math.min(fovTop, screenTop); - result[2] = Math.min(fovRight, screenRight); - result[3] = Math.max(fovBottom, screenBottom); - return result; -}; -DeviceInfo.prototype.getLeftEyeNoLensTanAngles = function () { - var viewer = this.viewer; - var device = this.device; - var distortion = this.distortion; - var result = new Float32Array(4); - var fovLeft = distortion.distortInverse(Math.tan(-degToRad * viewer.fov)); - var fovTop = distortion.distortInverse(Math.tan(degToRad * viewer.fov)); - var fovRight = distortion.distortInverse(Math.tan(degToRad * viewer.fov)); - var fovBottom = distortion.distortInverse(Math.tan(-degToRad * viewer.fov)); - var halfWidth = device.widthMeters / 4; - var halfHeight = device.heightMeters / 2; - var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight; - var centerX = viewer.interLensDistance / 2 - halfWidth; - var centerY = -verticalLensOffset; - var centerZ = viewer.screenLensDistance; - var screenLeft = (centerX - halfWidth) / centerZ; - var screenTop = (centerY + halfHeight) / centerZ; - var screenRight = (centerX + halfWidth) / centerZ; - var screenBottom = (centerY - halfHeight) / centerZ; - result[0] = Math.max(fovLeft, screenLeft); - result[1] = Math.min(fovTop, screenTop); - result[2] = Math.min(fovRight, screenRight); - result[3] = Math.max(fovBottom, screenBottom); - return result; -}; -DeviceInfo.prototype.getLeftEyeVisibleScreenRect = function (undistortedFrustum) { - var viewer = this.viewer; - var device = this.device; - var dist = viewer.screenLensDistance; - var eyeX = (device.widthMeters - viewer.interLensDistance) / 2; - var eyeY = viewer.baselineLensDistance - device.bevelMeters; - var left = (undistortedFrustum[0] * dist + eyeX) / device.widthMeters; - var top = (undistortedFrustum[1] * dist + eyeY) / device.heightMeters; - var right = (undistortedFrustum[2] * dist + eyeX) / device.widthMeters; - var bottom = (undistortedFrustum[3] * dist + eyeY) / device.heightMeters; - return { - x: left, - y: bottom, - width: right - left, - height: top - bottom - }; -}; -DeviceInfo.prototype.getFieldOfViewLeftEye = function (opt_isUndistorted) { - return opt_isUndistorted ? this.getUndistortedFieldOfViewLeftEye() : this.getDistortedFieldOfViewLeftEye(); -}; -DeviceInfo.prototype.getFieldOfViewRightEye = function (opt_isUndistorted) { - var fov = this.getFieldOfViewLeftEye(opt_isUndistorted); - return { - leftDegrees: fov.rightDegrees, - rightDegrees: fov.leftDegrees, - upDegrees: fov.upDegrees, - downDegrees: fov.downDegrees - }; -}; -DeviceInfo.prototype.getUndistortedFieldOfViewLeftEye = function () { - var p = this.getUndistortedParams_(); - return { - leftDegrees: radToDeg * Math.atan(p.outerDist), - rightDegrees: radToDeg * Math.atan(p.innerDist), - downDegrees: radToDeg * Math.atan(p.bottomDist), - upDegrees: radToDeg * Math.atan(p.topDist) - }; -}; -DeviceInfo.prototype.getUndistortedViewportLeftEye = function () { - var p = this.getUndistortedParams_(); - var viewer = this.viewer; - var device = this.device; - var eyeToScreenDistance = viewer.screenLensDistance; - var screenWidth = device.widthMeters / eyeToScreenDistance; - var screenHeight = device.heightMeters / eyeToScreenDistance; - var xPxPerTanAngle = device.width / screenWidth; - var yPxPerTanAngle = device.height / screenHeight; - var x = Math.round((p.eyePosX - p.outerDist) * xPxPerTanAngle); - var y = Math.round((p.eyePosY - p.bottomDist) * yPxPerTanAngle); - return { - x: x, - y: y, - width: Math.round((p.eyePosX + p.innerDist) * xPxPerTanAngle) - x, - height: Math.round((p.eyePosY + p.topDist) * yPxPerTanAngle) - y - }; -}; -DeviceInfo.prototype.getUndistortedParams_ = function () { - var viewer = this.viewer; - var device = this.device; - var distortion = this.distortion; - var eyeToScreenDistance = viewer.screenLensDistance; - var halfLensDistance = viewer.interLensDistance / 2 / eyeToScreenDistance; - var screenWidth = device.widthMeters / eyeToScreenDistance; - var screenHeight = device.heightMeters / eyeToScreenDistance; - var eyePosX = screenWidth / 2 - halfLensDistance; - var eyePosY = (viewer.baselineLensDistance - device.bevelMeters) / eyeToScreenDistance; - var maxFov = viewer.fov; - var viewerMax = distortion.distortInverse(Math.tan(degToRad * maxFov)); - var outerDist = Math.min(eyePosX, viewerMax); - var innerDist = Math.min(halfLensDistance, viewerMax); - var bottomDist = Math.min(eyePosY, viewerMax); - var topDist = Math.min(screenHeight - eyePosY, viewerMax); - return { - outerDist: outerDist, - innerDist: innerDist, - topDist: topDist, - bottomDist: bottomDist, - eyePosX: eyePosX, - eyePosY: eyePosY - }; -}; -function CardboardViewer(params) { - this.id = params.id; - this.label = params.label; - this.fov = params.fov; - this.interLensDistance = params.interLensDistance; - this.baselineLensDistance = params.baselineLensDistance; - this.screenLensDistance = params.screenLensDistance; - this.distortionCoefficients = params.distortionCoefficients; - this.inverseCoefficients = params.inverseCoefficients; -} -DeviceInfo.Viewers = Viewers; -var format = 1; -var last_updated = "2019-11-09T17:36:14Z"; -var devices = [{"type":"android","rules":[{"mdmh":"asus/*/Nexus 7/*"},{"ua":"Nexus 7"}],"dpi":[320.8,323],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_X00PD/*"},{"ua":"ASUS_X00PD"}],"dpi":245,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_X008D/*"},{"ua":"ASUS_X008D"}],"dpi":282,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_Z00AD/*"},{"ua":"ASUS_Z00AD"}],"dpi":[403,404.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2 XL/*"},{"ua":"Pixel 2 XL"}],"dpi":537.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3 XL/*"},{"ua":"Pixel 3 XL"}],"dpi":[558.5,553.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel XL/*"},{"ua":"Pixel XL"}],"dpi":[537.9,533],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3/*"},{"ua":"Pixel 3"}],"dpi":442.4,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2/*"},{"ua":"Pixel 2"}],"dpi":441,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Google/*/Pixel/*"},{"ua":"Pixel"}],"dpi":[432.6,436.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC6435LVW/*"},{"ua":"HTC6435LVW"}],"dpi":[449.7,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One XL/*"},{"ua":"HTC One XL"}],"dpi":[315.3,314.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"htc/*/Nexus 9/*"},{"ua":"Nexus 9"}],"dpi":289,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One M9/*"},{"ua":"HTC One M9"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One_M8/*"},{"ua":"HTC One_M8"}],"dpi":[449.7,447.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One/*"},{"ua":"HTC One"}],"dpi":472.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/Nexus 6P/*"},{"ua":"Nexus 6P"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/BLN-L24/*"},{"ua":"HONORBLN-L24"}],"dpi":480,"bw":4,"ac":500},{"type":"android","rules":[{"mdmh":"Huawei/*/BKL-L09/*"},{"ua":"BKL-L09"}],"dpi":403,"bw":3.47,"ac":500},{"type":"android","rules":[{"mdmh":"LENOVO/*/Lenovo PB2-690Y/*"},{"ua":"Lenovo PB2-690Y"}],"dpi":[457.2,454.713],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5X/*"},{"ua":"Nexus 5X"}],"dpi":[422,419.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS345/*"},{"ua":"LGMS345"}],"dpi":[221.7,219.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D800/*"},{"ua":"LG-D800"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D850/*"},{"ua":"LG-D850"}],"dpi":[537.9,541.9],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/VS985 4G/*"},{"ua":"VS985 4G"}],"dpi":[537.9,535.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5/*"},{"ua":"Nexus 5 B"}],"dpi":[442.4,444.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 4/*"},{"ua":"Nexus 4"}],"dpi":[319.8,318.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LG-P769/*"},{"ua":"LG-P769"}],"dpi":[240.6,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS323/*"},{"ua":"LGMS323"}],"dpi":[206.6,204.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGLS996/*"},{"ua":"LGLS996"}],"dpi":[403.4,401.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/4560MMX/*"},{"ua":"4560MMX"}],"dpi":[240,219.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/A250/*"},{"ua":"Micromax A250"}],"dpi":[480,446.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/Micromax AQ4501/*"},{"ua":"Micromax AQ4501"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/G5/*"},{"ua":"Moto G (5) Plus"}],"dpi":[403.4,403],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/DROID RAZR/*"},{"ua":"DROID RAZR"}],"dpi":[368.1,256.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT830C/*"},{"ua":"XT830C"}],"dpi":[254,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1021/*"},{"ua":"XT1021"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1023/*"},{"ua":"XT1023"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1028/*"},{"ua":"XT1028"}],"dpi":[326.6,327.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1034/*"},{"ua":"XT1034"}],"dpi":[326.6,328.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1053/*"},{"ua":"XT1053"}],"dpi":[315.3,316.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1562/*"},{"ua":"XT1562"}],"dpi":[403.4,402.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/Nexus 6/*"},{"ua":"Nexus 6 B"}],"dpi":[494.3,489.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1063/*"},{"ua":"XT1063"}],"dpi":[295,296.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1064/*"},{"ua":"XT1064"}],"dpi":[295,295.6],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1092/*"},{"ua":"XT1092"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1095/*"},{"ua":"XT1095"}],"dpi":[422,423.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/G4/*"},{"ua":"Moto G (4)"}],"dpi":401,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/A0001/*"},{"ua":"A0001"}],"dpi":[403.4,401],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1001/*"},{"ua":"ONE E1001"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1003/*"},{"ua":"ONE E1003"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1005/*"},{"ua":"ONE E1005"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2001/*"},{"ua":"ONE A2001"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2003/*"},{"ua":"ONE A2003"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2005/*"},{"ua":"ONE A2005"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A3000/*"},{"ua":"ONEPLUS A3000"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A3003/*"},{"ua":"ONEPLUS A3003"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A3010/*"},{"ua":"ONEPLUS A3010"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A5000/*"},{"ua":"ONEPLUS A5000 "}],"dpi":[403.411,399.737],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A5010/*"},{"ua":"ONEPLUS A5010"}],"dpi":[403,400],"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6000/*"},{"ua":"ONEPLUS A6000"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6003/*"},{"ua":"ONEPLUS A6003"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6010/*"},{"ua":"ONEPLUS A6010"}],"dpi":401,"bw":2,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6013/*"},{"ua":"ONEPLUS A6013"}],"dpi":401,"bw":2,"ac":500},{"type":"android","rules":[{"mdmh":"OPPO/*/X909/*"},{"ua":"X909"}],"dpi":[442.4,444.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9082/*"},{"ua":"GT-I9082"}],"dpi":[184.7,185.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G360P/*"},{"ua":"SM-G360P"}],"dpi":[196.7,205.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Nexus S/*"},{"ua":"Nexus S"}],"dpi":[234.5,229.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[304.8,303.9],"bw":5,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T230NU/*"},{"ua":"SM-T230NU"}],"dpi":216,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-T399/*"},{"ua":"SGH-T399"}],"dpi":[217.7,231.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-M919/*"},{"ua":"SGH-M919"}],"dpi":[440.8,437.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N9005/*"},{"ua":"SM-N9005"}],"dpi":[386.4,387],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SM-N900A/*"},{"ua":"SAMSUNG-SM-N900A"}],"dpi":[386.4,387.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9500/*"},{"ua":"GT-I9500"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9505/*"},{"ua":"GT-I9505"}],"dpi":439.4,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900F/*"},{"ua":"SM-G900F"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900M/*"},{"ua":"SM-G900M"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G800F/*"},{"ua":"SM-G800F"}],"dpi":326.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G906S/*"},{"ua":"SM-G906S"}],"dpi":[562.7,572.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[306.7,304.8],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T535/*"},{"ua":"SM-T535"}],"dpi":[142.6,136.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920C/*"},{"ua":"SM-N920C"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920P/*"},{"ua":"SM-N920P"}],"dpi":[386.3655,390.144],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920W8/*"},{"ua":"SM-N920W8"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300I/*"},{"ua":"GT-I9300I"}],"dpi":[304.8,305.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9195/*"},{"ua":"GT-I9195"}],"dpi":[249.4,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-L520/*"},{"ua":"SPH-L520"}],"dpi":[249.4,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SGH-I717/*"},{"ua":"SAMSUNG-SGH-I717"}],"dpi":285.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-D710/*"},{"ua":"SPH-D710"}],"dpi":[217.7,204.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-N7100/*"},{"ua":"GT-N7100"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SCH-I605/*"},{"ua":"SCH-I605"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Galaxy Nexus/*"},{"ua":"Galaxy Nexus"}],"dpi":[315.3,314.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910H/*"},{"ua":"SM-N910H"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910C/*"},{"ua":"SM-N910C"}],"dpi":[515.2,520.2],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G130M/*"},{"ua":"SM-G130M"}],"dpi":[165.9,164.8],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G928I/*"},{"ua":"SM-G928I"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920F/*"},{"ua":"SM-G920F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920P/*"},{"ua":"SM-G920P"}],"dpi":[522.5,577],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925F/*"},{"ua":"SM-G925F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925V/*"},{"ua":"SM-G925V"}],"dpi":[522.5,576.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G930F/*"},{"ua":"SM-G930F"}],"dpi":576.6,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G935F/*"},{"ua":"SM-G935F"}],"dpi":533,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G950F/*"},{"ua":"SM-G950F"}],"dpi":[562.707,565.293],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955U/*"},{"ua":"SM-G955U"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955F/*"},{"ua":"SM-G955F"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960F/*"},{"ua":"SM-G960F"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G9600/*"},{"ua":"SM-G9600"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960T/*"},{"ua":"SM-G960T"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960N/*"},{"ua":"SM-G960N"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960U/*"},{"ua":"SM-G960U"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G9608/*"},{"ua":"SM-G9608"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960FD/*"},{"ua":"SM-G960FD"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960W/*"},{"ua":"SM-G960W"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G965F/*"},{"ua":"SM-G965F"}],"dpi":529,"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/C6903/*"},{"ua":"C6903"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/D6653/*"},{"ua":"D6653"}],"dpi":[428.6,427.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6653/*"},{"ua":"E6653"}],"dpi":[428.6,425.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6853/*"},{"ua":"E6853"}],"dpi":[403.4,401.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/SGP321/*"},{"ua":"SGP321"}],"dpi":[224.7,224.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{"ua":"ALCATEL ONE TOUCH Fierce"}],"dpi":[240,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"THL/*/thl 5000/*"},{"ua":"thl 5000"}],"dpi":[480,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Fly/*/IQ4412/*"},{"ua":"IQ4412"}],"dpi":307.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"ZTE/*/ZTE Blade L2/*"},{"ua":"ZTE Blade L2"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"BENEVE/*/VR518/*"},{"ua":"VR518"}],"dpi":480,"bw":3,"ac":500},{"type":"ios","rules":[{"res":[640,960]}],"dpi":[325.1,328.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[640,1136]}],"dpi":[317.1,320.2],"bw":3,"ac":1000},{"type":"ios","rules":[{"res":[750,1334]}],"dpi":326.4,"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1242,2208]}],"dpi":[453.6,458.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2001]}],"dpi":[410.9,415.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2436]}],"dpi":458,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/EML-L29/*"},{"ua":"EML-L29"}],"dpi":428,"bw":3.45,"ac":500},{"type":"android","rules":[{"mdmh":"Nokia/*/Nokia 7.1/*"},{"ua":"Nokia 7.1"}],"dpi":[432,431.9],"bw":3,"ac":500},{"type":"ios","rules":[{"res":[1242,2688]}],"dpi":458,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G570M/*"},{"ua":"SM-G570M"}],"dpi":320,"bw":3.684,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G970F/*"},{"ua":"SM-G970F"}],"dpi":438,"bw":2.281,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G973F/*"},{"ua":"SM-G973F"}],"dpi":550,"bw":2.002,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G975F/*"},{"ua":"SM-G975F"}],"dpi":522,"bw":2.054,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G977F/*"},{"ua":"SM-G977F"}],"dpi":505,"bw":2.334,"ac":500},{"type":"ios","rules":[{"res":[828,1792]}],"dpi":326,"bw":5,"ac":500}]; -var DPDB_CACHE = { - format: format, - last_updated: last_updated, - devices: devices -}; -function Dpdb(url, onDeviceParamsUpdated) { - this.dpdb = DPDB_CACHE; - this.recalculateDeviceParams_(); - if (url) { - this.onDeviceParamsUpdated = onDeviceParamsUpdated; - var xhr = new XMLHttpRequest(); - var obj = this; - xhr.open('GET', url, true); - xhr.addEventListener('load', function () { - obj.loading = false; - if (xhr.status >= 200 && xhr.status <= 299) { - obj.dpdb = JSON.parse(xhr.response); - obj.recalculateDeviceParams_(); - } else { - console.error('Error loading online DPDB!'); - } - }); - xhr.send(); - } -} -Dpdb.prototype.getDeviceParams = function () { - return this.deviceParams; -}; -Dpdb.prototype.recalculateDeviceParams_ = function () { - var newDeviceParams = this.calcDeviceParams_(); - if (newDeviceParams) { - this.deviceParams = newDeviceParams; - if (this.onDeviceParamsUpdated) { - this.onDeviceParamsUpdated(this.deviceParams); - } - } else { - console.error('Failed to recalculate device parameters.'); - } -}; -Dpdb.prototype.calcDeviceParams_ = function () { - var db = this.dpdb; - if (!db) { - console.error('DPDB not available.'); - return null; - } - if (db.format != 1) { - console.error('DPDB has unexpected format version.'); - return null; - } - if (!db.devices || !db.devices.length) { - console.error('DPDB does not have a devices section.'); - return null; - } - var userAgent = navigator.userAgent || navigator.vendor || window.opera; - var width = getScreenWidth(); - var height = getScreenHeight(); - if (!db.devices) { - console.error('DPDB has no devices section.'); - return null; - } - for (var i = 0; i < db.devices.length; i++) { - var device = db.devices[i]; - if (!device.rules) { - console.warn('Device[' + i + '] has no rules section.'); - continue; - } - if (device.type != 'ios' && device.type != 'android') { - console.warn('Device[' + i + '] has invalid type.'); - continue; - } - if (isIOS() != (device.type == 'ios')) continue; - var matched = false; - for (var j = 0; j < device.rules.length; j++) { - var rule = device.rules[j]; - if (this.ruleMatches_(rule, userAgent, width, height)) { - matched = true; - break; - } - } - if (!matched) continue; - var xdpi = device.dpi[0] || device.dpi; - var ydpi = device.dpi[1] || device.dpi; - return new DeviceParams({ xdpi: xdpi, ydpi: ydpi, bevelMm: device.bw }); - } - console.warn('No DPDB device match.'); - return null; -}; -Dpdb.prototype.ruleMatches_ = function (rule, ua, screenWidth, screenHeight) { - if (!rule.ua && !rule.res) return false; - if (rule.ua && rule.ua.substring(0, 2) === 'SM') rule.ua = rule.ua.substring(0, 7); - if (rule.ua && ua.indexOf(rule.ua) < 0) return false; - if (rule.res) { - if (!rule.res[0] || !rule.res[1]) return false; - var resX = rule.res[0]; - var resY = rule.res[1]; - if (Math.min(screenWidth, screenHeight) != Math.min(resX, resY) || Math.max(screenWidth, screenHeight) != Math.max(resX, resY)) { - return false; - } - } - return true; -}; -function DeviceParams(params) { - this.xdpi = params.xdpi; - this.ydpi = params.ydpi; - this.bevelMm = params.bevelMm; -} -function SensorSample(sample, timestampS) { - this.set(sample, timestampS); -} -SensorSample.prototype.set = function (sample, timestampS) { - this.sample = sample; - this.timestampS = timestampS; -}; -SensorSample.prototype.copy = function (sensorSample) { - this.set(sensorSample.sample, sensorSample.timestampS); -}; -function ComplementaryFilter(kFilter, isDebug) { - this.kFilter = kFilter; - this.isDebug = isDebug; - this.currentAccelMeasurement = new SensorSample(); - this.currentGyroMeasurement = new SensorSample(); - this.previousGyroMeasurement = new SensorSample(); - if (isIOS()) { - this.filterQ = new Quaternion(-1, 0, 0, 1); - } else { - this.filterQ = new Quaternion(1, 0, 0, 1); - } - this.previousFilterQ = new Quaternion(); - this.previousFilterQ.copy(this.filterQ); - this.accelQ = new Quaternion(); - this.isOrientationInitialized = false; - this.estimatedGravity = new Vector3(); - this.measuredGravity = new Vector3(); - this.gyroIntegralQ = new Quaternion(); -} -ComplementaryFilter.prototype.addAccelMeasurement = function (vector, timestampS) { - this.currentAccelMeasurement.set(vector, timestampS); -}; -ComplementaryFilter.prototype.addGyroMeasurement = function (vector, timestampS) { - this.currentGyroMeasurement.set(vector, timestampS); - var deltaT = timestampS - this.previousGyroMeasurement.timestampS; - if (isTimestampDeltaValid(deltaT)) { - this.run_(); - } - this.previousGyroMeasurement.copy(this.currentGyroMeasurement); -}; -ComplementaryFilter.prototype.run_ = function () { - if (!this.isOrientationInitialized) { - this.accelQ = this.accelToQuaternion_(this.currentAccelMeasurement.sample); - this.previousFilterQ.copy(this.accelQ); - this.isOrientationInitialized = true; - return; - } - var deltaT = this.currentGyroMeasurement.timestampS - this.previousGyroMeasurement.timestampS; - var gyroDeltaQ = this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample, deltaT); - this.gyroIntegralQ.multiply(gyroDeltaQ); - this.filterQ.copy(this.previousFilterQ); - this.filterQ.multiply(gyroDeltaQ); - var invFilterQ = new Quaternion(); - invFilterQ.copy(this.filterQ); - invFilterQ.inverse(); - this.estimatedGravity.set(0, 0, -1); - this.estimatedGravity.applyQuaternion(invFilterQ); - this.estimatedGravity.normalize(); - this.measuredGravity.copy(this.currentAccelMeasurement.sample); - this.measuredGravity.normalize(); - var deltaQ = new Quaternion(); - deltaQ.setFromUnitVectors(this.estimatedGravity, this.measuredGravity); - deltaQ.inverse(); - if (this.isDebug) { - console.log('Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)', radToDeg * getQuaternionAngle(deltaQ), this.estimatedGravity.x.toFixed(1), this.estimatedGravity.y.toFixed(1), this.estimatedGravity.z.toFixed(1), this.measuredGravity.x.toFixed(1), this.measuredGravity.y.toFixed(1), this.measuredGravity.z.toFixed(1)); - } - var targetQ = new Quaternion(); - targetQ.copy(this.filterQ); - targetQ.multiply(deltaQ); - this.filterQ.slerp(targetQ, 1 - this.kFilter); - this.previousFilterQ.copy(this.filterQ); -}; -ComplementaryFilter.prototype.getOrientation = function () { - return this.filterQ; -}; -ComplementaryFilter.prototype.accelToQuaternion_ = function (accel) { - var normAccel = new Vector3(); - normAccel.copy(accel); - normAccel.normalize(); - var quat = new Quaternion(); - quat.setFromUnitVectors(new Vector3(0, 0, -1), normAccel); - quat.inverse(); - return quat; -}; -ComplementaryFilter.prototype.gyroToQuaternionDelta_ = function (gyro, dt) { - var quat = new Quaternion(); - var axis = new Vector3(); - axis.copy(gyro); - axis.normalize(); - quat.setFromAxisAngle(axis, gyro.length() * dt); - return quat; -}; -function PosePredictor(predictionTimeS, isDebug) { - this.predictionTimeS = predictionTimeS; - this.isDebug = isDebug; - this.previousQ = new Quaternion(); - this.previousTimestampS = null; - this.deltaQ = new Quaternion(); - this.outQ = new Quaternion(); -} -PosePredictor.prototype.getPrediction = function (currentQ, gyro, timestampS) { - if (!this.previousTimestampS) { - this.previousQ.copy(currentQ); - this.previousTimestampS = timestampS; - return currentQ; - } - var axis = new Vector3(); - axis.copy(gyro); - axis.normalize(); - var angularSpeed = gyro.length(); - if (angularSpeed < degToRad * 20) { - if (this.isDebug) { - console.log('Moving slowly, at %s deg/s: no prediction', (radToDeg * angularSpeed).toFixed(1)); - } - this.outQ.copy(currentQ); - this.previousQ.copy(currentQ); - return this.outQ; - } - var predictAngle = angularSpeed * this.predictionTimeS; - this.deltaQ.setFromAxisAngle(axis, predictAngle); - this.outQ.copy(this.previousQ); - this.outQ.multiply(this.deltaQ); - this.previousQ.copy(currentQ); - this.previousTimestampS = timestampS; - return this.outQ; -}; -function FusionPoseSensor(kFilter, predictionTime, yawOnly, isDebug) { - this.yawOnly = yawOnly; - this.accelerometer = new Vector3(); - this.gyroscope = new Vector3(); - this.filter = new ComplementaryFilter(kFilter, isDebug); - this.posePredictor = new PosePredictor(predictionTime, isDebug); - this.isFirefoxAndroid = isFirefoxAndroid(); - this.isIOS = isIOS(); - var chromeVersion = getChromeVersion(); - this.isDeviceMotionInRadians = !this.isIOS && chromeVersion && chromeVersion < 66; - this.isWithoutDeviceMotion = isChromeWithoutDeviceMotion(); - this.filterToWorldQ = new Quaternion(); - if (isIOS()) { - this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2); - } else { - this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2); - } - this.inverseWorldToScreenQ = new Quaternion(); - this.worldToScreenQ = new Quaternion(); - this.originalPoseAdjustQ = new Quaternion(); - this.originalPoseAdjustQ.setFromAxisAngle(new Vector3(0, 0, 1), -window.orientation * Math.PI / 180); - this.setScreenTransform_(); - if (isLandscapeMode()) { - this.filterToWorldQ.multiply(this.inverseWorldToScreenQ); - } - this.resetQ = new Quaternion(); - this.orientationOut_ = new Float32Array(4); - this.start(); -} -FusionPoseSensor.prototype.getPosition = function () { - return null; -}; -FusionPoseSensor.prototype.getOrientation = function () { - var orientation = void 0; - if (this.isWithoutDeviceMotion && this._deviceOrientationQ) { - this.deviceOrientationFixQ = this.deviceOrientationFixQ || function () { - var z = new Quaternion().setFromAxisAngle(new Vector3(0, 0, -1), 0); - var y = new Quaternion(); - if (window.orientation === -90) { - y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / -2); - } else { - y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 2); - } - return z.multiply(y); - }(); - this.deviceOrientationFilterToWorldQ = this.deviceOrientationFilterToWorldQ || function () { - var q = new Quaternion(); - q.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2); - return q; - }(); - orientation = this._deviceOrientationQ; - var out = new Quaternion(); - out.copy(orientation); - out.multiply(this.deviceOrientationFilterToWorldQ); - out.multiply(this.resetQ); - out.multiply(this.worldToScreenQ); - out.multiplyQuaternions(this.deviceOrientationFixQ, out); - if (this.yawOnly) { - out.x = 0; - out.z = 0; - out.normalize(); - } - this.orientationOut_[0] = out.x; - this.orientationOut_[1] = out.y; - this.orientationOut_[2] = out.z; - this.orientationOut_[3] = out.w; - return this.orientationOut_; - } else { - var filterOrientation = this.filter.getOrientation(); - orientation = this.posePredictor.getPrediction(filterOrientation, this.gyroscope, this.previousTimestampS); - } - var out = new Quaternion(); - out.copy(this.filterToWorldQ); - out.multiply(this.resetQ); - out.multiply(orientation); - out.multiply(this.worldToScreenQ); - if (this.yawOnly) { - out.x = 0; - out.z = 0; - out.normalize(); - } - this.orientationOut_[0] = out.x; - this.orientationOut_[1] = out.y; - this.orientationOut_[2] = out.z; - this.orientationOut_[3] = out.w; - return this.orientationOut_; -}; -FusionPoseSensor.prototype.resetPose = function () { - this.resetQ.copy(this.filter.getOrientation()); - this.resetQ.x = 0; - this.resetQ.y = 0; - this.resetQ.z *= -1; - this.resetQ.normalize(); - if (isLandscapeMode()) { - this.resetQ.multiply(this.inverseWorldToScreenQ); - } - this.resetQ.multiply(this.originalPoseAdjustQ); -}; -FusionPoseSensor.prototype.onDeviceOrientation_ = function (e) { - this._deviceOrientationQ = this._deviceOrientationQ || new Quaternion(); - var alpha = e.alpha, - beta = e.beta, - gamma = e.gamma; - alpha = (alpha || 0) * Math.PI / 180; - beta = (beta || 0) * Math.PI / 180; - gamma = (gamma || 0) * Math.PI / 180; - this._deviceOrientationQ.setFromEulerYXZ(beta, alpha, -gamma); -}; -FusionPoseSensor.prototype.onDeviceMotion_ = function (deviceMotion) { - this.updateDeviceMotion_(deviceMotion); -}; -FusionPoseSensor.prototype.updateDeviceMotion_ = function (deviceMotion) { - var accGravity = deviceMotion.accelerationIncludingGravity; - var rotRate = deviceMotion.rotationRate; - var timestampS = deviceMotion.timeStamp / 1000; - var deltaS = timestampS - this.previousTimestampS; - if (deltaS < 0) { - warnOnce('fusion-pose-sensor:invalid:non-monotonic', 'Invalid timestamps detected: non-monotonic timestamp from devicemotion'); - this.previousTimestampS = timestampS; - return; - } else if (deltaS <= MIN_TIMESTEP || deltaS > MAX_TIMESTEP) { - warnOnce('fusion-pose-sensor:invalid:outside-threshold', 'Invalid timestamps detected: Timestamp from devicemotion outside expected range.'); - this.previousTimestampS = timestampS; - return; - } - this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z); - if (isR7()) { - this.gyroscope.set(-rotRate.beta, rotRate.alpha, rotRate.gamma); - } else { - this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma); - } - if (!this.isDeviceMotionInRadians) { - this.gyroscope.multiplyScalar(Math.PI / 180); - } - this.filter.addAccelMeasurement(this.accelerometer, timestampS); - this.filter.addGyroMeasurement(this.gyroscope, timestampS); - this.previousTimestampS = timestampS; -}; -FusionPoseSensor.prototype.onOrientationChange_ = function (screenOrientation) { - this.setScreenTransform_(); -}; -FusionPoseSensor.prototype.onMessage_ = function (event) { - var message = event.data; - if (!message || !message.type) { - return; - } - var type = message.type.toLowerCase(); - if (type !== 'devicemotion') { - return; - } - this.updateDeviceMotion_(message.deviceMotionEvent); -}; -FusionPoseSensor.prototype.setScreenTransform_ = function () { - this.worldToScreenQ.set(0, 0, 0, 1); - switch (window.orientation) { - case 0: - break; - case 90: - this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), -Math.PI / 2); - break; - case -90: - this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), Math.PI / 2); - break; - case 180: - break; - } - this.inverseWorldToScreenQ.copy(this.worldToScreenQ); - this.inverseWorldToScreenQ.inverse(); -}; -FusionPoseSensor.prototype.start = function () { - this.onDeviceMotionCallback_ = this.onDeviceMotion_.bind(this); - this.onOrientationChangeCallback_ = this.onOrientationChange_.bind(this); - this.onMessageCallback_ = this.onMessage_.bind(this); - this.onDeviceOrientationCallback_ = this.onDeviceOrientation_.bind(this); - if (isIOS() && isInsideCrossOriginIFrame()) { - window.addEventListener('message', this.onMessageCallback_); - } - window.addEventListener('orientationchange', this.onOrientationChangeCallback_); - if (this.isWithoutDeviceMotion) { - window.addEventListener('deviceorientation', this.onDeviceOrientationCallback_); - } else { - window.addEventListener('devicemotion', this.onDeviceMotionCallback_); - } -}; -FusionPoseSensor.prototype.stop = function () { - window.removeEventListener('devicemotion', this.onDeviceMotionCallback_); - window.removeEventListener('deviceorientation', this.onDeviceOrientationCallback_); - window.removeEventListener('orientationchange', this.onOrientationChangeCallback_); - window.removeEventListener('message', this.onMessageCallback_); -}; -var SENSOR_FREQUENCY = 60; -var X_AXIS = new Vector3(1, 0, 0); -var Z_AXIS = new Vector3(0, 0, 1); -var SENSOR_TO_VR = new Quaternion(); -SENSOR_TO_VR.setFromAxisAngle(X_AXIS, -Math.PI / 2); -SENSOR_TO_VR.multiply(new Quaternion().setFromAxisAngle(Z_AXIS, Math.PI / 2)); -var PoseSensor = function () { - function PoseSensor(config) { - classCallCheck(this, PoseSensor); - this.config = config; - this.sensor = null; - this.fusionSensor = null; - this._out = new Float32Array(4); - this.api = null; - this.errors = []; - this._sensorQ = new Quaternion(); - this._outQ = new Quaternion(); - this._onSensorRead = this._onSensorRead.bind(this); - this._onSensorError = this._onSensorError.bind(this); - this.init(); - } - createClass(PoseSensor, [{ - key: 'init', - value: function init() { - var sensor = null; - try { - sensor = new RelativeOrientationSensor({ - frequency: SENSOR_FREQUENCY, - referenceFrame: 'screen' - }); - sensor.addEventListener('error', this._onSensorError); - } catch (error) { - this.errors.push(error); - if (error.name === 'SecurityError') { - console.error('Cannot construct sensors due to the Feature Policy'); - console.warn('Attempting to fall back using "devicemotion"; however this will ' + 'fail in the future without correct permissions.'); - this.useDeviceMotion(); - } else if (error.name === 'ReferenceError') { - this.useDeviceMotion(); - } else { - console.error(error); - } - } - if (sensor) { - this.api = 'sensor'; - this.sensor = sensor; - this.sensor.addEventListener('reading', this._onSensorRead); - this.sensor.start(); - } - } - }, { - key: 'useDeviceMotion', - value: function useDeviceMotion() { - this.api = 'devicemotion'; - this.fusionSensor = new FusionPoseSensor(this.config.K_FILTER, this.config.PREDICTION_TIME_S, this.config.YAW_ONLY, this.config.DEBUG); - if (this.sensor) { - this.sensor.removeEventListener('reading', this._onSensorRead); - this.sensor.removeEventListener('error', this._onSensorError); - this.sensor = null; - } - } - }, { - key: 'getOrientation', - value: function getOrientation() { - if (this.fusionSensor) { - return this.fusionSensor.getOrientation(); - } - if (!this.sensor || !this.sensor.quaternion) { - this._out[0] = this._out[1] = this._out[2] = 0; - this._out[3] = 1; - return this._out; - } - var q = this.sensor.quaternion; - this._sensorQ.set(q[0], q[1], q[2], q[3]); - var out = this._outQ; - out.copy(SENSOR_TO_VR); - out.multiply(this._sensorQ); - if (this.config.YAW_ONLY) { - out.x = out.z = 0; - out.normalize(); - } - this._out[0] = out.x; - this._out[1] = out.y; - this._out[2] = out.z; - this._out[3] = out.w; - return this._out; - } - }, { - key: '_onSensorError', - value: function _onSensorError(event) { - this.errors.push(event.error); - if (event.error.name === 'NotAllowedError') { - console.error('Permission to access sensor was denied'); - } else if (event.error.name === 'NotReadableError') { - console.error('Sensor could not be read'); - } else { - console.error(event.error); - } - this.useDeviceMotion(); - } - }, { - key: '_onSensorRead', - value: function _onSensorRead() {} - }]); - return PoseSensor; -}(); -var rotateInstructionsAsset = ""; -function RotateInstructions() { - this.loadIcon_(); - var overlay = document.createElement('div'); - var s = overlay.style; - s.position = 'fixed'; - s.top = 0; - s.right = 0; - s.bottom = 0; - s.left = 0; - s.backgroundColor = 'gray'; - s.fontFamily = 'sans-serif'; - s.zIndex = 1000000; - var img = document.createElement('img'); - img.src = this.icon; - var s = img.style; - s.marginLeft = '25%'; - s.marginTop = '25%'; - s.width = '50%'; - overlay.appendChild(img); - var text = document.createElement('div'); - var s = text.style; - s.textAlign = 'center'; - s.fontSize = '16px'; - s.lineHeight = '24px'; - s.margin = '24px 25%'; - s.width = '50%'; - text.innerHTML = 'Place your phone into your Cardboard viewer.'; - overlay.appendChild(text); - var snackbar = document.createElement('div'); - var s = snackbar.style; - s.backgroundColor = '#CFD8DC'; - s.position = 'fixed'; - s.bottom = 0; - s.width = '100%'; - s.height = '48px'; - s.padding = '14px 24px'; - s.boxSizing = 'border-box'; - s.color = '#656A6B'; - overlay.appendChild(snackbar); - var snackbarText = document.createElement('div'); - snackbarText.style.float = 'left'; - snackbarText.innerHTML = 'No Cardboard viewer?'; - var snackbarButton = document.createElement('a'); - snackbarButton.href = 'https://www.google.com/get/cardboard/get-cardboard/'; - snackbarButton.innerHTML = 'get one'; - snackbarButton.target = '_blank'; - var s = snackbarButton.style; - s.float = 'right'; - s.fontWeight = 600; - s.textTransform = 'uppercase'; - s.borderLeft = '1px solid gray'; - s.paddingLeft = '24px'; - s.textDecoration = 'none'; - s.color = '#656A6B'; - snackbar.appendChild(snackbarText); - snackbar.appendChild(snackbarButton); - this.overlay = overlay; - this.text = text; - this.hide(); -} -RotateInstructions.prototype.show = function (parent) { - if (!parent && !this.overlay.parentElement) { - document.body.appendChild(this.overlay); - } else if (parent) { - if (this.overlay.parentElement && this.overlay.parentElement != parent) this.overlay.parentElement.removeChild(this.overlay); - parent.appendChild(this.overlay); - } - this.overlay.style.display = 'block'; - var img = this.overlay.querySelector('img'); - var s = img.style; - if (isLandscapeMode()) { - s.width = '20%'; - s.marginLeft = '40%'; - s.marginTop = '3%'; - } else { - s.width = '50%'; - s.marginLeft = '25%'; - s.marginTop = '25%'; - } -}; -RotateInstructions.prototype.hide = function () { - this.overlay.style.display = 'none'; -}; -RotateInstructions.prototype.showTemporarily = function (ms, parent) { - this.show(parent); - this.timer = setTimeout(this.hide.bind(this), ms); -}; -RotateInstructions.prototype.disableShowTemporarily = function () { - clearTimeout(this.timer); -}; -RotateInstructions.prototype.update = function () { - this.disableShowTemporarily(); - if (!isLandscapeMode() && isMobile()) { - this.show(); - } else { - this.hide(); - } -}; -RotateInstructions.prototype.loadIcon_ = function () { - this.icon = dataUri('image/svg+xml', rotateInstructionsAsset); -}; -var DEFAULT_VIEWER = 'CardboardV1'; -var VIEWER_KEY = 'WEBVR_CARDBOARD_VIEWER'; -var CLASS_NAME = 'webvr-polyfill-viewer-selector'; -function ViewerSelector(defaultViewer) { - try { - this.selectedKey = localStorage.getItem(VIEWER_KEY); - } catch (error) { - console.error('Failed to load viewer profile: %s', error); - } - if (!this.selectedKey) { - this.selectedKey = defaultViewer || DEFAULT_VIEWER; - } - this.dialog = this.createDialog_(DeviceInfo.Viewers); - this.root = null; - this.onChangeCallbacks_ = []; -} -ViewerSelector.prototype.show = function (root) { - this.root = root; - root.appendChild(this.dialog); - var selected = this.dialog.querySelector('#' + this.selectedKey); - selected.checked = true; - this.dialog.style.display = 'block'; -}; -ViewerSelector.prototype.hide = function () { - if (this.root && this.root.contains(this.dialog)) { - this.root.removeChild(this.dialog); - } - this.dialog.style.display = 'none'; -}; -ViewerSelector.prototype.getCurrentViewer = function () { - return DeviceInfo.Viewers[this.selectedKey]; -}; -ViewerSelector.prototype.getSelectedKey_ = function () { - var input = this.dialog.querySelector('input[name=field]:checked'); - if (input) { - return input.id; - } - return null; -}; -ViewerSelector.prototype.onChange = function (cb) { - this.onChangeCallbacks_.push(cb); -}; -ViewerSelector.prototype.fireOnChange_ = function (viewer) { - for (var i = 0; i < this.onChangeCallbacks_.length; i++) { - this.onChangeCallbacks_[i](viewer); - } -}; -ViewerSelector.prototype.onSave_ = function () { - this.selectedKey = this.getSelectedKey_(); - if (!this.selectedKey || !DeviceInfo.Viewers[this.selectedKey]) { - console.error('ViewerSelector.onSave_: this should never happen!'); - return; - } - this.fireOnChange_(DeviceInfo.Viewers[this.selectedKey]); - try { - localStorage.setItem(VIEWER_KEY, this.selectedKey); - } catch (error) { - console.error('Failed to save viewer profile: %s', error); - } - this.hide(); -}; -ViewerSelector.prototype.createDialog_ = function (options) { - var container = document.createElement('div'); - container.classList.add(CLASS_NAME); - container.style.display = 'none'; - var overlay = document.createElement('div'); - var s = overlay.style; - s.position = 'fixed'; - s.left = 0; - s.top = 0; - s.width = '100%'; - s.height = '100%'; - s.background = 'rgba(0, 0, 0, 0.3)'; - overlay.addEventListener('click', this.hide.bind(this)); - var width = 280; - var dialog = document.createElement('div'); - var s = dialog.style; - s.boxSizing = 'border-box'; - s.position = 'fixed'; - s.top = '24px'; - s.left = '50%'; - s.marginLeft = -width / 2 + 'px'; - s.width = width + 'px'; - s.padding = '24px'; - s.overflow = 'hidden'; - s.background = '#fafafa'; - s.fontFamily = "'Roboto', sans-serif"; - s.boxShadow = '0px 5px 20px #666'; - dialog.appendChild(this.createH1_('Select your viewer')); - for (var id in options) { - dialog.appendChild(this.createChoice_(id, options[id].label)); - } - dialog.appendChild(this.createButton_('Save', this.onSave_.bind(this))); - container.appendChild(overlay); - container.appendChild(dialog); - return container; -}; -ViewerSelector.prototype.createH1_ = function (name) { - var h1 = document.createElement('h1'); - var s = h1.style; - s.color = 'black'; - s.fontSize = '20px'; - s.fontWeight = 'bold'; - s.marginTop = 0; - s.marginBottom = '24px'; - h1.innerHTML = name; - return h1; -}; -ViewerSelector.prototype.createChoice_ = function (id, name) { - var div = document.createElement('div'); - div.style.marginTop = '8px'; - div.style.color = 'black'; - var input = document.createElement('input'); - input.style.fontSize = '30px'; - input.setAttribute('id', id); - input.setAttribute('type', 'radio'); - input.setAttribute('value', id); - input.setAttribute('name', 'field'); - var label = document.createElement('label'); - label.style.marginLeft = '4px'; - label.setAttribute('for', id); - label.innerHTML = name; - div.appendChild(input); - div.appendChild(label); - return div; -}; -ViewerSelector.prototype.createButton_ = function (label, onclick) { - var button = document.createElement('button'); - button.innerHTML = label; - var s = button.style; - s.float = 'right'; - s.textTransform = 'uppercase'; - s.color = '#1094f7'; - s.fontSize = '14px'; - s.letterSpacing = 0; - s.border = 0; - s.background = 'none'; - s.marginTop = '16px'; - button.addEventListener('click', onclick); - return button; -}; -var commonjsGlobal$$1 = typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {}; -function unwrapExports$$1 (x) { - return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; -} -function createCommonjsModule$$1(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; -} -var NoSleep = createCommonjsModule$$1(function (module, exports) { -(function webpackUniversalModuleDefinition(root, factory) { - module.exports = factory(); -})(commonjsGlobal$$1, function() { -return (function(modules) { - var installedModules = {}; - function __webpack_require__(moduleId) { - if(installedModules[moduleId]) { - return installedModules[moduleId].exports; - } - var module = installedModules[moduleId] = { - i: moduleId, - l: false, - exports: {} - }; - modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - module.l = true; - return module.exports; - } - __webpack_require__.m = modules; - __webpack_require__.c = installedModules; - __webpack_require__.d = function(exports, name, getter) { - if(!__webpack_require__.o(exports, name)) { - Object.defineProperty(exports, name, { - configurable: false, - enumerable: true, - get: getter - }); - } - }; - __webpack_require__.n = function(module) { - var getter = module && module.__esModule ? - function getDefault() { return module['default']; } : - function getModuleExports() { return module; }; - __webpack_require__.d(getter, 'a', getter); - return getter; - }; - __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; - __webpack_require__.p = ""; - return __webpack_require__(__webpack_require__.s = 0); - }) - ([ - (function(module, exports, __webpack_require__) { -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -var mediaFile = __webpack_require__(1); -var oldIOS = typeof navigator !== 'undefined' && parseFloat(('' + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ''])[1]).replace('undefined', '3_2').replace('_', '.').replace('_', '')) < 10 && !window.MSStream; -var NoSleep = function () { - function NoSleep() { - _classCallCheck(this, NoSleep); - if (oldIOS) { - this.noSleepTimer = null; - } else { - this.noSleepVideo = document.createElement('video'); - this.noSleepVideo.setAttribute('playsinline', ''); - this.noSleepVideo.setAttribute('src', mediaFile); - this.noSleepVideo.addEventListener('timeupdate', function (e) { - if (this.noSleepVideo.currentTime > 0.5) { - this.noSleepVideo.currentTime = Math.random(); - } - }.bind(this)); - } - } - _createClass(NoSleep, [{ - key: 'enable', - value: function enable() { - if (oldIOS) { - this.disable(); - this.noSleepTimer = window.setInterval(function () { - window.location.href = '/'; - window.setTimeout(window.stop, 0); - }, 15000); - } else { - this.noSleepVideo.play(); - } - } - }, { - key: 'disable', - value: function disable() { - if (oldIOS) { - if (this.noSleepTimer) { - window.clearInterval(this.noSleepTimer); - this.noSleepTimer = null; - } - } else { - this.noSleepVideo.pause(); - } - } - }]); - return NoSleep; -}(); -module.exports = NoSleep; - }), - (function(module, exports, __webpack_require__) { -module.exports = 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA='; - }) - ]); -}); -}); -var NoSleep$1 = unwrapExports$$1(NoSleep); -var nextDisplayId = 1000; -var defaultLeftBounds = [0, 0, 0.5, 1]; -var defaultRightBounds = [0.5, 0, 0.5, 1]; -var raf = window.requestAnimationFrame; -var caf = window.cancelAnimationFrame; -function VRFrameData() { - this.leftProjectionMatrix = new Float32Array(16); - this.leftViewMatrix = new Float32Array(16); - this.rightProjectionMatrix = new Float32Array(16); - this.rightViewMatrix = new Float32Array(16); - this.pose = null; -} -function VRDisplayCapabilities(config) { - Object.defineProperties(this, { - hasPosition: { - writable: false, enumerable: true, value: config.hasPosition - }, - hasExternalDisplay: { - writable: false, enumerable: true, value: config.hasExternalDisplay - }, - canPresent: { - writable: false, enumerable: true, value: config.canPresent - }, - maxLayers: { - writable: false, enumerable: true, value: config.maxLayers - }, - hasOrientation: { - enumerable: true, get: function get() { - deprecateWarning('VRDisplayCapabilities.prototype.hasOrientation', 'VRDisplay.prototype.getFrameData'); - return config.hasOrientation; - } - } - }); -} -function VRDisplay(config) { - config = config || {}; - var USE_WAKELOCK = 'wakelock' in config ? config.wakelock : true; - this.isPolyfilled = true; - this.displayId = nextDisplayId++; - this.displayName = ''; - this.depthNear = 0.01; - this.depthFar = 10000.0; - this.isPresenting = false; - Object.defineProperty(this, 'isConnected', { - get: function get() { - deprecateWarning('VRDisplay.prototype.isConnected', 'VRDisplayCapabilities.prototype.hasExternalDisplay'); - return false; - } - }); - this.capabilities = new VRDisplayCapabilities({ - hasPosition: false, - hasOrientation: false, - hasExternalDisplay: false, - canPresent: false, - maxLayers: 1 - }); - this.stageParameters = null; - this.waitingForPresent_ = false; - this.layer_ = null; - this.originalParent_ = null; - this.fullscreenElement_ = null; - this.fullscreenWrapper_ = null; - this.fullscreenElementCachedStyle_ = null; - this.fullscreenEventTarget_ = null; - this.fullscreenChangeHandler_ = null; - this.fullscreenErrorHandler_ = null; - if (USE_WAKELOCK && isMobile()) { - this.wakelock_ = new NoSleep$1(); - } -} -VRDisplay.prototype.getFrameData = function (frameData) { - return frameDataFromPose(frameData, this._getPose(), this); -}; -VRDisplay.prototype.getPose = function () { - deprecateWarning('VRDisplay.prototype.getPose', 'VRDisplay.prototype.getFrameData'); - return this._getPose(); -}; -VRDisplay.prototype.resetPose = function () { - deprecateWarning('VRDisplay.prototype.resetPose'); - return this._resetPose(); -}; -VRDisplay.prototype.getImmediatePose = function () { - deprecateWarning('VRDisplay.prototype.getImmediatePose', 'VRDisplay.prototype.getFrameData'); - return this._getPose(); -}; -VRDisplay.prototype.requestAnimationFrame = function (callback) { - return raf(callback); -}; -VRDisplay.prototype.cancelAnimationFrame = function (id) { - return caf(id); -}; -VRDisplay.prototype.wrapForFullscreen = function (element) { - if (isIOS()) { - return element; - } - if (!this.fullscreenWrapper_) { - this.fullscreenWrapper_ = document.createElement('div'); - var cssProperties = ['height: ' + Math.min(screen.height, screen.width) + 'px !important', 'top: 0 !important', 'left: 0 !important', 'right: 0 !important', 'border: 0', 'margin: 0', 'padding: 0', 'z-index: 999999 !important', 'position: fixed']; - this.fullscreenWrapper_.setAttribute('style', cssProperties.join('; ') + ';'); - this.fullscreenWrapper_.classList.add('webvr-polyfill-fullscreen-wrapper'); - } - if (this.fullscreenElement_ == element) { - return this.fullscreenWrapper_; - } - if (this.fullscreenElement_) { - if (this.originalParent_) { - this.originalParent_.appendChild(this.fullscreenElement_); - } else { - this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_); - } - } - this.fullscreenElement_ = element; - this.originalParent_ = element.parentElement; - if (!this.originalParent_) { - document.body.appendChild(element); - } - if (!this.fullscreenWrapper_.parentElement) { - var parent = this.fullscreenElement_.parentElement; - parent.insertBefore(this.fullscreenWrapper_, this.fullscreenElement_); - parent.removeChild(this.fullscreenElement_); - } - this.fullscreenWrapper_.insertBefore(this.fullscreenElement_, this.fullscreenWrapper_.firstChild); - this.fullscreenElementCachedStyle_ = this.fullscreenElement_.getAttribute('style'); - var self = this; - function applyFullscreenElementStyle() { - if (!self.fullscreenElement_) { - return; - } - var cssProperties = ['position: absolute', 'top: 0', 'left: 0', 'width: ' + Math.max(screen.width, screen.height) + 'px', 'height: ' + Math.min(screen.height, screen.width) + 'px', 'border: 0', 'margin: 0', 'padding: 0']; - self.fullscreenElement_.setAttribute('style', cssProperties.join('; ') + ';'); - } - applyFullscreenElementStyle(); - return this.fullscreenWrapper_; -}; -VRDisplay.prototype.removeFullscreenWrapper = function () { - if (!this.fullscreenElement_) { - return; - } - var element = this.fullscreenElement_; - if (this.fullscreenElementCachedStyle_) { - element.setAttribute('style', this.fullscreenElementCachedStyle_); - } else { - element.removeAttribute('style'); - } - this.fullscreenElement_ = null; - this.fullscreenElementCachedStyle_ = null; - var parent = this.fullscreenWrapper_.parentElement; - this.fullscreenWrapper_.removeChild(element); - if (this.originalParent_ === parent) { - parent.insertBefore(element, this.fullscreenWrapper_); - } - else if (this.originalParent_) { - this.originalParent_.appendChild(element); - } - parent.removeChild(this.fullscreenWrapper_); - return element; -}; -VRDisplay.prototype.requestPresent = function (layers) { - var wasPresenting = this.isPresenting; - var self = this; - if (!(layers instanceof Array)) { - deprecateWarning('VRDisplay.prototype.requestPresent with non-array argument', 'an array of VRLayers as the first argument'); - layers = [layers]; - } - return new Promise(function (resolve, reject) { - if (!self.capabilities.canPresent) { - reject(new Error('VRDisplay is not capable of presenting.')); - return; - } - if (layers.length == 0 || layers.length > self.capabilities.maxLayers) { - reject(new Error('Invalid number of layers.')); - return; - } - var incomingLayer = layers[0]; - if (!incomingLayer.source) { - resolve(); - return; - } - var leftBounds = incomingLayer.leftBounds || defaultLeftBounds; - var rightBounds = incomingLayer.rightBounds || defaultRightBounds; - if (wasPresenting) { - var layer = self.layer_; - if (layer.source !== incomingLayer.source) { - layer.source = incomingLayer.source; - } - for (var i = 0; i < 4; i++) { - layer.leftBounds[i] = leftBounds[i]; - layer.rightBounds[i] = rightBounds[i]; - } - self.wrapForFullscreen(self.layer_.source); - self.updatePresent_(); - resolve(); - return; - } - self.layer_ = { - predistorted: incomingLayer.predistorted, - source: incomingLayer.source, - leftBounds: leftBounds.slice(0), - rightBounds: rightBounds.slice(0) - }; - self.waitingForPresent_ = false; - if (self.layer_ && self.layer_.source) { - var fullscreenElement = self.wrapForFullscreen(self.layer_.source); - var onFullscreenChange = function onFullscreenChange() { - var actualFullscreenElement = getFullscreenElement(); - self.isPresenting = fullscreenElement === actualFullscreenElement; - if (self.isPresenting) { - if (screen.orientation && screen.orientation.lock) { - screen.orientation.lock('landscape-primary').catch(function (error) { - console.error('screen.orientation.lock() failed due to', error.message); - }); - } - self.waitingForPresent_ = false; - self.beginPresent_(); - resolve(); - } else { - if (screen.orientation && screen.orientation.unlock) { - screen.orientation.unlock(); - } - self.removeFullscreenWrapper(); - self.disableWakeLock(); - self.endPresent_(); - self.removeFullscreenListeners_(); - } - self.fireVRDisplayPresentChange_(); - }; - var onFullscreenError = function onFullscreenError() { - if (!self.waitingForPresent_) { - return; - } - self.removeFullscreenWrapper(); - self.removeFullscreenListeners_(); - self.disableWakeLock(); - self.waitingForPresent_ = false; - self.isPresenting = false; - reject(new Error('Unable to present.')); - }; - self.addFullscreenListeners_(fullscreenElement, onFullscreenChange, onFullscreenError); - if (requestFullscreen(fullscreenElement)) { - self.enableWakeLock(); - self.waitingForPresent_ = true; - } else if (isIOS() || isWebViewAndroid()) { - self.enableWakeLock(); - self.isPresenting = true; - self.beginPresent_(); - self.fireVRDisplayPresentChange_(); - resolve(); - } - } - if (!self.waitingForPresent_ && !isIOS()) { - exitFullscreen(); - reject(new Error('Unable to present.')); - } - }); -}; -VRDisplay.prototype.exitPresent = function () { - var wasPresenting = this.isPresenting; - var self = this; - this.isPresenting = false; - this.layer_ = null; - this.disableWakeLock(); - return new Promise(function (resolve, reject) { - if (wasPresenting) { - if (!exitFullscreen() && isIOS()) { - self.endPresent_(); - self.fireVRDisplayPresentChange_(); - } - if (isWebViewAndroid()) { - self.removeFullscreenWrapper(); - self.removeFullscreenListeners_(); - self.endPresent_(); - self.fireVRDisplayPresentChange_(); - } - resolve(); - } else { - reject(new Error('Was not presenting to VRDisplay.')); - } - }); -}; -VRDisplay.prototype.getLayers = function () { - if (this.layer_) { - return [this.layer_]; - } - return []; -}; -VRDisplay.prototype.fireVRDisplayPresentChange_ = function () { - var event = new CustomEvent('vrdisplaypresentchange', { detail: { display: this } }); - window.dispatchEvent(event); -}; -VRDisplay.prototype.fireVRDisplayConnect_ = function () { - var event = new CustomEvent('vrdisplayconnect', { detail: { display: this } }); - window.dispatchEvent(event); -}; -VRDisplay.prototype.addFullscreenListeners_ = function (element, changeHandler, errorHandler) { - this.removeFullscreenListeners_(); - this.fullscreenEventTarget_ = element; - this.fullscreenChangeHandler_ = changeHandler; - this.fullscreenErrorHandler_ = errorHandler; - if (changeHandler) { - if (document.fullscreenEnabled) { - element.addEventListener('fullscreenchange', changeHandler, false); - } else if (document.webkitFullscreenEnabled) { - element.addEventListener('webkitfullscreenchange', changeHandler, false); - } else if (document.mozFullScreenEnabled) { - document.addEventListener('mozfullscreenchange', changeHandler, false); - } else if (document.msFullscreenEnabled) { - element.addEventListener('msfullscreenchange', changeHandler, false); - } - } - if (errorHandler) { - if (document.fullscreenEnabled) { - element.addEventListener('fullscreenerror', errorHandler, false); - } else if (document.webkitFullscreenEnabled) { - element.addEventListener('webkitfullscreenerror', errorHandler, false); - } else if (document.mozFullScreenEnabled) { - document.addEventListener('mozfullscreenerror', errorHandler, false); - } else if (document.msFullscreenEnabled) { - element.addEventListener('msfullscreenerror', errorHandler, false); - } - } -}; -VRDisplay.prototype.removeFullscreenListeners_ = function () { - if (!this.fullscreenEventTarget_) return; - var element = this.fullscreenEventTarget_; - if (this.fullscreenChangeHandler_) { - var changeHandler = this.fullscreenChangeHandler_; - element.removeEventListener('fullscreenchange', changeHandler, false); - element.removeEventListener('webkitfullscreenchange', changeHandler, false); - document.removeEventListener('mozfullscreenchange', changeHandler, false); - element.removeEventListener('msfullscreenchange', changeHandler, false); - } - if (this.fullscreenErrorHandler_) { - var errorHandler = this.fullscreenErrorHandler_; - element.removeEventListener('fullscreenerror', errorHandler, false); - element.removeEventListener('webkitfullscreenerror', errorHandler, false); - document.removeEventListener('mozfullscreenerror', errorHandler, false); - element.removeEventListener('msfullscreenerror', errorHandler, false); - } - this.fullscreenEventTarget_ = null; - this.fullscreenChangeHandler_ = null; - this.fullscreenErrorHandler_ = null; -}; -VRDisplay.prototype.enableWakeLock = function () { - if (this.wakelock_) { - this.wakelock_.enable(); - } -}; -VRDisplay.prototype.disableWakeLock = function () { - if (this.wakelock_) { - this.wakelock_.disable(); - } -}; -VRDisplay.prototype.beginPresent_ = function () { -}; -VRDisplay.prototype.endPresent_ = function () { -}; -VRDisplay.prototype.submitFrame = function (pose) { -}; -VRDisplay.prototype.getEyeParameters = function (whichEye) { - return null; -}; -var config = { - ADDITIONAL_VIEWERS: [], - DEFAULT_VIEWER: '', - MOBILE_WAKE_LOCK: true, - DEBUG: false, - DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json', - K_FILTER: 0.98, - PREDICTION_TIME_S: 0.040, - CARDBOARD_UI_DISABLED: false, - ROTATE_INSTRUCTIONS_DISABLED: false, - YAW_ONLY: false, - BUFFER_SCALE: 0.5, - DIRTY_SUBMIT_FRAME_BINDINGS: false -}; -var Eye = { - LEFT: 'left', - RIGHT: 'right' -}; -function CardboardVRDisplay(config$$1) { - var defaults = extend({}, config); - config$$1 = extend(defaults, config$$1 || {}); - VRDisplay.call(this, { - wakelock: config$$1.MOBILE_WAKE_LOCK - }); - this.config = config$$1; - this.displayName = 'Cardboard VRDisplay'; - this.capabilities = new VRDisplayCapabilities({ - hasPosition: false, - hasOrientation: true, - hasExternalDisplay: false, - canPresent: true, - maxLayers: 1 - }); - this.stageParameters = null; - this.bufferScale_ = this.config.BUFFER_SCALE; - this.poseSensor_ = new PoseSensor(this.config); - this.distorter_ = null; - this.cardboardUI_ = null; - this.dpdb_ = new Dpdb(this.config.DPDB_URL, this.onDeviceParamsUpdated_.bind(this)); - this.deviceInfo_ = new DeviceInfo(this.dpdb_.getDeviceParams(), config$$1.ADDITIONAL_VIEWERS); - this.viewerSelector_ = new ViewerSelector(config$$1.DEFAULT_VIEWER); - this.viewerSelector_.onChange(this.onViewerChanged_.bind(this)); - this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer()); - if (!this.config.ROTATE_INSTRUCTIONS_DISABLED) { - this.rotateInstructions_ = new RotateInstructions(); - } - if (isIOS()) { - window.addEventListener('resize', this.onResize_.bind(this)); - } -} -CardboardVRDisplay.prototype = Object.create(VRDisplay.prototype); -CardboardVRDisplay.prototype._getPose = function () { - return { - position: null, - orientation: this.poseSensor_.getOrientation(), - linearVelocity: null, - linearAcceleration: null, - angularVelocity: null, - angularAcceleration: null - }; -}; -CardboardVRDisplay.prototype._resetPose = function () { - if (this.poseSensor_.resetPose) { - this.poseSensor_.resetPose(); - } -}; -CardboardVRDisplay.prototype._getFieldOfView = function (whichEye) { - var fieldOfView; - if (whichEye == Eye.LEFT) { - fieldOfView = this.deviceInfo_.getFieldOfViewLeftEye(); - } else if (whichEye == Eye.RIGHT) { - fieldOfView = this.deviceInfo_.getFieldOfViewRightEye(); - } else { - console.error('Invalid eye provided: %s', whichEye); - return null; - } - return fieldOfView; -}; -CardboardVRDisplay.prototype._getEyeOffset = function (whichEye) { - var offset; - if (whichEye == Eye.LEFT) { - offset = [-this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0]; - } else if (whichEye == Eye.RIGHT) { - offset = [this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0]; - } else { - console.error('Invalid eye provided: %s', whichEye); - return null; - } - return offset; -}; -CardboardVRDisplay.prototype.getEyeParameters = function (whichEye) { - var offset = this._getEyeOffset(whichEye); - var fieldOfView = this._getFieldOfView(whichEye); - var eyeParams = { - offset: offset, - renderWidth: this.deviceInfo_.device.width * 0.5 * this.bufferScale_, - renderHeight: this.deviceInfo_.device.height * this.bufferScale_ - }; - Object.defineProperty(eyeParams, 'fieldOfView', { - enumerable: true, - get: function get() { - deprecateWarning('VRFieldOfView', 'VRFrameData\'s projection matrices'); - return fieldOfView; - } - }); - return eyeParams; -}; -CardboardVRDisplay.prototype.onDeviceParamsUpdated_ = function (newParams) { - if (this.config.DEBUG) { - console.log('DPDB reported that device params were updated.'); - } - this.deviceInfo_.updateDeviceParams(newParams); - if (this.distorter_) { - this.distorter_.updateDeviceInfo(this.deviceInfo_); - } -}; -CardboardVRDisplay.prototype.updateBounds_ = function () { - if (this.layer_ && this.distorter_ && (this.layer_.leftBounds || this.layer_.rightBounds)) { - this.distorter_.setTextureBounds(this.layer_.leftBounds, this.layer_.rightBounds); - } -}; -CardboardVRDisplay.prototype.beginPresent_ = function () { - var gl = this.layer_.source.getContext('webgl'); - if (!gl) gl = this.layer_.source.getContext('experimental-webgl'); - if (!gl) gl = this.layer_.source.getContext('webgl2'); - if (!gl) return; - if (this.layer_.predistorted) { - if (!this.config.CARDBOARD_UI_DISABLED) { - gl.canvas.width = getScreenWidth() * this.bufferScale_; - gl.canvas.height = getScreenHeight() * this.bufferScale_; - this.cardboardUI_ = new CardboardUI(gl); - } - } else { - if (!this.config.CARDBOARD_UI_DISABLED) { - this.cardboardUI_ = new CardboardUI(gl); - } - this.distorter_ = new CardboardDistorter(gl, this.cardboardUI_, this.config.BUFFER_SCALE, this.config.DIRTY_SUBMIT_FRAME_BINDINGS); - this.distorter_.updateDeviceInfo(this.deviceInfo_); - } - if (this.cardboardUI_) { - this.cardboardUI_.listen(function (e) { - this.viewerSelector_.show(this.layer_.source.parentElement); - e.stopPropagation(); - e.preventDefault(); - }.bind(this), function (e) { - this.exitPresent(); - e.stopPropagation(); - e.preventDefault(); - }.bind(this)); - } - if (this.rotateInstructions_) { - if (isLandscapeMode() && isMobile()) { - this.rotateInstructions_.showTemporarily(3000, this.layer_.source.parentElement); - } else { - this.rotateInstructions_.update(); - } - } - this.orientationHandler = this.onOrientationChange_.bind(this); - window.addEventListener('orientationchange', this.orientationHandler); - this.vrdisplaypresentchangeHandler = this.updateBounds_.bind(this); - window.addEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler); - this.fireVRDisplayDeviceParamsChange_(); -}; -CardboardVRDisplay.prototype.endPresent_ = function () { - if (this.distorter_) { - this.distorter_.destroy(); - this.distorter_ = null; - } - if (this.cardboardUI_) { - this.cardboardUI_.destroy(); - this.cardboardUI_ = null; - } - if (this.rotateInstructions_) { - this.rotateInstructions_.hide(); - } - this.viewerSelector_.hide(); - window.removeEventListener('orientationchange', this.orientationHandler); - window.removeEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler); -}; -CardboardVRDisplay.prototype.updatePresent_ = function () { - this.endPresent_(); - this.beginPresent_(); -}; -CardboardVRDisplay.prototype.submitFrame = function (pose) { - if (this.distorter_) { - this.updateBounds_(); - this.distorter_.submitFrame(); - } else if (this.cardboardUI_ && this.layer_) { - var gl = this.layer_.source.getContext('webgl'); - if (!gl) gl = this.layer_.source.getContext('experimental-webgl'); - if (!gl) gl = this.layer_.source.getContext('webgl2'); - var canvas = gl.canvas; - if (canvas.width != this.lastWidth || canvas.height != this.lastHeight) { - this.cardboardUI_.onResize(); - } - this.lastWidth = canvas.width; - this.lastHeight = canvas.height; - this.cardboardUI_.render(); - } -}; -CardboardVRDisplay.prototype.onOrientationChange_ = function (e) { - this.viewerSelector_.hide(); - if (this.rotateInstructions_) { - this.rotateInstructions_.update(); - } - this.onResize_(); -}; -CardboardVRDisplay.prototype.onResize_ = function (e) { - if (this.layer_) { - var gl = this.layer_.source.getContext('webgl'); - if (!gl) gl = this.layer_.source.getContext('experimental-webgl'); - if (!gl) gl = this.layer_.source.getContext('webgl2'); - var cssProperties = ['position: absolute', 'top: 0', 'left: 0', - 'width: 100vw', 'height: 100vh', 'border: 0', 'margin: 0', - 'padding: 0px', 'box-sizing: content-box']; - gl.canvas.setAttribute('style', cssProperties.join('; ') + ';'); - safariCssSizeWorkaround(gl.canvas); - } -}; -CardboardVRDisplay.prototype.onViewerChanged_ = function (viewer) { - this.deviceInfo_.setViewer(viewer); - if (this.distorter_) { - this.distorter_.updateDeviceInfo(this.deviceInfo_); - } - this.fireVRDisplayDeviceParamsChange_(); -}; -CardboardVRDisplay.prototype.fireVRDisplayDeviceParamsChange_ = function () { - var event = new CustomEvent('vrdisplaydeviceparamschange', { - detail: { - vrdisplay: this, - deviceInfo: this.deviceInfo_ - } - }); - window.dispatchEvent(event); -}; -CardboardVRDisplay.VRFrameData = VRFrameData; -CardboardVRDisplay.VRDisplay = VRDisplay; -return CardboardVRDisplay; -}))); -}); -var CardboardVRDisplay = unwrapExports(cardboardVrDisplay); - -class XRDevice extends EventTarget { - constructor(global) { - super(); - this.global = global; - this.onWindowResize = this.onWindowResize.bind(this); - this.global.window.addEventListener('resize', this.onWindowResize); - this.environmentBlendMode = 'opaque'; - } - onBaseLayerSet(sessionId, layer) { throw new Error('Not implemented'); } - isSessionSupported(mode) { throw new Error('Not implemented'); } - isFeatureSupported(featureDescriptor) { throw new Error('Not implemented'); } - async requestSession(mode, enabledFeatures) { throw new Error('Not implemented'); } - requestAnimationFrame(callback) { throw new Error('Not implemented'); } - onFrameStart(sessionId) { throw new Error('Not implemented'); } - onFrameEnd(sessionId) { throw new Error('Not implemented'); } - doesSessionSupportReferenceSpace(sessionId, type) { throw new Error('Not implemented'); } - requestStageBounds() { throw new Error('Not implemented'); } - async requestFrameOfReferenceTransform(type, options) { - return undefined; - } - cancelAnimationFrame(handle) { throw new Error('Not implemented'); } - endSession(sessionId) { throw new Error('Not implemented'); } - getViewport(sessionId, eye, layer, target) { throw new Error('Not implemented'); } - getProjectionMatrix(eye) { throw new Error('Not implemented'); } - getBasePoseMatrix() { throw new Error('Not implemented'); } - getBaseViewMatrix(eye) { throw new Error('Not implemented'); } - getInputSources() { throw new Error('Not implemented'); } - getInputPose(inputSource, coordinateSystem, poseType) { throw new Error('Not implemented'); } - onWindowResize() { - this.onWindowResize(); - } -} - -let daydream = { - mapping: '', - profiles: ['google-daydream', 'generic-trigger-touchpad'], - buttons: { - length: 3, - 0: null, - 1: null, - 2: 0 - }, -}; -let viveFocus = { - mapping: 'xr-standard', - profiles: ['htc-vive-focus', 'generic-trigger-touchpad'], - buttons: { - length: 3, - 0: 1, - 1: null, - 2: 0 - }, -}; -let oculusGo = { - mapping: 'xr-standard', - profiles: ['oculus-go', 'generic-trigger-touchpad'], - buttons: { - length: 3, - 0: 1, - 1: null, - 2: 0 - }, - gripTransform: { - orientation: [Math.PI * 0.11, 0, 0, 1] - } -}; -let oculusTouch = { - mapping: 'xr-standard', - displayProfiles: { - 'Oculus Quest': ['oculus-touch-v2', 'oculus-touch', 'generic-trigger-squeeze-thumbstick'] - }, - profiles: ['oculus-touch', 'generic-trigger-squeeze-thumbstick'], - axes: { - length: 4, - 0: null, - 1: null, - 2: 0, - 3: 1 - }, - buttons: { - length: 7, - 0: 1, - 1: 2, - 2: null, - 3: 0, - 4: 3, - 5: 4, - 6: null - }, - gripTransform: { - position: [0, -0.02, 0.04, 1], - orientation: [Math.PI * 0.11, 0, 0, 1] - } -}; -let openVr = { - mapping: 'xr-standard', - profiles: ['htc-vive', 'generic-trigger-squeeze-touchpad'], - displayProfiles: { - 'HTC Vive': ['htc-vive', 'generic-trigger-squeeze-touchpad'], - 'HTC Vive DVT': ['htc-vive', 'generic-trigger-squeeze-touchpad'], - 'Valve Index': ['valve-index', 'generic-trigger-squeeze-touchpad-thumbstick'] - }, - buttons: { - length: 3, - 0: 1, - 1: 2, - 2: 0 - }, - gripTransform: { - position: [0, 0, 0.05, 1], - }, - targetRayTransform: { - orientation: [Math.PI * -0.08, 0, 0, 1] - }, - userAgentOverrides: { - "Firefox": { - axes: { - invert: [1, 3] - } - } - } -}; -let samsungGearVR = { - mapping: 'xr-standard', - profiles: ['samsung-gearvr', 'generic-trigger-touchpad'], - buttons: { - length: 3, - 0: 1, - 1: null, - 2: 0 - }, - gripTransform: { - orientation: [Math.PI * 0.11, 0, 0, 1] - } -}; -let samsungOdyssey = { - mapping: 'xr-standard', - profiles: ['samsung-odyssey', 'microsoft-mixed-reality', 'generic-trigger-squeeze-touchpad-thumbstick'], - buttons: { - length: 4, - 0: 1, - 1: 0, - 2: 2, - 3: 4, - }, - gripTransform: { - position: [0, -0.02, 0.04, 1], - orientation: [Math.PI * 0.11, 0, 0, 1] - } -}; -let windowsMixedReality = { - mapping: 'xr-standard', - profiles: ['microsoft-mixed-reality', 'generic-trigger-squeeze-touchpad-thumbstick'], - buttons: { - length: 4, - 0: 1, - 1: 0, - 2: 2, - 3: 4, - }, - gripTransform: { - position: [0, -0.02, 0.04, 1], - orientation: [Math.PI * 0.11, 0, 0, 1] - } -}; -let GamepadMappings = { - 'Daydream Controller': daydream, - 'Gear VR Controller': samsungGearVR, - 'HTC Vive Focus Controller': viveFocus, - 'Oculus Go Controller': oculusGo, - 'Oculus Touch (Right)': oculusTouch, - 'Oculus Touch (Left)': oculusTouch, - 'OpenVR Gamepad': openVr, - 'Spatial Controller (Spatial Interaction Source) 045E-065A': windowsMixedReality, - 'Spatial Controller (Spatial Interaction Source) 045E-065D': samsungOdyssey, - 'Windows Mixed Reality (Right)': windowsMixedReality, - 'Windows Mixed Reality (Left)': windowsMixedReality, -}; - -const HEAD_ELBOW_OFFSET_RIGHTHANDED = fromValues$1(0.155, -0.465, -0.15); -const HEAD_ELBOW_OFFSET_LEFTHANDED = fromValues$1(-0.155, -0.465, -0.15); -const ELBOW_WRIST_OFFSET = fromValues$1(0, 0, -0.25); -const WRIST_CONTROLLER_OFFSET = fromValues$1(0, 0, 0.05); -const ARM_EXTENSION_OFFSET = fromValues$1(-0.08, 0.14, 0.08); -const ELBOW_BEND_RATIO = 0.4; -const EXTENSION_RATIO_WEIGHT = 0.4; -const MIN_ANGULAR_SPEED = 0.61; -const MIN_ANGLE_DELTA = 0.175; -const MIN_EXTENSION_COS = 0.12; -const MAX_EXTENSION_COS = 0.87; -const RAD_TO_DEG = 180 / Math.PI; -function eulerFromQuaternion(out, q, order) { - function clamp(value, min$$1, max$$1) { - return (value < min$$1 ? min$$1 : (value > max$$1 ? max$$1 : value)); - } - var sqx = q[0] * q[0]; - var sqy = q[1] * q[1]; - var sqz = q[2] * q[2]; - var sqw = q[3] * q[3]; - if ( order === 'XYZ' ) { - out[0] = Math.atan2( 2 * ( q[0] * q[3] - q[1] * q[2] ), ( sqw - sqx - sqy + sqz ) ); - out[1] = Math.asin( clamp( 2 * ( q[0] * q[2] + q[1] * q[3] ), -1, 1 ) ); - out[2] = Math.atan2( 2 * ( q[2] * q[3] - q[0] * q[1] ), ( sqw + sqx - sqy - sqz ) ); - } else if ( order === 'YXZ' ) { - out[0] = Math.asin( clamp( 2 * ( q[0] * q[3] - q[1] * q[2] ), -1, 1 ) ); - out[1] = Math.atan2( 2 * ( q[0] * q[2] + q[1] * q[3] ), ( sqw - sqx - sqy + sqz ) ); - out[2] = Math.atan2( 2 * ( q[0] * q[1] + q[2] * q[3] ), ( sqw - sqx + sqy - sqz ) ); - } else if ( order === 'ZXY' ) { - out[0] = Math.asin( clamp( 2 * ( q[0] * q[3] + q[1] * q[2] ), -1, 1 ) ); - out[1] = Math.atan2( 2 * ( q[1] * q[3] - q[2] * q[0] ), ( sqw - sqx - sqy + sqz ) ); - out[2] = Math.atan2( 2 * ( q[2] * q[3] - q[0] * q[1] ), ( sqw - sqx + sqy - sqz ) ); - } else if ( order === 'ZYX' ) { - out[0] = Math.atan2( 2 * ( q[0] * q[3] + q[2] * q[1] ), ( sqw - sqx - sqy + sqz ) ); - out[1] = Math.asin( clamp( 2 * ( q[1] * q[3] - q[0] * q[2] ), -1, 1 ) ); - out[2] = Math.atan2( 2 * ( q[0] * q[1] + q[2] * q[3] ), ( sqw + sqx - sqy - sqz ) ); - } else if ( order === 'YZX' ) { - out[0] = Math.atan2( 2 * ( q[0] * q[3] - q[2] * q[1] ), ( sqw - sqx + sqy - sqz ) ); - out[1] = Math.atan2( 2 * ( q[1] * q[3] - q[0] * q[2] ), ( sqw + sqx - sqy - sqz ) ); - out[2] = Math.asin( clamp( 2 * ( q[0] * q[1] + q[2] * q[3] ), -1, 1 ) ); - } else if ( order === 'XZY' ) { - out[0] = Math.atan2( 2 * ( q[0] * q[3] + q[1] * q[2] ), ( sqw - sqx + sqy - sqz ) ); - out[1] = Math.atan2( 2 * ( q[0] * q[2] + q[1] * q[3] ), ( sqw + sqx - sqy - sqz ) ); - out[2] = Math.asin( clamp( 2 * ( q[2] * q[3] - q[0] * q[1] ), -1, 1 ) ); - } else { - console.log('No order given for quaternion to euler conversion.'); - return; - } -} -class OrientationArmModel { - constructor() { - this.hand = 'right'; - this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED; - this.controllerQ = create$4(); - this.lastControllerQ = create$4(); - this.headQ = create$4(); - this.headPos = create$1(); - this.elbowPos = create$1(); - this.wristPos = create$1(); - this.time = null; - this.lastTime = null; - this.rootQ = create$4(); - this.position = create$1(); - } - setHandedness(hand) { - if (this.hand != hand) { - this.hand = hand; - if (this.hand == 'left') { - this.headElbowOffset = HEAD_ELBOW_OFFSET_LEFTHANDED; - } else { - this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED; - } - } - } - update(controllerOrientation, headPoseMatrix) { - this.time = now$1(); - if (controllerOrientation) { - copy$4(this.lastControllerQ, this.controllerQ); - copy$4(this.controllerQ, controllerOrientation); - } - if (headPoseMatrix) { - getTranslation(this.headPos, headPoseMatrix); - getRotation(this.headQ, headPoseMatrix); - } - let headYawQ = this.getHeadYawOrientation_(); - let angleDelta = this.quatAngle_(this.lastControllerQ, this.controllerQ); - let timeDelta = (this.time - this.lastTime) / 1000; - let controllerAngularSpeed = angleDelta / timeDelta; - if (controllerAngularSpeed > MIN_ANGULAR_SPEED) { - slerp(this.rootQ, this.rootQ, headYawQ, - Math.min(angleDelta / MIN_ANGLE_DELTA, 1.0)); - } else { - copy$4(this.rootQ, headYawQ); - } - let controllerForward = fromValues$1(0, 0, -1.0); - transformQuat(controllerForward, controllerForward, this.controllerQ); - let controllerDotY = dot(controllerForward, [0, 1, 0]); - let extensionRatio = this.clamp_( - (controllerDotY - MIN_EXTENSION_COS) / MAX_EXTENSION_COS, 0.0, 1.0); - let controllerCameraQ = clone$4(this.rootQ); - invert$2(controllerCameraQ, controllerCameraQ); - multiply$4(controllerCameraQ, controllerCameraQ, this.controllerQ); - let elbowPos = this.elbowPos; - copy$1(elbowPos, this.headPos); - add$1(elbowPos, elbowPos, this.headElbowOffset); - let elbowOffset = clone$1(ARM_EXTENSION_OFFSET); - scale$1(elbowOffset, elbowOffset, extensionRatio); - add$1(elbowPos, elbowPos, elbowOffset); - let totalAngle = this.quatAngle_(controllerCameraQ, create$4()); - let totalAngleDeg = totalAngle * RAD_TO_DEG; - let lerpSuppression = 1 - Math.pow(totalAngleDeg / 180, 4);let elbowRatio = ELBOW_BEND_RATIO; - let wristRatio = 1 - ELBOW_BEND_RATIO; - let lerpValue = lerpSuppression * - (elbowRatio + wristRatio * extensionRatio * EXTENSION_RATIO_WEIGHT); - let wristQ = create$4(); - slerp(wristQ, wristQ, controllerCameraQ, lerpValue); - let invWristQ = invert$2(create$4(), wristQ); - let elbowQ = clone$4(controllerCameraQ); - multiply$4(elbowQ, elbowQ, invWristQ); - let wristPos = this.wristPos; - copy$1(wristPos, WRIST_CONTROLLER_OFFSET); - transformQuat(wristPos, wristPos, wristQ); - add$1(wristPos, wristPos, ELBOW_WRIST_OFFSET); - transformQuat(wristPos, wristPos, elbowQ); - add$1(wristPos, wristPos, elbowPos); - let offset = clone$1(ARM_EXTENSION_OFFSET); - scale$1(offset, offset, extensionRatio); - add$1(this.position, this.wristPos, offset); - transformQuat(this.position, this.position, this.rootQ); - this.lastTime = this.time; - } - getPosition() { - return this.position; - } - getHeadYawOrientation_() { - let headEuler = create$1(); - eulerFromQuaternion(headEuler, this.headQ, 'YXZ'); - let destinationQ = fromEuler(create$4(), 0, headEuler[1] * RAD_TO_DEG, 0); - return destinationQ; - } - clamp_(value, min$$1, max$$1) { - return Math.min(Math.max(value, min$$1), max$$1); - } - quatAngle_(q1, q2) { - let vec1 = [0, 0, -1]; - let vec2 = [0, 0, -1]; - transformQuat(vec1, vec1, q1); - transformQuat(vec2, vec2, q2); - return angle(vec1, vec2); - } -} - -const PRIVATE$18 = Symbol('@@webxr-polyfill/XRRemappedGamepad'); -const PLACEHOLDER_BUTTON = { pressed: false, touched: false, value: 0.0 }; -Object.freeze(PLACEHOLDER_BUTTON); -class XRRemappedGamepad { - constructor(gamepad, display, map) { - if (!map) { - map = {}; - } - if (map.userAgentOverrides) { - for (let agent in map.userAgentOverrides) { - if (navigator.userAgent.includes(agent)) { - let override = map.userAgentOverrides[agent]; - for (let key in override) { - if (key in map) { - Object.assign(map[key], override[key]); - } else { - map[key] = override[key]; - } - } - break; - } - } - } - let axes = new Array(map.axes && map.axes.length ? map.axes.length : gamepad.axes.length); - let buttons = new Array(map.buttons && map.buttons.length ? map.buttons.length : gamepad.buttons.length); - let gripTransform = null; - if (map.gripTransform) { - let orientation = map.gripTransform.orientation || [0, 0, 0, 1]; - gripTransform = create(); - fromRotationTranslation( - gripTransform, - normalize$2(orientation, orientation), - map.gripTransform.position || [0, 0, 0] - ); - } - let targetRayTransform = null; - if (map.targetRayTransform) { - let orientation = map.targetRayTransform.orientation || [0, 0, 0, 1]; - targetRayTransform = create(); - fromRotationTranslation( - targetRayTransform, - normalize$2(orientation, orientation), - map.targetRayTransform.position || [0, 0, 0] - ); - } - let profiles = map.profiles; - if (map.displayProfiles) { - if (display.displayName in map.displayProfiles) { - profiles = map.displayProfiles[display.displayName]; - } - } - this[PRIVATE$18] = { - gamepad, - map, - profiles: profiles || [gamepad.id], - mapping: map.mapping || gamepad.mapping, - axes, - buttons, - gripTransform, - targetRayTransform, - }; - this._update(); - } - _update() { - let gamepad = this[PRIVATE$18].gamepad; - let map = this[PRIVATE$18].map; - let axes = this[PRIVATE$18].axes; - for (let i = 0; i < axes.length; ++i) { - if (map.axes && i in map.axes) { - if (map.axes[i] === null) { - axes[i] = 0; - } else { - axes[i] = gamepad.axes[map.axes[i]]; - } - } else { - axes[i] = gamepad.axes[i]; - } - } - if (map.axes && map.axes.invert) { - for (let axis of map.axes.invert) { - if (axis < axes.length) { - axes[axis] *= -1; - } - } - } - let buttons = this[PRIVATE$18].buttons; - for (let i = 0; i < buttons.length; ++i) { - if (map.buttons && i in map.buttons) { - if (map.buttons[i] === null) { - buttons[i] = PLACEHOLDER_BUTTON; - } else { - buttons[i] = gamepad.buttons[map.buttons[i]]; - } - } else { - buttons[i] = gamepad.buttons[i]; - } - } - } - get id() { - return ''; - } - get _profiles() { - return this[PRIVATE$18].profiles; - } - get index() { - return -1; - } - get connected() { - return this[PRIVATE$18].gamepad.connected; - } - get timestamp() { - return this[PRIVATE$18].gamepad.timestamp; - } - get mapping() { - return this[PRIVATE$18].mapping; - } - get axes() { - return this[PRIVATE$18].axes; - } - get buttons() { - return this[PRIVATE$18].buttons; - } - get hapticActuators() { - return this[PRIVATE$18].gamepad.hapticActuators; - } -} -class GamepadXRInputSource { - constructor(polyfill, display, primaryButtonIndex = 0, primarySqueezeButtonIndex = -1) { - this.polyfill = polyfill; - this.display = display; - this.nativeGamepad = null; - this.gamepad = null; - this.inputSource = new XRInputSource(this); - this.lastPosition = create$1(); - this.emulatedPosition = false; - this.basePoseMatrix = create(); - this.outputMatrix = create(); - this.primaryButtonIndex = primaryButtonIndex; - this.primaryActionPressed = false; - this.primarySqueezeButtonIndex = primarySqueezeButtonIndex; - this.primarySqueezeActionPressed = false; - this.handedness = ''; - this.targetRayMode = 'gaze'; - this.armModel = null; - } - get profiles() { - return this.gamepad ? this.gamepad._profiles : []; - } - updateFromGamepad(gamepad) { - if (this.nativeGamepad !== gamepad) { - this.nativeGamepad = gamepad; - if (gamepad) { - this.gamepad = new XRRemappedGamepad(gamepad, this.display, GamepadMappings[gamepad.id]); - } else { - this.gamepad = null; - } - } - this.handedness = gamepad.hand === '' ? 'none' : gamepad.hand; - if (this.gamepad) { - this.gamepad._update(); - } - if (gamepad.pose) { - this.targetRayMode = 'tracked-pointer'; - this.emulatedPosition = !gamepad.pose.hasPosition; - } else if (gamepad.hand === '') { - this.targetRayMode = 'gaze'; - this.emulatedPosition = false; - } - } - updateBasePoseMatrix() { - if (this.nativeGamepad && this.nativeGamepad.pose) { - let pose = this.nativeGamepad.pose; - let position = pose.position; - let orientation = pose.orientation; - if (!position && !orientation) { - return; - } - if (!position) { - if (!pose.hasPosition) { - if (!this.armModel) { - this.armModel = new OrientationArmModel(); - } - this.armModel.setHandedness(this.nativeGamepad.hand); - this.armModel.update(orientation, this.polyfill.getBasePoseMatrix()); - position = this.armModel.getPosition(); - } else { - position = this.lastPosition; - } - } else { - this.lastPosition[0] = position[0]; - this.lastPosition[1] = position[1]; - this.lastPosition[2] = position[2]; - } - fromRotationTranslation(this.basePoseMatrix, orientation, position); - } else { - copy(this.basePoseMatrix, this.polyfill.getBasePoseMatrix()); - } - return this.basePoseMatrix; - } - getXRPose(coordinateSystem, poseType) { - this.updateBasePoseMatrix(); - switch(poseType) { - case "target-ray": - coordinateSystem._transformBasePoseMatrix(this.outputMatrix, this.basePoseMatrix); - if (this.gamepad && this.gamepad[PRIVATE$18].targetRayTransform) { - multiply(this.outputMatrix, this.outputMatrix, this.gamepad[PRIVATE$18].targetRayTransform); - } - break; - case "grip": - if (!this.nativeGamepad || !this.nativeGamepad.pose) { - return null; - } - coordinateSystem._transformBasePoseMatrix(this.outputMatrix, this.basePoseMatrix); - if (this.gamepad && this.gamepad[PRIVATE$18].gripTransform) { - multiply(this.outputMatrix, this.outputMatrix, this.gamepad[PRIVATE$18].gripTransform); - } - break; - default: - return null; - } - coordinateSystem._adjustForOriginOffset(this.outputMatrix); - return new XRPose(new XRRigidTransform(this.outputMatrix), this.emulatedPosition); - } -} - -const TEST_ENV = "production" === 'test'; -const EXTRA_PRESENTATION_ATTRIBUTES = { - highRefreshRate: true, -}; -const PRIMARY_BUTTON_MAP = { - oculus: 1, - openvr: 1, - 'spatial controller (spatial interaction source)': 1 -}; -let SESSION_ID = 0; -class Session { - constructor(mode, enabledFeatures, polyfillOptions={}) { - this.mode = mode; - this.enabledFeatures = enabledFeatures; - this.outputContext = null; - this.immersive = mode == 'immersive-vr' || mode == 'immersive-ar'; - this.ended = null; - this.baseLayer = null; - this.id = ++SESSION_ID; - this.modifiedCanvasLayer = false; - if (this.outputContext && !TEST_ENV) { - const renderContextType = polyfillOptions.renderContextType || '2d'; - this.renderContext = this.outputContext.canvas.getContext(renderContextType); - } - } -} -class WebVRDevice extends XRDevice { - constructor(global, display) { - const { canPresent } = display.capabilities; - super(global); - this.display = display; - this.frame = new global.VRFrameData(); - this.sessions = new Map(); - this.immersiveSession = null; - this.canPresent = canPresent; - this.baseModelMatrix = create(); - this.gamepadInputSources = {}; - this.tempVec3 = new Float32Array(3); - this.onVRDisplayPresentChange = this.onVRDisplayPresentChange.bind(this); - global.window.addEventListener('vrdisplaypresentchange', this.onVRDisplayPresentChange); - this.CAN_USE_GAMEPAD = global.navigator && ('getGamepads' in global.navigator); - this.HAS_BITMAP_SUPPORT = isImageBitmapSupported(global); - } - get depthNear() { return this.display.depthNear; } - set depthNear(val) { this.display.depthNear = val; } - get depthFar() { return this.display.depthFar; } - set depthFar(val) { this.display.depthFar = val; } - onBaseLayerSet(sessionId, layer) { - const session = this.sessions.get(sessionId); - const canvas = layer.context.canvas; - if (session.immersive) { - const left = this.display.getEyeParameters('left'); - const right = this.display.getEyeParameters('right'); - canvas.width = Math.max(left.renderWidth, right.renderWidth) * 2; - canvas.height = Math.max(left.renderHeight, right.renderHeight); - this.display.requestPresent([{ - source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES - }]).then(() => { - if (!TEST_ENV && !this.global.document.body.contains(canvas)) { - session.modifiedCanvasLayer = true; - this.global.document.body.appendChild(canvas); - applyCanvasStylesForMinimalRendering(canvas); - } - session.baseLayer = layer; - }); - } - else { - session.baseLayer = layer; - } - } - isSessionSupported(mode) { - if (mode == 'immersive-ar') { - return false; - } - if (mode == 'immersive-vr' && this.canPresent === false) { - return false; - } - return true; - } - isFeatureSupported(featureDescriptor) { - switch(featureDescriptor) { - case 'viewer': return true; - case 'local': return true; - case 'local-floor': return true; - case 'bounded': return false; - case 'unbounded': return false; - default: return false; - } - } - async requestSession(mode, enabledFeatures) { - if (!this.isSessionSupported(mode)) { - return Promise.reject(); - } - let immersive = mode == 'immersive-vr'; - if (immersive) { - const canvas = this.global.document.createElement('canvas'); - if (!TEST_ENV) { - const ctx = canvas.getContext('webgl'); - } - await this.display.requestPresent([{ - source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES }]); - } - const session = new Session(mode, enabledFeatures, { - renderContextType: this.HAS_BITMAP_SUPPORT ? 'bitmaprenderer' : '2d' - }); - this.sessions.set(session.id, session); - if (immersive) { - this.immersiveSession = session; - this.dispatchEvent('@@webxr-polyfill/vr-present-start', session.id); - } - return Promise.resolve(session.id); - } - requestAnimationFrame(callback) { - return this.display.requestAnimationFrame(callback); - } - getPrimaryButtonIndex(gamepad) { - let primaryButton = 0; - let name = gamepad.id.toLowerCase(); - for (let key in PRIMARY_BUTTON_MAP) { - if (name.includes(key)) { - primaryButton = PRIMARY_BUTTON_MAP[key]; - break; - } - } - return Math.min(primaryButton, gamepad.buttons.length - 1); - } - onFrameStart(sessionId, renderState) { - this.display.depthNear = renderState.depthNear; - this.display.depthFar = renderState.depthFar; - this.display.getFrameData(this.frame); - const session = this.sessions.get(sessionId); - if (session.immersive && this.CAN_USE_GAMEPAD) { - let prevInputSources = this.gamepadInputSources; - this.gamepadInputSources = {}; - let gamepads = this.global.navigator.getGamepads(); - for (let i = 0; i < gamepads.length; ++i) { - let gamepad = gamepads[i]; - if (gamepad && gamepad.displayId > 0) { - let inputSourceImpl = prevInputSources[i]; - if (!inputSourceImpl) { - inputSourceImpl = new GamepadXRInputSource(this, this.display, this.getPrimaryButtonIndex(gamepad)); - } - inputSourceImpl.updateFromGamepad(gamepad); - this.gamepadInputSources[i] = inputSourceImpl; - if (inputSourceImpl.primaryButtonIndex != -1) { - let primaryActionPressed = gamepad.buttons[inputSourceImpl.primaryButtonIndex].pressed; - if (primaryActionPressed && !inputSourceImpl.primaryActionPressed) { - this.dispatchEvent('@@webxr-polyfill/input-select-start', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); - } else if (!primaryActionPressed && inputSourceImpl.primaryActionPressed) { - this.dispatchEvent('@@webxr-polyfill/input-select-end', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); - } - inputSourceImpl.primaryActionPressed = primaryActionPressed; - } - if (inputSourceImpl.primarySqueezeButtonIndex != -1) { - let primarySqueezeActionPressed = gamepad.buttons[inputSourceImpl.primarySqueezeButtonIndex].pressed; - if (primarySqueezeActionPressed && !inputSourceImpl.primarySqueezeActionPressed) { - this.dispatchEvent('@@webxr-polyfill/input-squeeze-start', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); - } else if (!primarySqueezeActionPressed && inputSourceImpl.primarySqueezeActionPressed) { - this.dispatchEvent('@@webxr-polyfill/input-squeeze-end', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); - } - inputSourceImpl.primarySqueezeActionPressed = primarySqueezeActionPressed; - } - } - } - } - if (TEST_ENV) { - return; - } - if (!session.immersive && session.baseLayer) { - const canvas = session.baseLayer.context.canvas; - perspective(this.frame.leftProjectionMatrix, renderState.inlineVerticalFieldOfView, - canvas.width/canvas.height, renderState.depthNear, renderState.depthFar); - } - } - onFrameEnd(sessionId) { - const session = this.sessions.get(sessionId); - if (session.ended || !session.baseLayer) { - return; - } - if (session.outputContext && - !(session.immersive && !this.display.capabilities.hasExternalDisplay)) { - const mirroring = - session.immersive && this.display.capabilities.hasExternalDisplay; - const iCanvas = session.baseLayer.context.canvas; - const iWidth = mirroring ? iCanvas.width / 2 : iCanvas.width; - const iHeight = iCanvas.height; - if (!TEST_ENV) { - const oCanvas = session.outputContext.canvas; - const oWidth = oCanvas.width; - const oHeight = oCanvas.height; - const renderContext = session.renderContext; - if (this.HAS_BITMAP_SUPPORT) { - if (iCanvas.transferToImageBitmap) { - renderContext.transferFromImageBitmap(iCanvas.transferToImageBitmap()); - } - else { - this.global.createImageBitmap(iCanvas, 0, 0, iWidth, iHeight, { - resizeWidth: oWidth, - resizeHeight: oHeight, - }).then(bitmap => renderContext.transferFromImageBitmap(bitmap)); - } - } else { - renderContext.drawImage(iCanvas, 0, 0, iWidth, iHeight, - 0, 0, oWidth, oHeight); - } - } - } - if (session.immersive && session.baseLayer) { - this.display.submitFrame(); - } - } - cancelAnimationFrame(handle) { - this.display.cancelAnimationFrame(handle); - } - async endSession(sessionId) { - const session = this.sessions.get(sessionId); - if (session.ended) { - return; - } - if (session.immersive) { - return this.display.exitPresent(); - } else { - session.ended = true; - } - } - doesSessionSupportReferenceSpace(sessionId, type) { - const session = this.sessions.get(sessionId); - if (session.ended) { - return false; - } - return session.enabledFeatures.has(type); - } - requestStageBounds() { - if (this.display.stageParameters) { - const width = this.display.stageParameters.sizeX; - const depth = this.display.stageParameters.sizeZ; - const data = []; - data.push(-width / 2); - data.push(-depth / 2); - data.push(width / 2); - data.push(-depth / 2); - data.push(width / 2); - data.push(depth / 2); - data.push(-width / 2); - data.push(depth / 2); - return data; - } - return null; - } - async requestFrameOfReferenceTransform(type, options) { - if ((type === 'local-floor' || type === 'bounded-floor') && - this.display.stageParameters && - this.display.stageParameters.sittingToStandingTransform) { - return this.display.stageParameters.sittingToStandingTransform; - } - return null; - } - getProjectionMatrix(eye) { - if (eye === 'left') { - return this.frame.leftProjectionMatrix; - } else if (eye === 'right') { - return this.frame.rightProjectionMatrix; - } else if (eye === 'none') { - return this.frame.leftProjectionMatrix; - } else { - throw new Error(`eye must be of type 'left' or 'right'`); - } - } - getViewport(sessionId, eye, layer, target) { - const session = this.sessions.get(sessionId); - const { width, height } = layer.context.canvas; - if (!session.immersive) { - target.x = target.y = 0; - target.width = width; - target.height = height; - return true; - } - if (eye === 'left' || eye === 'none') { - target.x = 0; - } else if (eye === 'right') { - target.x = width / 2; - } else { - return false; - } - target.y = 0; - target.width = width / 2; - target.height = height; - return true; - } - getBasePoseMatrix() { - let { position, orientation } = this.frame.pose; - if (!position && !orientation) { - return this.baseModelMatrix; - } - if (!position) { - position = this.tempVec3; - position[0] = position[1] = position[2] = 0; - } - fromRotationTranslation(this.baseModelMatrix, orientation, position); - return this.baseModelMatrix; - } - getBaseViewMatrix(eye) { - if (eye === 'left' || eye === 'none') { - return this.frame.leftViewMatrix; - } else if (eye === 'right') { - return this.frame.rightViewMatrix; - } else { - throw new Error(`eye must be of type 'left' or 'right'`); - } - } - getInputSources() { - let inputSources = []; - for (let i in this.gamepadInputSources) { - inputSources.push(this.gamepadInputSources[i].inputSource); - } - return inputSources; - } - getInputPose(inputSource, coordinateSystem, poseType) { - if (!coordinateSystem) { - return null; - } - for (let i in this.gamepadInputSources) { - let inputSourceImpl = this.gamepadInputSources[i]; - if (inputSourceImpl.inputSource === inputSource) { - return inputSourceImpl.getXRPose(coordinateSystem, poseType); - } - } - return null; - } - onWindowResize() { - } - onVRDisplayPresentChange(e) { - if (!this.display.isPresenting) { - this.sessions.forEach(session => { - if (session.immersive && !session.ended) { - if (session.modifiedCanvasLayer) { - const canvas = session.baseLayer.context.canvas; - document.body.removeChild(canvas); - canvas.setAttribute('style', ''); - } - if (this.immersiveSession === session) { - this.immersiveSession = null; - } - this.dispatchEvent('@@webxr-polyfill/vr-present-end', session.id); - } - }); - } - } -} - -class CardboardXRDevice extends WebVRDevice { - constructor(global, cardboardConfig) { - const display = new CardboardVRDisplay(cardboardConfig || {}); - super(global, display); - this.display = display; - this.frame = { - rightViewMatrix: new Float32Array(16), - leftViewMatrix: new Float32Array(16), - rightProjectionMatrix: new Float32Array(16), - leftProjectionMatrix: new Float32Array(16), - pose: null, - timestamp: null, - }; - } -} - -const TEST_ENV$1 = "production" === 'test'; -let SESSION_ID$1 = 0; -class Session$1 { - constructor(mode, enabledFeatures) { - this.mode = mode; - this.enabledFeatures = enabledFeatures; - this.ended = null; - this.baseLayer = null; - this.id = ++SESSION_ID$1; - } -} -class InlineDevice extends XRDevice { - constructor(global) { - super(global); - this.sessions = new Map(); - this.projectionMatrix = create(); - this.identityMatrix = create(); - } - onBaseLayerSet(sessionId, layer) { - const session = this.sessions.get(sessionId); - session.baseLayer = layer; - } - isSessionSupported(mode) { - return mode == 'inline'; - } - isFeatureSupported(featureDescriptor) { - switch(featureDescriptor) { - case 'viewer': return true; - default: return false; - } - } - async requestSession(mode, enabledFeatures) { - if (!this.isSessionSupported(mode)) { - return Promise.reject(); - } - const session = new Session$1(mode, enabledFeatures); - this.sessions.set(session.id, session); - return Promise.resolve(session.id); - } - requestAnimationFrame(callback) { - return window.requestAnimationFrame(callback); - } - cancelAnimationFrame(handle) { - window.cancelAnimationFrame(handle); - } - onFrameStart(sessionId, renderState) { - if (TEST_ENV$1) { - return; - } - const session = this.sessions.get(sessionId); - if (session.baseLayer) { - const canvas = session.baseLayer.context.canvas; - perspective(this.projectionMatrix, renderState.inlineVerticalFieldOfView, - canvas.width/canvas.height, renderState.depthNear, renderState.depthFar); - } - } - onFrameEnd(sessionId) { - } - async endSession(sessionId) { - const session = this.sessions.get(sessionId); - session.ended = true; - } - doesSessionSupportReferenceSpace(sessionId, type) { - const session = this.sessions.get(sessionId); - if (session.ended) { - return false; - } - return session.enabledFeatures.has(type); - } - requestStageBounds() { - return null; - } - async requestFrameOfReferenceTransform(type, options) { - return null; - } - getProjectionMatrix(eye) { - return this.projectionMatrix; - } - getViewport(sessionId, eye, layer, target) { - const session = this.sessions.get(sessionId); - const { width, height } = layer.context.canvas; - target.x = target.y = 0; - target.width = width; - target.height = height; - return true; - } - getBasePoseMatrix() { - return this.identityMatrix; - } - getBaseViewMatrix(eye) { - return this.identityMatrix; - } - getInputSources() { - return []; - } - getInputPose(inputSource, coordinateSystem, poseType) { - return null; - } - onWindowResize() { - } -} - -const getWebVRDevice = async function (global) { - let device = null; - if ('getVRDisplays' in global.navigator) { - try { - const displays = await global.navigator.getVRDisplays(); - if (displays && displays.length) { - device = new WebVRDevice(global, displays[0]); - } - } catch (e) {} - } - return device; -}; -const requestXRDevice = async function (global, config) { - if (config.webvr) { - let xr = await getWebVRDevice(global); - if (xr) { - return xr; - } - } - let mobile = isMobile(global); - if ((mobile && config.cardboard) || - (!mobile && config.allowCardboardOnDesktop)) { - if (!global.VRFrameData) { - global.VRFrameData = function () { - this.rightViewMatrix = new Float32Array(16); - this.leftViewMatrix = new Float32Array(16); - this.rightProjectionMatrix = new Float32Array(16); - this.leftProjectionMatrix = new Float32Array(16); - this.pose = null; - }; - } - return new CardboardXRDevice(global, config.cardboardConfig); - } - return new InlineDevice(global); -}; - -const CONFIG_DEFAULTS = { - global: _global, - webvr: true, - cardboard: true, - cardboardConfig: null, - allowCardboardOnDesktop: false, -}; -const partials = ['navigator', 'HTMLCanvasElement', 'WebGLRenderingContext']; -class WebXRPolyfill { - constructor(config={}) { - this.config = Object.freeze(Object.assign({}, CONFIG_DEFAULTS, config)); - this.global = this.config.global; - this.nativeWebXR = 'xr' in this.global.navigator; - this.injected = false; - if (!this.nativeWebXR) { - this._injectPolyfill(this.global); - } else { - this._injectCompatibilityShims(this.global); - } - } - _injectPolyfill(global) { - if (!partials.every(iface => !!global[iface])) { - throw new Error(`Global must have the following attributes : ${partials}`); - } - for (const className of Object.keys(API)) { - if (global[className] !== undefined) { - console.warn(`${className} already defined on global.`); - } else { - global[className] = API[className]; - } - } - { - const polyfilledCtx = polyfillMakeXRCompatible(global.WebGLRenderingContext); - if (polyfilledCtx) { - polyfillGetContext(global.HTMLCanvasElement); - if (global.OffscreenCanvas) { - polyfillGetContext(global.OffscreenCanvas); - } - if (global.WebGL2RenderingContext){ - polyfillMakeXRCompatible(global.WebGL2RenderingContext); - } - } - } - this.injected = true; - this._patchNavigatorXR(); - } - _patchNavigatorXR() { - let devicePromise = requestXRDevice(this.global, this.config); - this.xr = new API.XR(devicePromise); - Object.defineProperty(this.global.navigator, 'xr', { - value: this.xr, - configurable: true, - }); - } - _injectCompatibilityShims(global) { - if (!partials.every(iface => !!global[iface])) { - throw new Error(`Global must have the following attributes : ${partials}`); - } - if (global.navigator.xr && - 'supportsSession' in global.navigator.xr && - !('isSessionSupported' in global.navigator.xr)) { - let originalSupportsSession = global.navigator.xr.supportsSession; - global.navigator.xr.isSessionSupported = function(mode) { - return originalSupportsSession.call(this, mode).then(() => { - return true; - }).catch(() => { - return false; - }); - }; - global.navigator.xr.supportsSession = function(mode) { - console.warn("navigator.xr.supportsSession() is deprecated. Please " + - "call navigator.xr.isSessionSupported() instead and check the boolean " + - "value returned when the promise resolves."); - return originalSupportsSession.call(this, mode); - }; - } - } -} - -return WebXRPolyfill; - -}))); diff --git a/build/webxr-polyfill.min.js b/build/webxr-polyfill.min.js deleted file mode 100644 index 8031aa7..0000000 --- a/build/webxr-polyfill.min.js +++ /dev/null @@ -1,95 +0,0 @@ -/** - * @license - * webxr-polyfill - * Copyright (c) 2017 Google - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @license - * cardboard-vr-display - * Copyright (c) 2015-2017 Google - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @license - * webvr-polyfill-dpdb - * Copyright (c) 2017 Google - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @license - * wglu-preserve-state - * Copyright (c) 2016, Brandon Jones. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -/** - * @license - * nosleep.js - * Copyright (c) 2017, Rich Tibbett - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.WebXRPolyfill=t()}(this,function(){"use strict";const e="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},t=Symbol("@@webxr-polyfill/EventTarget");class i{constructor(){this[t]={listeners:new Map}}addEventListener(e,i){if("string"!=typeof e)throw new Error("`type` must be a string");if("function"!=typeof i)throw new Error("`listener` must be a function");const r=this[t].listeners.get(e)||[];r.push(i),this[t].listeners.set(e,r)}removeEventListener(e,i){if("string"!=typeof e)throw new Error("`type` must be a string");if("function"!=typeof i)throw new Error("`listener` must be a function");const r=this[t].listeners.get(e)||[];for(let e=r.length;e>=0;e--)r[e]===i&&r.pop()}dispatchEvent(e,i){const r=this[t].listeners.get(e)||[],s=[];for(let e=0;e0?(r=2*Math.sqrt(i+1),e[3]=.25*r,e[0]=(t[6]-t[9])/r,e[1]=(t[8]-t[2])/r,e[2]=(t[1]-t[4])/r):t[0]>t[5]&&t[0]>t[10]?(r=2*Math.sqrt(1+t[0]-t[5]-t[10]),e[3]=(t[6]-t[9])/r,e[0]=.25*r,e[1]=(t[1]+t[4])/r,e[2]=(t[8]+t[2])/r):t[5]>t[10]?(r=2*Math.sqrt(1+t[5]-t[0]-t[10]),e[3]=(t[8]-t[2])/r,e[0]=(t[1]+t[4])/r,e[1]=.25*r,e[2]=(t[6]+t[9])/r):(r=2*Math.sqrt(1+t[10]-t[0]-t[5]),e[3]=(t[1]-t[4])/r,e[0]=(t[8]+t[2])/r,e[1]=(t[6]+t[9])/r,e[2]=.25*r),e}function d(e,t,i,r,s){let n,a=1/Math.tan(t/2);return e[0]=a/i,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=a,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[11]=-1,e[12]=0,e[13]=0,e[15]=0,null!=s&&s!==1/0?(n=1/(r-s),e[10]=(s+r)*n,e[14]=2*s*r*n):(e[10]=-1,e[14]=-2*r),e}function u(){let e=new s(3);return s!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e}function p(e){var t=new s(3);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t}function f(e,t,i){let r=new s(3);return r[0]=e,r[1]=t,r[2]=i,r}function m(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e}function g(e,t,i){return e[0]=t[0]+i[0],e[1]=t[1]+i[1],e[2]=t[2]+i[2],e}function v(e,t,i){return e[0]=t[0]*i,e[1]=t[1]*i,e[2]=t[2]*i,e}function w(e,t){let i=t[0],r=t[1],s=t[2],n=i*i+r*r+s*s;return n>0&&(n=1/Math.sqrt(n),e[0]=t[0]*n,e[1]=t[1]*n,e[2]=t[2]*n),e}function y(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]}function b(e,t,i){let r=t[0],s=t[1],n=t[2],a=i[0],o=i[1],l=i[2];return e[0]=s*l-n*o,e[1]=n*a-r*l,e[2]=r*o-s*a,e}function E(e,t,i){let r=i[0],s=i[1],n=i[2],a=i[3],o=t[0],l=t[1],A=t[2],h=s*A-n*l,c=n*o-r*A,d=r*l-s*o,u=s*d-n*c,p=n*h-r*d,f=r*c-s*h,m=2*a;return h*=m,c*=m,d*=m,u*=2,p*=2,f*=2,e[0]=o+h+u,e[1]=l+c+p,e[2]=A+d+f,e}const S=function(e){let t=e[0],i=e[1],r=e[2];return Math.sqrt(t*t+i*i+r*r)};!function(){let e=u()}();!function(){let e=function(){let e=new s(4);return s!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0,e[3]=0),e}()}();function M(){let e=new s(4);return s!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e[3]=1,e}function x(e,t,i){let r=t[0],s=t[1],n=t[2],a=t[3],o=i[0],l=i[1],A=i[2],h=i[3];return e[0]=r*h+a*o+s*A-n*l,e[1]=s*h+a*l+n*o-r*A,e[2]=n*h+a*A+r*l-s*o,e[3]=a*h-r*o-s*l-n*A,e}function _(e,t,i,s){let n,a,o,l,A,h=t[0],c=t[1],d=t[2],u=t[3],p=i[0],f=i[1],m=i[2],g=i[3];return(a=h*p+c*f+d*m+u*g)<0&&(a=-a,p=-p,f=-f,m=-m,g=-g),1-a>r?(n=Math.acos(a),o=Math.sin(n),l=Math.sin((1-s)*n)/o,A=Math.sin(s*n)/o):(l=1-s,A=s),e[0]=l*h+A*p,e[1]=l*c+A*f,e[2]=l*d+A*m,e[3]=l*u+A*g,e}function F(e,t){let i=t[0],r=t[1],s=t[2],n=t[3],a=i*i+r*r+s*s+n*n,o=a?1/a:0;return e[0]=-i*o,e[1]=-r*o,e[2]=-s*o,e[3]=n*o,e}const R=function(e){let t=new s(4);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},T=function(e,t,i,r){let n=new s(4);return n[0]=e,n[1]=t,n[2]=i,n[3]=r,n},B=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e},P=function(e,t){let i=t[0],r=t[1],s=t[2],n=t[3],a=i*i+r*r+s*s+n*n;return a>0&&(a=1/Math.sqrt(a),e[0]=i*a,e[1]=r*a,e[2]=s*a,e[3]=n*a),e},C=(function(){let e=u(),t=f(1,0,0),i=f(0,1,0)}(),function(){let e=M(),t=M()}(),function(){let e=function(){let e=new s(9);return s!=Float32Array&&(e[1]=0,e[2]=0,e[3]=0,e[5]=0,e[6]=0,e[7]=0),e[0]=1,e[4]=1,e[8]=1,e}()}(),Symbol("@@webxr-polyfill/XRRigidTransform"));class D{constructor(){if(this[C]={matrix:null,position:null,orientation:null,inverse:null},0===arguments.length)this[C].matrix=a(new Float32Array(16));else if(1===arguments.length)arguments[0]instanceof Float32Array?this[C].matrix=arguments[0]:(this[C].position=this._getPoint(arguments[0]),this[C].orientation=DOMPointReadOnly.fromPoint({x:0,y:0,z:0,w:1}));else{if(2!==arguments.length)throw new Error("Too many arguments!");this[C].position=this._getPoint(arguments[0]),this[C].orientation=this._getPoint(arguments[1])}if(this[C].matrix){let e=u();h(e,this[C].matrix),this[C].position=DOMPointReadOnly.fromPoint({x:e[0],y:e[1],z:e[2]});let t=M();c(t,this[C].matrix),this[C].orientation=DOMPointReadOnly.fromPoint({x:t[0],y:t[1],z:t[2],w:t[3]})}else this[C].matrix=a(new Float32Array(16)),A(this[C].matrix,T(this[C].orientation.x,this[C].orientation.y,this[C].orientation.z,this[C].orientation.w),f(this[C].position.x,this[C].position.y,this[C].position.z))}_getPoint(e){return e instanceof DOMPointReadOnly?e:DOMPointReadOnly.fromPoint(e)}get matrix(){return this[C].matrix}get position(){return this[C].position}get orientation(){return this[C].orientation}get inverse(){if(null===this[C].inverse){let e=a(new Float32Array(16));o(e,this[C].matrix),this[C].inverse=new D(e),this[C].inverse[C].inverse=this}return this[C].inverse}}const I=Symbol("@@webxr-polyfill/XRSpace");class L{constructor(e=null,t=null){this[I]={specialType:e,inputSource:t,baseMatrix:null,inverseBaseMatrix:null,lastFrameId:-1}}get _specialType(){return this[I].specialType}get _inputSource(){return this[I].inputSource}_ensurePoseUpdated(e,t){t!=this[I].lastFrameId&&(this[I].lastFrameId=t,this._onPoseUpdate(e))}_onPoseUpdate(e){"viewer"==this[I].specialType&&(this._baseMatrix=e.getBasePoseMatrix())}set _baseMatrix(e){this[I].baseMatrix=e,this[I].inverseBaseMatrix=null}get _baseMatrix(){return this[I].baseMatrix||this[I].inverseBaseMatrix&&(this[I].baseMatrix=new Float32Array(16),o(this[I].baseMatrix,this[I].inverseBaseMatrix)),this[I].baseMatrix}set _inverseBaseMatrix(e){this[I].inverseBaseMatrix=e,this[I].baseMatrix=null}get _inverseBaseMatrix(){return this[I].inverseBaseMatrix||this[I].baseMatrix&&(this[I].inverseBaseMatrix=new Float32Array(16),o(this[I].inverseBaseMatrix,this[I].baseMatrix)),this[I].inverseBaseMatrix}_getSpaceRelativeTransform(e){if(!this._inverseBaseMatrix||!e._baseMatrix)return null;let t=new Float32Array(16);return l(t,this._inverseBaseMatrix,e._baseMatrix),new D(t)}}const O=1.6,N=Symbol("@@webxr-polyfill/XRReferenceSpace"),G=["viewer","local","local-floor","bounded-floor","unbounded"];class Q extends L{constructor(e,t=null){if(!G.includes(e))throw new Error(`XRReferenceSpaceType must be one of ${G}`);if(super(e),"bounded-floor"===e&&!t)throw new Error("XRReferenceSpace cannot use 'bounded-floor' type if the platform does not provide the floor level");(function(e){return"bounded-floor"===e||"local-floor"===e})(e)&&!t&&((t=a(new Float32Array(16)))[13]=O),this._inverseBaseMatrix=t||a(new Float32Array(16)),this[N]={type:e,transform:t,originOffset:a(new Float32Array(16))}}_transformBasePoseMatrix(e,t){l(e,this._inverseBaseMatrix,t)}_originOffsetMatrix(){return this[N].originOffset}_adjustForOriginOffset(e){let t=new Float32Array(16);o(t,this[N].originOffset),l(e,t,e)}_getSpaceRelativeTransform(e){let t=super._getSpaceRelativeTransform(e);return this._adjustForOriginOffset(t.matrix),new XRRigidTransform(t.matrix)}getOffsetReferenceSpace(e){let t=new Q(this[N].type,this[N].transform,this[N].bounds);return l(t[N].originOffset,this[N].originOffset,e.matrix),t}}const k=Symbol("@@webxr-polyfill/XR"),z=["inline","immersive-vr","immersive-ar"],U={inline:{requiredFeatures:["viewer"],optionalFeatures:[]},"immersive-vr":{requiredFeatures:["viewer","local"],optionalFeatures:[]},"immersive-ar":{requiredFeatures:["viewer","local"],optionalFeatures:[]}},V="Polyfill Error: Must call navigator.xr.isSessionSupported() with any XRSessionMode\nor navigator.xr.requestSession('inline') prior to requesting an immersive\nsession. This is a limitation specific to the WebXR Polyfill and does not apply\nto native implementations of the API.";let H;if("performance"in e==!1){let e=Date.now();H=(()=>Date.now()-e)}else H=(()=>performance.now());var X=H;const W=Symbol("@@webxr-polyfill/XRPose");class j{constructor(e,t){this[W]={transform:e,emulatedPosition:t}}get transform(){return this[W].transform}get emulatedPosition(){return this[W].emulatedPosition}}const q=Symbol("@@webxr-polyfill/XRViewerPose");class Y extends j{constructor(e,t,i=!1){super(e,i),this[q]={views:t}}get views(){return this[q].views}}const Z=Symbol("@@webxr-polyfill/XRViewport");class J{constructor(e){this[Z]={target:e}}get x(){return this[Z].target.x}get y(){return this[Z].target.y}get width(){return this[Z].target.width}get height(){return this[Z].target.height}}const K=["left","right","none"],$=Symbol("@@webxr-polyfill/XRView");class ee{constructor(e,t,i,r){if(!K.includes(i))throw new Error(`XREye must be one of: ${K}`);const s=Object.create(null),n=new J(s);this[$]={device:e,eye:i,viewport:n,temp:s,sessionId:r,transform:t}}get eye(){return this[$].eye}get projectionMatrix(){return this[$].device.getProjectionMatrix(this.eye)}get transform(){return this[$].transform}_getViewport(e){if(this[$].device.getViewport(this[$].sessionId,this.eye,e,this[$].temp))return this[$].viewport}}const te=Symbol("@@webxr-polyfill/XRFrame"),ie="XRFrame access outside the callback that produced it is invalid.",re="getViewerPose can only be called on XRFrame objects passed to XRSession.requestAnimationFrame callbacks.";let se=0;class ne{constructor(e,t,i){this[te]={id:++se,active:!1,animationFrame:!1,device:e,session:t,sessionId:i}}get session(){return this[te].session}getViewerPose(e){if(!this[te].animationFrame)throw new DOMException(re,"InvalidStateError");if(!this[te].active)throw new DOMException(ie,"InvalidStateError");const t=this[te].device,i=this[te].session;i[we].viewerSpace._ensurePoseUpdated(t,this[te].id),e._ensurePoseUpdated(t,this[te].id);let r=e._getSpaceRelativeTransform(i[we].viewerSpace);const s=[];for(let r of i[we].viewSpaces){r._ensurePoseUpdated(t,this[te].id);let i=e._getSpaceRelativeTransform(r),n=new ee(t,i,r.eye,this[te].sessionId);s.push(n)}return new Y(r,s,!1)}getPose(e,t){if(!this[te].active)throw new DOMException(ie,"InvalidStateError");const i=this[te].device;if("target-ray"===e._specialType||"grip"===e._specialType)return i.getInputPose(e._inputSource,t,e._specialType);{e._ensurePoseUpdated(i,this[te].id),t._ensurePoseUpdated(i,this[te].id);let r=t._getSpaceRelativeTransform(e);return r?new XRPose(r,!1):null}}}const ae=Symbol("@@webxr-polyfill/XRRenderState"),oe=Object.freeze({depthNear:.1,depthFar:1e3,inlineVerticalFieldOfView:null,baseLayer:null});class le{constructor(e={}){const t=Object.assign({},oe,e);this[ae]={config:t}}get depthNear(){return this[ae].config.depthNear}get depthFar(){return this[ae].config.depthFar}get inlineVerticalFieldOfView(){return this[ae].config.inlineVerticalFieldOfView}get baseLayer(){return this[ae].config.baseLayer}}const Ae=Symbol("@@webxr-polyfill/polyfilled-xr-compatible"),he=Symbol("@@webxr-polyfill/xr-compatible"),ce=Symbol("@@webxr-polyfill/XRWebGLLayer"),de=Object.freeze({antialias:!0,depth:!1,stencil:!1,alpha:!0,multiview:!1,ignoreDepthValues:!1,framebufferScaleFactor:1});const ue=Symbol("@@webxr-polyfill/XRInputSourceEvent");class pe extends Event{constructor(e,t){super(e,t),this[ue]={frame:t.frame,inputSource:t.inputSource}}get frame(){return this[ue].frame}get inputSource(){return this[ue].inputSource}}const fe=Symbol("@@webxr-polyfill/XRSessionEvent");class me extends Event{constructor(e,t){super(e,t),this[fe]={session:t.session}}get session(){return this[fe].session}}const ge=Symbol("@@webxr-polyfill/XRInputSourcesChangeEvent");class ve extends Event{constructor(e,t){super(e,t),this[ge]={session:t.session,added:t.added,removed:t.removed}}get session(){return this[ge].session}get added(){return this[ge].added}get removed(){return this[ge].removed}}const we=Symbol("@@webxr-polyfill/XRSession");class ye extends L{constructor(e){super(e)}get eye(){return this._specialType}_onPoseUpdate(e){this._inverseBaseMatrix=e.getBaseViewMatrix(this._specialType)}}class be extends i{constructor(e,t,i){super();let r="inline"!=t,s=new le({inlineVerticalFieldOfView:r?null:.5*Math.PI});this[we]={device:e,mode:t,immersive:r,ended:!1,suspended:!1,frameCallbacks:[],currentFrameCallbacks:null,frameHandle:0,deviceFrameHandle:null,id:i,activeRenderState:s,pendingRenderState:null,viewerSpace:new Q("viewer"),viewSpaces:[],currentInputSources:[]},r?this[we].viewSpaces.push(new ye("left"),new ye("right")):this[we].viewSpaces.push(new ye("none")),this[we].onDeviceFrame=(()=>{if(this[we].ended||this[we].suspended)return;if(this[we].deviceFrameHandle=null,this[we].startDeviceFrameLoop(),null!==this[we].pendingRenderState&&(this[we].activeRenderState=new le(this[we].pendingRenderState),this[we].pendingRenderState=null,this[we].activeRenderState.baseLayer&&this[we].device.onBaseLayerSet(this[we].id,this[we].activeRenderState.baseLayer)),null===this[we].activeRenderState.baseLayer)return;const t=new ne(e,this,this[we].id),i=this[we].currentFrameCallbacks=this[we].frameCallbacks;this[we].frameCallbacks=[],t[te].active=!0,t[te].animationFrame=!0,this[we].device.onFrameStart(this[we].id,this[we].activeRenderState),this._checkInputSourcesChange();const r=X();for(let e=0;e{null===this[we].deviceFrameHandle&&(this[we].deviceFrameHandle=this[we].device.requestAnimationFrame(this[we].onDeviceFrame))}),this[we].stopDeviceFrameLoop=(()=>{const e=this[we].deviceFrameHandle;null!==e&&(this[we].device.cancelAnimationFrame(e),this[we].deviceFrameHandle=null)}),this[we].onPresentationEnd=(t=>{if(t!==this[we].id)return this[we].suspended=!1,this[we].startDeviceFrameLoop(),void this.dispatchEvent("focus",{session:this});this[we].ended=!0,this[we].stopDeviceFrameLoop(),e.removeEventListener("@webvr-polyfill/vr-present-end",this[we].onPresentationEnd),e.removeEventListener("@webvr-polyfill/vr-present-start",this[we].onPresentationStart),e.removeEventListener("@@webvr-polyfill/input-select-start",this[we].onSelectStart),e.removeEventListener("@@webvr-polyfill/input-select-end",this[we].onSelectEnd),this.dispatchEvent("end",new me("end",{session:this}))}),e.addEventListener("@@webxr-polyfill/vr-present-end",this[we].onPresentationEnd),this[we].onPresentationStart=(e=>{e!==this[we].id&&(this[we].suspended=!0,this[we].stopDeviceFrameLoop(),this.dispatchEvent("blur",{session:this}))}),e.addEventListener("@@webxr-polyfill/vr-present-start",this[we].onPresentationStart),this[we].onSelectStart=(e=>{e.sessionId===this[we].id&&this[we].dispatchInputSourceEvent("selectstart",e.inputSource)}),e.addEventListener("@@webxr-polyfill/input-select-start",this[we].onSelectStart),this[we].onSelectEnd=(e=>{e.sessionId===this[we].id&&(this[we].dispatchInputSourceEvent("selectend",e.inputSource),this[we].dispatchInputSourceEvent("select",e.inputSource))}),e.addEventListener("@@webxr-polyfill/input-select-end",this[we].onSelectEnd),this[we].onSqueezeStart=(e=>{e.sessionId===this[we].id&&this[we].dispatchInputSourceEvent("squeezestart",e.inputSource)}),e.addEventListener("@@webxr-polyfill/input-squeeze-start",this[we].onSqueezeStart),this[we].onSqueezeEnd=(e=>{e.sessionId===this[we].id&&(this[we].dispatchInputSourceEvent("squeezeend",e.inputSource),this[we].dispatchInputSourceEvent("squeeze",e.inputSource))}),e.addEventListener("@@webxr-polyfill/input-squeeze-end",this[we].onSqueezeEnd),this[we].dispatchInputSourceEvent=((t,i)=>{const r=new ne(e,this,this[we].id),s=new pe(t,{frame:r,inputSource:i});r[te].active=!0,this.dispatchEvent(t,s),r[te].active=!1}),this[we].startDeviceFrameLoop(),this.onblur=void 0,this.onfocus=void 0,this.onresetpose=void 0,this.onend=void 0,this.onselect=void 0,this.onselectstart=void 0,this.onselectend=void 0}get renderState(){return this[we].activeRenderState}get environmentBlendMode(){return this[we].device.environmentBlendMode||"opaque"}async requestReferenceSpace(e){if(this[we].ended)return;if(!G.includes(e))throw new TypeError(`XRReferenceSpaceType must be one of ${G}`);if(!this[we].device.doesSessionSupportReferenceSpace(this[we].id,e))throw new DOMException(`The ${e} reference space is not supported by this session.`,"NotSupportedError");if("viewer"===e)return this[we].viewerSpace;let t=await this[we].device.requestFrameOfReferenceTransform(e);if("bounded-floor"===e){if(!t)throw new DOMException(`${e} XRReferenceSpace not supported by this device.`,"NotSupportedError");if(!this[we].device.requestStageBounds())throw new DOMException(`${e} XRReferenceSpace not supported by this device.`,"NotSupportedError");throw new DOMException(`The WebXR polyfill does not support the ${e} reference space yet.`,"NotSupportedError")}return new Q(e,t)}requestAnimationFrame(e){if(this[we].ended)return;const t=++this[we].frameHandle;return this[we].frameCallbacks.push({handle:t,callback:e,cancelled:!1}),t}cancelAnimationFrame(e){let t=this[we].frameCallbacks,i=t.findIndex(t=>t&&t.handle===e);i>-1&&(t[i].cancelled=!0,t.splice(i,1)),(t=this[we].currentFrameCallbacks)&&(i=t.findIndex(t=>t&&t.handle===e))>-1&&(t[i].cancelled=!0)}get inputSources(){return this[we].device.getInputSources()}async end(){if(!this[we].ended)return this[we].immersive&&(this[we].ended=!0,this[we].device.removeEventListener("@@webvr-polyfill/vr-present-start",this[we].onPresentationStart),this[we].device.removeEventListener("@@webvr-polyfill/vr-present-end",this[we].onPresentationEnd),this[we].device.removeEventListener("@@webvr-polyfill/input-select-start",this[we].onSelectStart),this[we].device.removeEventListener("@@webvr-polyfill/input-select-end",this[we].onSelectEnd),this.dispatchEvent("end",new me("end",{session:this}))),this[we].stopDeviceFrameLoop(),this[we].device.endSession(this[we].id)}updateRenderState(e){if(this[we].ended){throw new Error("Can't call updateRenderState on an XRSession that has already ended.")}if(e.baseLayer&&e.baseLayer._session!==this){throw new Error("Called updateRenderState with a base layer that was created by a different session.")}if(null!==e.inlineVerticalFieldOfView&&void 0!==e.inlineVerticalFieldOfView){if(this[we].immersive){throw new Error("inlineVerticalFieldOfView must not be set for an XRRenderState passed to updateRenderState for an immersive session.")}e.inlineVerticalFieldOfView=Math.min(3.13,Math.max(.01,e.inlineVerticalFieldOfView))}if(null===this[we].pendingRenderState){const e=this[we].activeRenderState;this[we].pendingRenderState={depthNear:e.depthNear,depthFar:e.depthFar,inlineVerticalFieldOfView:e.inlineVerticalFieldOfView,baseLayer:e.baseLayer}}Object.assign(this[we].pendingRenderState,e)}_checkInputSourcesChange(){const e=[],t=[],i=this.inputSources,r=this[we].currentInputSources;for(const t of i)r.includes(t)||e.push(t);for(const e of r)i.includes(e)||t.push(e);(e.length>0||t.length>0)&&this.dispatchEvent("inputsourceschange",new ve("inputsourceschange",{session:this,added:e,removed:t})),this[we].currentInputSources.length=0;for(const e of i)this[we].currentInputSources.push(e)}}const Ee=Symbol("@@webxr-polyfill/XRInputSource");class Se{constructor(e){this[Ee]={impl:e,gripSpace:new L("grip",this),targetRaySpace:new L("target-ray",this)}}get handedness(){return this[Ee].impl.handedness}get targetRayMode(){return this[Ee].impl.targetRayMode}get gripSpace(){let e=this[Ee].impl.targetRayMode;return"gaze"===e||"screen"===e?null:this[Ee].gripSpace}get targetRaySpace(){return this[Ee].targetRaySpace}get profiles(){return this[Ee].impl.profiles}get gamepad(){return this[Ee].impl.gamepad}}const Me=Symbol("@@webxr-polyfill/XRReferenceSpaceEvent");var xe={XR:class extends i{constructor(e){super(),this[k]={device:null,devicePromise:e,immersiveSession:null,inlineSessions:new Set},e.then(e=>{this[k].device=e})}async isSessionSupported(e){return this[k].device||await this[k].devicePromise,"inline"!=e?Promise.resolve(this[k].device.isSessionSupported(e)):Promise.resolve(!0)}async requestSession(e,t){if(!this[k].device){if("inline"!=e)throw new Error(V);await this[k].devicePromise}if(!z.includes(e))throw new TypeError(`The provided value '${e}' is not a valid enum value of type XRSessionMode`);const i=U[e],r=i.requiredFeatures.concat(t&&t.requiredFeatures?t.requiredFeatures:[]),s=i.optionalFeatures.concat(t&&t.optionalFeatures?t.optionalFeatures:[]),n=new Set;let a=!1;for(let e of r)this[k].device.isFeatureSupported(e)?n.add(e):(console.error(`The required feature '${e}' is not supported`),a=!0);if(a)throw new DOMException("Session does not support some required features","NotSupportedError");for(let e of s)this[k].device.isFeatureSupported(e)?n.add(e):console.log(`The optional feature '${e}' is not supported`);const o=await this[k].device.requestSession(e,n),l=new XRSession(this[k].device,e,o);"inline"==e?this[k].inlineSessions.add(l):this[k].immersiveSession=l;const A=()=>{"inline"==e?this[k].inlineSessions.delete(l):this[k].immersiveSession=null,l.removeEventListener("end",A)};return l.addEventListener("end",A),l}},XRSession:be,XRSessionEvent:me,XRFrame:ne,XRView:ee,XRViewport:J,XRViewerPose:Y,XRWebGLLayer:class{constructor(e,t,i={}){const r=Object.assign({},de,i);if(!(e instanceof be))throw new Error("session must be a XRSession");if(e.ended)throw new Error("InvalidStateError");if(t[Ae]&&!0!==t[he])throw new Error("InvalidStateError");const s=t.getParameter(t.FRAMEBUFFER_BINDING);this[ce]={context:t,config:r,framebuffer:s,session:e}}get context(){return this[ce].context}get antialias(){return this[ce].config.antialias}get ignoreDepthValues(){return!0}get framebuffer(){return this[ce].framebuffer}get framebufferWidth(){return this[ce].context.drawingBufferWidth}get framebufferHeight(){return this[ce].context.drawingBufferHeight}get _session(){return this[ce].session}getViewport(e){return e._getViewport(this)}static getNativeFramebufferScaleFactor(e){if(!e)throw new TypeError("getNativeFramebufferScaleFactor must be passed a session.");return e[we].ended?0:1}},XRSpace:L,XRReferenceSpace:Q,XRReferenceSpaceEvent:class extends Event{constructor(e,t){super(e,t),this[Me]={referenceSpace:t.referenceSpace,transform:t.transform||null}}get referenceSpace(){return this[Me].referenceSpace}get transform(){return this[Me].transform}},XRInputSource:Se,XRInputSourceEvent:pe,XRInputSourcesChangeEvent:ve,XRRenderState:le,XRRigidTransform:D,XRPose:j};const _e=e=>"function"!=typeof e.prototype.makeXRCompatible&&(e.prototype.makeXRCompatible=function(){return this[he]=!0,Promise.resolve()},!0),Fe=e=>{const t=e.prototype.getContext;e.prototype.getContext=function(e,i){const r=t.call(this,e,i);return r&&(r[Ae]=!0,i&&"xrCompatible"in i&&(r[he]=i.xrCompatible)),r}},Re=e=>!(!e.ImageBitmapRenderingContext||!e.createImageBitmap);var Te;const Be=e=>{e.style.display="block",e.style.position="absolute",e.style.width=e.style.height="1px",e.style.top=e.style.left="0px"};var Pe="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var Ce,De,Ie=(function(e,t){e.exports=function(){var e,t,i,r=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},s=function(){function e(e,t){for(var i=0;ie.TEXTURE31){console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit"),r.push(null,null);break}s||(s=e.getParameter(e.ACTIVE_TEXTURE)),e.activeTexture(o),r.push(e.getParameter(a),null);break;case e.ACTIVE_TEXTURE:s=e.getParameter(e.ACTIVE_TEXTURE),r.push(null);break;default:r.push(e.getParameter(a))}}i(e);for(var n=0;ne.TEXTURE31)break;e.activeTexture(o),e.bindTexture(e.TEXTURE_2D,l);break;case e.TEXTURE_BINDING_CUBE_MAP:var o=t[++n];if(oe.TEXTURE31)break;e.activeTexture(o),e.bindTexture(e.TEXTURE_CUBE_MAP,l);break;case e.VIEWPORT:e.viewport(l[0],l[1],l[2],l[3]);break;case e.BLEND:case e.CULL_FACE:case e.DEPTH_TEST:case e.SCISSOR_TEST:case e.STENCIL_TEST:l?e.enable(a):e.disable(a);break;default:console.log("No GL restore behavior for 0x"+a.toString(16))}s&&e.activeTexture(s)}}else i(e)},F=["attribute vec2 position;","attribute vec3 texCoord;","varying vec2 vTexCoord;","uniform vec4 viewportOffsetScale[2];","void main() {"," vec4 viewport = viewportOffsetScale[int(texCoord.z)];"," vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;"," gl_Position = vec4( position, 1.0, 1.0 );","}"].join("\n"),R=["precision mediump float;","uniform sampler2D diffuse;","varying vec2 vTexCoord;","void main() {"," gl_FragColor = texture2D(diffuse, vTexCoord);","}"].join("\n");function T(e,t,i,r){this.gl=e,this.cardboardUI=t,this.bufferScale=i,this.dirtySubmitFrameBindings=r,this.ctxAttribs=e.getContextAttributes(),this.meshWidth=20,this.meshHeight=20,this.bufferWidth=e.drawingBufferWidth,this.bufferHeight=e.drawingBufferHeight,this.realBindFramebuffer=e.bindFramebuffer,this.realEnable=e.enable,this.realDisable=e.disable,this.realColorMask=e.colorMask,this.realClearColor=e.clearColor,this.realViewport=e.viewport,o()||(this.realCanvasWidth=Object.getOwnPropertyDescriptor(e.canvas.__proto__,"width"),this.realCanvasHeight=Object.getOwnPropertyDescriptor(e.canvas.__proto__,"height")),this.isPatched=!1,this.lastBoundFramebuffer=null,this.cullFace=!1,this.depthTest=!1,this.blend=!1,this.scissorTest=!1,this.stencilTest=!1,this.viewport=[0,0,0,0],this.colorMask=[!0,!0,!0,!0],this.clearColor=[0,0,0,0],this.attribs={position:0,texCoord:1},this.program=g(e,F,R,this.attribs),this.uniforms=v(e,this.program),this.viewportOffsetScale=new Float32Array(8),this.setTextureBounds(),this.vertexBuffer=e.createBuffer(),this.indexBuffer=e.createBuffer(),this.indexCount=0,this.renderTarget=e.createTexture(),this.framebuffer=e.createFramebuffer(),this.depthStencilBuffer=null,this.depthBuffer=null,this.stencilBuffer=null,this.ctxAttribs.depth&&this.ctxAttribs.stencil?this.depthStencilBuffer=e.createRenderbuffer():this.ctxAttribs.depth?this.depthBuffer=e.createRenderbuffer():this.ctxAttribs.stencil&&(this.stencilBuffer=e.createRenderbuffer()),this.patch(),this.onResize()}T.prototype.destroy=function(){var e=this.gl;this.unpatch(),e.deleteProgram(this.program),e.deleteBuffer(this.vertexBuffer),e.deleteBuffer(this.indexBuffer),e.deleteTexture(this.renderTarget),e.deleteFramebuffer(this.framebuffer),this.depthStencilBuffer&&e.deleteRenderbuffer(this.depthStencilBuffer),this.depthBuffer&&e.deleteRenderbuffer(this.depthBuffer),this.stencilBuffer&&e.deleteRenderbuffer(this.stencilBuffer),this.cardboardUI&&this.cardboardUI.destroy()},T.prototype.onResize=function(){var e=this.gl,t=this,i=[e.RENDERBUFFER_BINDING,e.TEXTURE_BINDING_2D,e.TEXTURE0];_(e,i,function(e){t.realBindFramebuffer.call(e,e.FRAMEBUFFER,null),t.scissorTest&&t.realDisable.call(e,e.SCISSOR_TEST),t.realColorMask.call(e,!0,!0,!0,!0),t.realViewport.call(e,0,0,e.drawingBufferWidth,e.drawingBufferHeight),t.realClearColor.call(e,0,0,0,1),e.clear(e.COLOR_BUFFER_BIT),t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.framebuffer),e.bindTexture(e.TEXTURE_2D,t.renderTarget),e.texImage2D(e.TEXTURE_2D,0,t.ctxAttribs.alpha?e.RGBA:e.RGB,t.bufferWidth,t.bufferHeight,0,t.ctxAttribs.alpha?e.RGBA:e.RGB,e.UNSIGNED_BYTE,null),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t.renderTarget,0),t.ctxAttribs.depth&&t.ctxAttribs.stencil?(e.bindRenderbuffer(e.RENDERBUFFER,t.depthStencilBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.DEPTH_STENCIL,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.DEPTH_STENCIL_ATTACHMENT,e.RENDERBUFFER,t.depthStencilBuffer)):t.ctxAttribs.depth?(e.bindRenderbuffer(e.RENDERBUFFER,t.depthBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.DEPTH_COMPONENT16,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.DEPTH_ATTACHMENT,e.RENDERBUFFER,t.depthBuffer)):t.ctxAttribs.stencil&&(e.bindRenderbuffer(e.RENDERBUFFER,t.stencilBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.STENCIL_INDEX8,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.STENCIL_ATTACHMENT,e.RENDERBUFFER,t.stencilBuffer)),!e.checkFramebufferStatus(e.FRAMEBUFFER)===e.FRAMEBUFFER_COMPLETE&&console.error("Framebuffer incomplete!"),t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.lastBoundFramebuffer),t.scissorTest&&t.realEnable.call(e,e.SCISSOR_TEST),t.realColorMask.apply(e,t.colorMask),t.realViewport.apply(e,t.viewport),t.realClearColor.apply(e,t.clearColor)}),this.cardboardUI&&this.cardboardUI.onResize()},T.prototype.patch=function(){if(!this.isPatched){var e=this,t=this.gl.canvas,i=this.gl;o()||(t.width=p()*this.bufferScale,t.height=f()*this.bufferScale,Object.defineProperty(t,"width",{configurable:!0,enumerable:!0,get:function(){return e.bufferWidth},set:function(i){e.bufferWidth=i,e.realCanvasWidth.set.call(t,i),e.onResize()}}),Object.defineProperty(t,"height",{configurable:!0,enumerable:!0,get:function(){return e.bufferHeight},set:function(i){e.bufferHeight=i,e.realCanvasHeight.set.call(t,i),e.onResize()}})),this.lastBoundFramebuffer=i.getParameter(i.FRAMEBUFFER_BINDING),null==this.lastBoundFramebuffer&&(this.lastBoundFramebuffer=this.framebuffer,this.gl.bindFramebuffer(i.FRAMEBUFFER,this.framebuffer)),this.gl.bindFramebuffer=function(t,r){e.lastBoundFramebuffer=r||e.framebuffer,e.realBindFramebuffer.call(i,t,e.lastBoundFramebuffer)},this.cullFace=i.getParameter(i.CULL_FACE),this.depthTest=i.getParameter(i.DEPTH_TEST),this.blend=i.getParameter(i.BLEND),this.scissorTest=i.getParameter(i.SCISSOR_TEST),this.stencilTest=i.getParameter(i.STENCIL_TEST),i.enable=function(t){switch(t){case i.CULL_FACE:e.cullFace=!0;break;case i.DEPTH_TEST:e.depthTest=!0;break;case i.BLEND:e.blend=!0;break;case i.SCISSOR_TEST:e.scissorTest=!0;break;case i.STENCIL_TEST:e.stencilTest=!0}e.realEnable.call(i,t)},i.disable=function(t){switch(t){case i.CULL_FACE:e.cullFace=!1;break;case i.DEPTH_TEST:e.depthTest=!1;break;case i.BLEND:e.blend=!1;break;case i.SCISSOR_TEST:e.scissorTest=!1;break;case i.STENCIL_TEST:e.stencilTest=!1}e.realDisable.call(i,t)},this.colorMask=i.getParameter(i.COLOR_WRITEMASK),i.colorMask=function(t,r,s,n){e.colorMask[0]=t,e.colorMask[1]=r,e.colorMask[2]=s,e.colorMask[3]=n,e.realColorMask.call(i,t,r,s,n)},this.clearColor=i.getParameter(i.COLOR_CLEAR_VALUE),i.clearColor=function(t,r,s,n){e.clearColor[0]=t,e.clearColor[1]=r,e.clearColor[2]=s,e.clearColor[3]=n,e.realClearColor.call(i,t,r,s,n)},this.viewport=i.getParameter(i.VIEWPORT),i.viewport=function(t,r,s,n){e.viewport[0]=t,e.viewport[1]=r,e.viewport[2]=s,e.viewport[3]=n,e.realViewport.call(i,t,r,s,n)},this.isPatched=!0,b(t)}},T.prototype.unpatch=function(){if(this.isPatched){var e=this.gl,t=this.gl.canvas;o()||(Object.defineProperty(t,"width",this.realCanvasWidth),Object.defineProperty(t,"height",this.realCanvasHeight)),t.width=this.bufferWidth,t.height=this.bufferHeight,e.bindFramebuffer=this.realBindFramebuffer,e.enable=this.realEnable,e.disable=this.realDisable,e.colorMask=this.realColorMask,e.clearColor=this.realClearColor,e.viewport=this.realViewport,this.lastBoundFramebuffer==this.framebuffer&&e.bindFramebuffer(e.FRAMEBUFFER,null),this.isPatched=!1,setTimeout(function(){b(t)},1)}},T.prototype.setTextureBounds=function(e,t){e||(e=[0,0,.5,1]),t||(t=[.5,0,.5,1]),this.viewportOffsetScale[0]=e[0],this.viewportOffsetScale[1]=e[1],this.viewportOffsetScale[2]=e[2],this.viewportOffsetScale[3]=e[3],this.viewportOffsetScale[4]=t[0],this.viewportOffsetScale[5]=t[1],this.viewportOffsetScale[6]=t[2],this.viewportOffsetScale[7]=t[3]},T.prototype.submitFrame=function(){var e=this.gl,t=this,i=[];if(this.dirtySubmitFrameBindings||i.push(e.CURRENT_PROGRAM,e.ARRAY_BUFFER_BINDING,e.ELEMENT_ARRAY_BUFFER_BINDING,e.TEXTURE_BINDING_2D,e.TEXTURE0),_(e,i,function(e){t.realBindFramebuffer.call(e,e.FRAMEBUFFER,null),t.cullFace&&t.realDisable.call(e,e.CULL_FACE),t.depthTest&&t.realDisable.call(e,e.DEPTH_TEST),t.blend&&t.realDisable.call(e,e.BLEND),t.scissorTest&&t.realDisable.call(e,e.SCISSOR_TEST),t.stencilTest&&t.realDisable.call(e,e.STENCIL_TEST),t.realColorMask.call(e,!0,!0,!0,!0),t.realViewport.call(e,0,0,e.drawingBufferWidth,e.drawingBufferHeight),(t.ctxAttribs.alpha||o())&&(t.realClearColor.call(e,0,0,0,1),e.clear(e.COLOR_BUFFER_BIT)),e.useProgram(t.program),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,t.indexBuffer),e.bindBuffer(e.ARRAY_BUFFER,t.vertexBuffer),e.enableVertexAttribArray(t.attribs.position),e.enableVertexAttribArray(t.attribs.texCoord),e.vertexAttribPointer(t.attribs.position,2,e.FLOAT,!1,20,0),e.vertexAttribPointer(t.attribs.texCoord,3,e.FLOAT,!1,20,8),e.activeTexture(e.TEXTURE0),e.uniform1i(t.uniforms.diffuse,0),e.bindTexture(e.TEXTURE_2D,t.renderTarget),e.uniform4fv(t.uniforms.viewportOffsetScale,t.viewportOffsetScale),e.drawElements(e.TRIANGLES,t.indexCount,e.UNSIGNED_SHORT,0),t.cardboardUI&&t.cardboardUI.renderNoState(),t.realBindFramebuffer.call(t.gl,e.FRAMEBUFFER,t.framebuffer),t.ctxAttribs.preserveDrawingBuffer||(t.realClearColor.call(e,0,0,0,0),e.clear(e.COLOR_BUFFER_BIT)),t.dirtySubmitFrameBindings||t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.lastBoundFramebuffer),t.cullFace&&t.realEnable.call(e,e.CULL_FACE),t.depthTest&&t.realEnable.call(e,e.DEPTH_TEST),t.blend&&t.realEnable.call(e,e.BLEND),t.scissorTest&&t.realEnable.call(e,e.SCISSOR_TEST),t.stencilTest&&t.realEnable.call(e,e.STENCIL_TEST),t.realColorMask.apply(e,t.colorMask),t.realViewport.apply(e,t.viewport),!t.ctxAttribs.alpha&&t.ctxAttribs.preserveDrawingBuffer||t.realClearColor.apply(e,t.clearColor)}),o()){var r=e.canvas;r.width==t.bufferWidth&&r.height==t.bufferHeight||(t.bufferWidth=r.width,t.bufferHeight=r.height,t.onResize())}},T.prototype.updateDeviceInfo=function(e){var t=this.gl,i=this,r=[t.ARRAY_BUFFER_BINDING,t.ELEMENT_ARRAY_BUFFER_BINDING];_(t,r,function(t){var r=i.computeMeshVertices_(i.meshWidth,i.meshHeight,e);if(t.bindBuffer(t.ARRAY_BUFFER,i.vertexBuffer),t.bufferData(t.ARRAY_BUFFER,r,t.STATIC_DRAW),!i.indexCount){var s=i.computeMeshIndices_(i.meshWidth,i.meshHeight);t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,i.indexBuffer),t.bufferData(t.ELEMENT_ARRAY_BUFFER,s,t.STATIC_DRAW),i.indexCount=s.length}})},T.prototype.computeMeshVertices_=function(e,t,i){for(var r=new Float32Array(2*e*t*5),s=i.getLeftEyeVisibleTanAngles(),n=i.getLeftEyeNoLensTanAngles(),o=i.getLeftEyeVisibleScreenRect(n),l=0,A=0;A<2;A++){for(var h=0;hs-42&&r.clientXi.clientHeight-42?e(r):r.clientX<42&&r.clientY<42&&t(r)},i.addEventListener("click",this.listener,!1)},I.prototype.onResize=function(){var e=this.gl,t=this,i=[e.ARRAY_BUFFER_BINDING];_(e,i,function(e){var i=[],r=e.drawingBufferWidth/2,s=Math.max(screen.width,screen.height)*window.devicePixelRatio,n=e.drawingBufferWidth/s,a=n*window.devicePixelRatio,o=4*a/2,l=42*a,A=28*a/2,h=14*a;function c(e,t){var s=(90-e)*C,n=Math.cos(s),a=Math.sin(s);i.push(D*n*A+r,D*a*A+A),i.push(t*n*A+r,t*a*A+A)}i.push(r-o,l),i.push(r-o,e.drawingBufferHeight),i.push(r+o,l),i.push(r+o,e.drawingBufferHeight),t.gearOffset=i.length/2;for(var d=0;d<=6;d++){var u=60*d;c(u,1),c(u+12,1),c(u+20,.75),c(u+40,.75),c(u+48,1)}function p(t,r){i.push(h+t,e.drawingBufferHeight-h-r)}t.gearVertexCount=i.length/2-t.gearOffset,t.arrowOffset=i.length/2;var f=o/Math.sin(45*C);p(0,A),p(A,0),p(A+f,f),p(f,A+f),p(f,A-f),p(0,A),p(A,2*A),p(A+f,2*A-f),p(f,A-f),p(0,A),p(f,A-o),p(28*a,A-o),p(f,A+o),p(28*a,A+o),t.arrowVertexCount=i.length/2-t.arrowOffset,e.bindBuffer(e.ARRAY_BUFFER,t.vertexBuffer),e.bufferData(e.ARRAY_BUFFER,new Float32Array(i),e.STATIC_DRAW)})},I.prototype.render=function(){var e=this.gl,t=this,i=[e.CULL_FACE,e.DEPTH_TEST,e.BLEND,e.SCISSOR_TEST,e.STENCIL_TEST,e.COLOR_WRITEMASK,e.VIEWPORT,e.CURRENT_PROGRAM,e.ARRAY_BUFFER_BINDING];_(e,i,function(e){e.disable(e.CULL_FACE),e.disable(e.DEPTH_TEST),e.disable(e.BLEND),e.disable(e.SCISSOR_TEST),e.disable(e.STENCIL_TEST),e.colorMask(!0,!0,!0,!0),e.viewport(0,0,e.drawingBufferWidth,e.drawingBufferHeight),t.renderNoState()})},I.prototype.renderNoState=function(){var e,t,i,r,s,n,a,o,l,A,h=this.gl;h.useProgram(this.program),h.bindBuffer(h.ARRAY_BUFFER,this.vertexBuffer),h.enableVertexAttribArray(this.attribs.position),h.vertexAttribPointer(this.attribs.position,2,h.FLOAT,!1,8,0),h.uniform4f(this.uniforms.color,1,1,1,1),e=this.projMat,t=0,i=h.drawingBufferWidth,r=0,s=h.drawingBufferHeight,o=1/(t-i),l=1/(r-s),A=1/((n=.1)-(a=1024)),e[0]=-2*o,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=-2*l,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=2*A,e[11]=0,e[12]=(t+i)*o,e[13]=(s+r)*l,e[14]=(a+n)*A,e[15]=1,h.uniformMatrix4fv(this.uniforms.projectionMat,!1,this.projMat),h.drawArrays(h.TRIANGLE_STRIP,0,4),h.drawArrays(h.TRIANGLE_STRIP,this.gearOffset,this.gearVertexCount),h.drawArrays(h.TRIANGLE_STRIP,this.arrowOffset,this.arrowVertexCount)},L.prototype.distortInverse=function(e){for(var t=0,i=1,r=e-this.distort(t);Math.abs(i-t)>1e-4;){var s=e-this.distort(i),n=i-s*((i-t)/(s-r));t=i,i=n,r=s}return i},L.prototype.distort=function(e){for(var t=e*e,i=0,r=0;r=1)return this.w=n,this.x=i,this.y=r,this.z=s,this;var o=Math.acos(a),l=Math.sqrt(1-a*a);if(Math.abs(l)<.001)return this.w=.5*(n+this.w),this.x=.5*(i+this.x),this.y=.5*(r+this.y),this.z=.5*(s+this.z),this;var A=Math.sin((1-t)*o)/l,h=Math.sin(t*o)/l;return this.w=n*A+this.w*h,this.x=i*A+this.x*h,this.y=r*A+this.y*h,this.z=s*A+this.z*h,this},setFromUnitVectors:function(e,t){return void 0===Q&&(Q=new G),(k=e.dot(t)+1)<1e-6?(k=0,Math.abs(e.x)>Math.abs(e.z)?Q.set(-e.y,e.x,0):Q.set(0,-e.z,e.y)):Q.crossVectors(e,t),this.x=Q.x,this.y=Q.y,this.z=Q.z,this.w=k,this.normalize(),this}};var V=new U({widthMeters:.11,heightMeters:.062,bevelMeters:.004}),H=new U({widthMeters:.1038,heightMeters:.0584,bevelMeters:.004}),X={CardboardV1:new j({id:"CardboardV1",label:"Cardboard I/O 2014",fov:40,interLensDistance:.06,baselineLensDistance:.035,screenLensDistance:.042,distortionCoefficients:[.441,.156],inverseCoefficients:[-.4410035,.42756155,-.4804439,.5460139,-.58821183,.5733938,-.48303202,.33299083,-.17573841,.0651772,-.01488963,.001559834]}),CardboardV2:new j({id:"CardboardV2",label:"Cardboard I/O 2015",fov:60,interLensDistance:.064,baselineLensDistance:.035,screenLensDistance:.039,distortionCoefficients:[.34,.55],inverseCoefficients:[-.33836704,-.18162185,.862655,-1.2462051,1.0560602,-.58208317,.21609078,-.05444823,.009177956,-.0009904169,6183535e-11,-16981803e-13]})};function W(e,t){this.viewer=X.CardboardV2,this.updateDeviceParams(e),this.distortion=new L(this.viewer.distortionCoefficients);for(var i=0;i=200&&i.status<=299?(r.dpdb=JSON.parse(i.response),r.recalculateDeviceParams_()):console.error("Error loading online DPDB!")}),i.send()}}function Z(e){this.xdpi=e.xdpi,this.ydpi=e.ydpi,this.bevelMm=e.bevelMm}function J(e,t){this.set(e,t)}function K(e,t){this.kFilter=e,this.isDebug=t,this.currentAccelMeasurement=new J,this.currentGyroMeasurement=new J,this.previousGyroMeasurement=new J,o()?this.filterQ=new z(-1,0,0,1):this.filterQ=new z(1,0,0,1),this.previousFilterQ=new z,this.previousFilterQ.copy(this.filterQ),this.accelQ=new z,this.isOrientationInitialized=!1,this.estimatedGravity=new G,this.measuredGravity=new G,this.gyroIntegralQ=new z}function $(e,t){this.predictionTimeS=e,this.isDebug=t,this.previousQ=new z,this.previousTimestampS=null,this.deltaQ=new z,this.outQ=new z}function ee(e,t,i,r){this.yawOnly=i,this.accelerometer=new G,this.gyroscope=new G,this.filter=new K(e,r),this.posePredictor=new $(t,r),this.isFirefoxAndroid=A(),this.isIOS=o();var s=h();this.isDeviceMotionInRadians=!this.isIOS&&s&&s<66,this.isWithoutDeviceMotion=c(),this.filterToWorldQ=new z,o()?this.filterToWorldQ.setFromAxisAngle(new G(1,0,0),Math.PI/2):this.filterToWorldQ.setFromAxisAngle(new G(1,0,0),-Math.PI/2),this.inverseWorldToScreenQ=new z,this.worldToScreenQ=new z,this.originalPoseAdjustQ=new z,this.originalPoseAdjustQ.setFromAxisAngle(new G(0,0,1),-window.orientation*Math.PI/180),this.setScreenTransform_(),u()&&this.filterToWorldQ.multiply(this.inverseWorldToScreenQ),this.resetQ=new z,this.orientationOut_=new Float32Array(4),this.start()}Y.prototype.getDeviceParams=function(){return this.deviceParams},Y.prototype.recalculateDeviceParams_=function(){var e=this.calcDeviceParams_();e?(this.deviceParams=e,this.onDeviceParamsUpdated&&this.onDeviceParamsUpdated(this.deviceParams)):console.error("Failed to recalculate device parameters.")},Y.prototype.calcDeviceParams_=function(){var e=this.dpdb;if(!e)return console.error("DPDB not available."),null;if(1!=e.format)return console.error("DPDB has unexpected format version."),null;if(!e.devices||!e.devices.length)return console.error("DPDB does not have a devices section."),null;var t=navigator.userAgent||navigator.vendor||window.opera,i=p(),r=f();if(!e.devices)return console.error("DPDB has no devices section."),null;for(var s=0;s1)&&this.run_(),this.previousGyroMeasurement.copy(this.currentGyroMeasurement)},K.prototype.run_=function(){if(!this.isOrientationInitialized)return this.accelQ=this.accelToQuaternion_(this.currentAccelMeasurement.sample),this.previousFilterQ.copy(this.accelQ),void(this.isOrientationInitialized=!0);var e=this.currentGyroMeasurement.timestampS-this.previousGyroMeasurement.timestampS,t=this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample,e);this.gyroIntegralQ.multiply(t),this.filterQ.copy(this.previousFilterQ),this.filterQ.multiply(t);var i=new z;i.copy(this.filterQ),i.inverse(),this.estimatedGravity.set(0,0,-1),this.estimatedGravity.applyQuaternion(i),this.estimatedGravity.normalize(),this.measuredGravity.copy(this.currentAccelMeasurement.sample),this.measuredGravity.normalize();var r,s=new z;s.setFromUnitVectors(this.estimatedGravity,this.measuredGravity),s.inverse(),this.isDebug&&console.log("Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)",N*((r=s).w>1?(console.warn("getQuaternionAngle: w > 1"),0):2*Math.acos(r.w)),this.estimatedGravity.x.toFixed(1),this.estimatedGravity.y.toFixed(1),this.estimatedGravity.z.toFixed(1),this.measuredGravity.x.toFixed(1),this.measuredGravity.y.toFixed(1),this.measuredGravity.z.toFixed(1));var n=new z;n.copy(this.filterQ),n.multiply(s),this.filterQ.slerp(n,1-this.kFilter),this.previousFilterQ.copy(this.filterQ)},K.prototype.getOrientation=function(){return this.filterQ},K.prototype.accelToQuaternion_=function(e){var t=new G;t.copy(e),t.normalize();var i=new z;return i.setFromUnitVectors(new G(0,0,-1),t),i.inverse(),i},K.prototype.gyroToQuaternionDelta_=function(e,t){var i=new z,r=new G;return r.copy(e),r.normalize(),i.setFromAxisAngle(r,e.length()*t),i},$.prototype.getPrediction=function(e,t,i){if(!this.previousTimestampS)return this.previousQ.copy(e),this.previousTimestampS=i,e;var r=new G;r.copy(t),r.normalize();var s=t.length();if(s<20*O)return this.isDebug&&console.log("Moving slowly, at %s deg/s: no prediction",(N*s).toFixed(1)),this.outQ.copy(e),this.previousQ.copy(e),this.outQ;var n=s*this.predictionTimeS;return this.deltaQ.setFromAxisAngle(r,n),this.outQ.copy(this.previousQ),this.outQ.multiply(this.deltaQ),this.previousQ.copy(e),this.previousTimestampS=i,this.outQ},ee.prototype.getPosition=function(){return null},ee.prototype.getOrientation=function(){var e=void 0;if(this.isWithoutDeviceMotion&&this._deviceOrientationQ){this.deviceOrientationFixQ=this.deviceOrientationFixQ||(r=(new z).setFromAxisAngle(new G(0,0,-1),0),s=new z,-90===window.orientation?s.setFromAxisAngle(new G(0,1,0),Math.PI/-2):s.setFromAxisAngle(new G(0,1,0),Math.PI/2),r.multiply(s)),this.deviceOrientationFilterToWorldQ=this.deviceOrientationFilterToWorldQ||((i=new z).setFromAxisAngle(new G(1,0,0),-Math.PI/2),i),e=this._deviceOrientationQ;var t=new z;return t.copy(e),t.multiply(this.deviceOrientationFilterToWorldQ),t.multiply(this.resetQ),t.multiply(this.worldToScreenQ),t.multiplyQuaternions(this.deviceOrientationFixQ,t),this.yawOnly&&(t.x=0,t.z=0,t.normalize()),this.orientationOut_[0]=t.x,this.orientationOut_[1]=t.y,this.orientationOut_[2]=t.z,this.orientationOut_[3]=t.w,this.orientationOut_}var i,r,s,n=this.filter.getOrientation();e=this.posePredictor.getPrediction(n,this.gyroscope,this.previousTimestampS);var t=new z;return t.copy(this.filterToWorldQ),t.multiply(this.resetQ),t.multiply(e),t.multiply(this.worldToScreenQ),this.yawOnly&&(t.x=0,t.z=0,t.normalize()),this.orientationOut_[0]=t.x,this.orientationOut_[1]=t.y,this.orientationOut_[2]=t.z,this.orientationOut_[3]=t.w,this.orientationOut_},ee.prototype.resetPose=function(){this.resetQ.copy(this.filter.getOrientation()),this.resetQ.x=0,this.resetQ.y=0,this.resetQ.z*=-1,this.resetQ.normalize(),u()&&this.resetQ.multiply(this.inverseWorldToScreenQ),this.resetQ.multiply(this.originalPoseAdjustQ)},ee.prototype.onDeviceOrientation_=function(e){this._deviceOrientationQ=this._deviceOrientationQ||new z;var t=e.alpha,i=e.beta,r=e.gamma;t=(t||0)*Math.PI/180,i=(i||0)*Math.PI/180,r=(r||0)*Math.PI/180,this._deviceOrientationQ.setFromEulerYXZ(i,t,-r)},ee.prototype.onDeviceMotion_=function(e){this.updateDeviceMotion_(e)},ee.prototype.updateDeviceMotion_=function(e){var t=e.accelerationIncludingGravity,i=e.rotationRate,r=e.timeStamp/1e3,s=r-this.previousTimestampS;return s<0?(M("fusion-pose-sensor:invalid:non-monotonic","Invalid timestamps detected: non-monotonic timestamp from devicemotion"),void(this.previousTimestampS=r)):s<=.001||s>1?(M("fusion-pose-sensor:invalid:outside-threshold","Invalid timestamps detected: Timestamp from devicemotion outside expected range."),void(this.previousTimestampS=r)):(this.accelerometer.set(-t.x,-t.y,-t.z),d()?this.gyroscope.set(-i.beta,i.alpha,i.gamma):this.gyroscope.set(i.alpha,i.beta,i.gamma),this.isDeviceMotionInRadians||this.gyroscope.multiplyScalar(Math.PI/180),this.filter.addAccelMeasurement(this.accelerometer,r),this.filter.addGyroMeasurement(this.gyroscope,r),void(this.previousTimestampS=r))},ee.prototype.onOrientationChange_=function(e){this.setScreenTransform_()},ee.prototype.onMessage_=function(e){var t=e.data;if(t&&t.type){var i=t.type.toLowerCase();"devicemotion"===i&&this.updateDeviceMotion_(t.deviceMotionEvent)}},ee.prototype.setScreenTransform_=function(){switch(this.worldToScreenQ.set(0,0,0,1),window.orientation){case 0:break;case 90:this.worldToScreenQ.setFromAxisAngle(new G(0,0,1),-Math.PI/2);break;case-90:this.worldToScreenQ.setFromAxisAngle(new G(0,0,1),Math.PI/2)}this.inverseWorldToScreenQ.copy(this.worldToScreenQ),this.inverseWorldToScreenQ.inverse()},ee.prototype.start=function(){var e,t,i;this.onDeviceMotionCallback_=this.onDeviceMotion_.bind(this),this.onOrientationChangeCallback_=this.onOrientationChange_.bind(this),this.onMessageCallback_=this.onMessage_.bind(this),this.onDeviceOrientationCallback_=this.onDeviceOrientation_.bind(this),o()&&(e=window.self!==window.top,t=S(document.referrer),i=S(window.location.href),e&&t!==i)&&window.addEventListener("message",this.onMessageCallback_),window.addEventListener("orientationchange",this.onOrientationChangeCallback_),this.isWithoutDeviceMotion?window.addEventListener("deviceorientation",this.onDeviceOrientationCallback_):window.addEventListener("devicemotion",this.onDeviceMotionCallback_)},ee.prototype.stop=function(){window.removeEventListener("devicemotion",this.onDeviceMotionCallback_),window.removeEventListener("deviceorientation",this.onDeviceOrientationCallback_),window.removeEventListener("orientationchange",this.onOrientationChangeCallback_),window.removeEventListener("message",this.onMessageCallback_)};var te=new G(1,0,0),ie=new G(0,0,1),re=new z;re.setFromAxisAngle(te,-Math.PI/2),re.multiply((new z).setFromAxisAngle(ie,Math.PI/2));var se=function(){function e(t){r(this,e),this.config=t,this.sensor=null,this.fusionSensor=null,this._out=new Float32Array(4),this.api=null,this.errors=[],this._sensorQ=new z,this._outQ=new z,this._onSensorRead=this._onSensorRead.bind(this),this._onSensorError=this._onSensorError.bind(this),this.init()}return s(e,[{key:"init",value:function(){var e=null;try{(e=new RelativeOrientationSensor({frequency:60,referenceFrame:"screen"})).addEventListener("error",this._onSensorError)}catch(e){this.errors.push(e),"SecurityError"===e.name?(console.error("Cannot construct sensors due to the Feature Policy"),console.warn('Attempting to fall back using "devicemotion"; however this will fail in the future without correct permissions.'),this.useDeviceMotion()):"ReferenceError"===e.name?this.useDeviceMotion():console.error(e)}e&&(this.api="sensor",this.sensor=e,this.sensor.addEventListener("reading",this._onSensorRead),this.sensor.start())}},{key:"useDeviceMotion",value:function(){this.api="devicemotion",this.fusionSensor=new ee(this.config.K_FILTER,this.config.PREDICTION_TIME_S,this.config.YAW_ONLY,this.config.DEBUG),this.sensor&&(this.sensor.removeEventListener("reading",this._onSensorRead),this.sensor.removeEventListener("error",this._onSensorError),this.sensor=null)}},{key:"getOrientation",value:function(){if(this.fusionSensor)return this.fusionSensor.getOrientation();if(!this.sensor||!this.sensor.quaternion)return this._out[0]=this._out[1]=this._out[2]=0,this._out[3]=1,this._out;var e=this.sensor.quaternion;this._sensorQ.set(e[0],e[1],e[2],e[3]);var t=this._outQ;return t.copy(re),t.multiply(this._sensorQ),this.config.YAW_ONLY&&(t.x=t.z=0,t.normalize()),this._out[0]=t.x,this._out[1]=t.y,this._out[2]=t.z,this._out[3]=t.w,this._out}},{key:"_onSensorError",value:function(e){this.errors.push(e.error),"NotAllowedError"===e.error.name?console.error("Permission to access sensor was denied"):"NotReadableError"===e.error.name?console.error("Sensor could not be read"):console.error(e.error),this.useDeviceMotion()}},{key:"_onSensorRead",value:function(){}}]),e}();function ne(){this.loadIcon_();var e=document.createElement("div"),t=e.style;t.position="fixed",t.top=0,t.right=0,t.bottom=0,t.left=0,t.backgroundColor="gray",t.fontFamily="sans-serif",t.zIndex=1e6;var i=document.createElement("img");i.src=this.icon;var t=i.style;t.marginLeft="25%",t.marginTop="25%",t.width="50%",e.appendChild(i);var r=document.createElement("div"),t=r.style;t.textAlign="center",t.fontSize="16px",t.lineHeight="24px",t.margin="24px 25%",t.width="50%",r.innerHTML="Place your phone into your Cardboard viewer.",e.appendChild(r);var s=document.createElement("div"),t=s.style;t.backgroundColor="#CFD8DC",t.position="fixed",t.bottom=0,t.width="100%",t.height="48px",t.padding="14px 24px",t.boxSizing="border-box",t.color="#656A6B",e.appendChild(s);var n=document.createElement("div");n.style.float="left",n.innerHTML="No Cardboard viewer?";var a=document.createElement("a");a.href="https://www.google.com/get/cardboard/get-cardboard/",a.innerHTML="get one",a.target="_blank";var t=a.style;t.float="right",t.fontWeight=600,t.textTransform="uppercase",t.borderLeft="1px solid gray",t.paddingLeft="24px",t.textDecoration="none",t.color="#656A6B",s.appendChild(n),s.appendChild(a),this.overlay=e,this.text=r,this.hide()}ne.prototype.show=function(e){e||this.overlay.parentElement?e&&(this.overlay.parentElement&&this.overlay.parentElement!=e&&this.overlay.parentElement.removeChild(this.overlay),e.appendChild(this.overlay)):document.body.appendChild(this.overlay),this.overlay.style.display="block";var t=this.overlay.querySelector("img"),i=t.style;u()?(i.width="20%",i.marginLeft="40%",i.marginTop="3%"):(i.width="50%",i.marginLeft="25%",i.marginTop="25%")},ne.prototype.hide=function(){this.overlay.style.display="none"},ne.prototype.showTemporarily=function(e,t){this.show(t),this.timer=setTimeout(this.hide.bind(this),e)},ne.prototype.disableShowTemporarily=function(){clearTimeout(this.timer)},ne.prototype.update=function(){this.disableShowTemporarily(),!u()&&w()?this.show():this.hide()},ne.prototype.loadIcon_=function(){this.icon="data:image/svg+xml,"+encodeURIComponent("")};var ae="CardboardV1",oe="WEBVR_CARDBOARD_VIEWER";function le(e){try{this.selectedKey=localStorage.getItem(oe)}catch(e){console.error("Failed to load viewer profile: %s",e)}this.selectedKey||(this.selectedKey=e||ae),this.dialog=this.createDialog_(W.Viewers),this.root=null,this.onChangeCallbacks_=[]}le.prototype.show=function(e){this.root=e,e.appendChild(this.dialog);var t=this.dialog.querySelector("#"+this.selectedKey);t.checked=!0,this.dialog.style.display="block"},le.prototype.hide=function(){this.root&&this.root.contains(this.dialog)&&this.root.removeChild(this.dialog),this.dialog.style.display="none"},le.prototype.getCurrentViewer=function(){return W.Viewers[this.selectedKey]},le.prototype.getSelectedKey_=function(){var e=this.dialog.querySelector("input[name=field]:checked");return e?e.id:null},le.prototype.onChange=function(e){this.onChangeCallbacks_.push(e)},le.prototype.fireOnChange_=function(e){for(var t=0;t.5&&(this.noSleepVideo.currentTime=Math.random())}.bind(this)))}return r(e,[{key:"enable",value:function(){n?(this.disable(),this.noSleepTimer=window.setInterval(function(){window.location.href="/",window.setTimeout(window.stop,0)},15e3)):this.noSleepVideo.play()}},{key:"disable",value:function(){n?this.noSleepTimer&&(window.clearInterval(this.noSleepTimer),this.noSleepTimer=null):this.noSleepVideo.pause()}}]),e}();e.exports=a},function(e,t,i){e.exports="data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA="}])},e.exports=i()}(he={exports:{}},he.exports),(Ae=he.exports)&&Ae.__esModule&&Object.prototype.hasOwnProperty.call(Ae,"default")?Ae.default:Ae),de=1e3,ue=[0,0,.5,1],pe=[.5,0,.5,1],fe=window.requestAnimationFrame,me=window.cancelAnimationFrame;function ge(e){Object.defineProperties(this,{hasPosition:{writable:!1,enumerable:!0,value:e.hasPosition},hasExternalDisplay:{writable:!1,enumerable:!0,value:e.hasExternalDisplay},canPresent:{writable:!1,enumerable:!0,value:e.canPresent},maxLayers:{writable:!1,enumerable:!0,value:e.maxLayers},hasOrientation:{enumerable:!0,get:function(){return x("VRDisplayCapabilities.prototype.hasOrientation","VRDisplay.prototype.getFrameData"),e.hasOrientation}}})}function ve(e){var t=!("wakelock"in(e=e||{}))||e.wakelock;this.isPolyfilled=!0,this.displayId=de++,this.displayName="",this.depthNear=.01,this.depthFar=1e4,this.isPresenting=!1,Object.defineProperty(this,"isConnected",{get:function(){return x("VRDisplay.prototype.isConnected","VRDisplayCapabilities.prototype.hasExternalDisplay"),!1}}),this.capabilities=new ge({hasPosition:!1,hasOrientation:!1,hasExternalDisplay:!1,canPresent:!1,maxLayers:1}),this.stageParameters=null,this.waitingForPresent_=!1,this.layer_=null,this.originalParent_=null,this.fullscreenElement_=null,this.fullscreenWrapper_=null,this.fullscreenElementCachedStyle_=null,this.fullscreenEventTarget_=null,this.fullscreenChangeHandler_=null,this.fullscreenErrorHandler_=null,t&&w()&&(this.wakelock_=new ce)}ve.prototype.getFrameData=function(e){return E(e,this._getPose(),this)},ve.prototype.getPose=function(){return x("VRDisplay.prototype.getPose","VRDisplay.prototype.getFrameData"),this._getPose()},ve.prototype.resetPose=function(){return x("VRDisplay.prototype.resetPose"),this._resetPose()},ve.prototype.getImmediatePose=function(){return x("VRDisplay.prototype.getImmediatePose","VRDisplay.prototype.getFrameData"),this._getPose()},ve.prototype.requestAnimationFrame=function(e){return fe(e)},ve.prototype.cancelAnimationFrame=function(e){return me(e)},ve.prototype.wrapForFullscreen=function(e){if(o())return e;if(!this.fullscreenWrapper_){this.fullscreenWrapper_=document.createElement("div");var t=["height: "+Math.min(screen.height,screen.width)+"px !important","top: 0 !important","left: 0 !important","right: 0 !important","border: 0","margin: 0","padding: 0","z-index: 999999 !important","position: fixed"];this.fullscreenWrapper_.setAttribute("style",t.join("; ")+";"),this.fullscreenWrapper_.classList.add("webvr-polyfill-fullscreen-wrapper")}if(this.fullscreenElement_==e)return this.fullscreenWrapper_;if(this.fullscreenElement_&&(this.originalParent_?this.originalParent_.appendChild(this.fullscreenElement_):this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_)),this.fullscreenElement_=e,this.originalParent_=e.parentElement,this.originalParent_||document.body.appendChild(e),!this.fullscreenWrapper_.parentElement){var i=this.fullscreenElement_.parentElement;i.insertBefore(this.fullscreenWrapper_,this.fullscreenElement_),i.removeChild(this.fullscreenElement_)}this.fullscreenWrapper_.insertBefore(this.fullscreenElement_,this.fullscreenWrapper_.firstChild),this.fullscreenElementCachedStyle_=this.fullscreenElement_.getAttribute("style");var r=this;return function(){if(r.fullscreenElement_){var e=["position: absolute","top: 0","left: 0","width: "+Math.max(screen.width,screen.height)+"px","height: "+Math.min(screen.height,screen.width)+"px","border: 0","margin: 0","padding: 0"];r.fullscreenElement_.setAttribute("style",e.join("; ")+";")}}(),this.fullscreenWrapper_},ve.prototype.removeFullscreenWrapper=function(){if(this.fullscreenElement_){var e=this.fullscreenElement_;this.fullscreenElementCachedStyle_?e.setAttribute("style",this.fullscreenElementCachedStyle_):e.removeAttribute("style"),this.fullscreenElement_=null,this.fullscreenElementCachedStyle_=null;var t=this.fullscreenWrapper_.parentElement;return this.fullscreenWrapper_.removeChild(e),this.originalParent_===t?t.insertBefore(e,this.fullscreenWrapper_):this.originalParent_&&this.originalParent_.appendChild(e),t.removeChild(this.fullscreenWrapper_),e}},ve.prototype.requestPresent=function(e){var t=this.isPresenting,i=this;return e instanceof Array||(x("VRDisplay.prototype.requestPresent with non-array argument","an array of VRLayers as the first argument"),e=[e]),new Promise(function(r,s){if(i.capabilities.canPresent)if(0==e.length||e.length>i.capabilities.maxLayers)s(new Error("Invalid number of layers."));else{var n=e[0];if(n.source){var a=n.leftBounds||ue,A=n.rightBounds||pe;if(t){var h=i.layer_;h.source!==n.source&&(h.source=n.source);for(var c=0;c<4;c++)h.leftBounds[c]=a[c],h.rightBounds[c]=A[c];return i.wrapForFullscreen(i.layer_.source),i.updatePresent_(),void r()}if(i.layer_={predistorted:n.predistorted,source:n.source,leftBounds:a.slice(0),rightBounds:A.slice(0)},i.waitingForPresent_=!1,i.layer_&&i.layer_.source){var d=i.wrapForFullscreen(i.layer_.source);i.addFullscreenListeners_(d,function(){var e=document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement;i.isPresenting=d===e,i.isPresenting?(screen.orientation&&screen.orientation.lock&&screen.orientation.lock("landscape-primary").catch(function(e){console.error("screen.orientation.lock() failed due to",e.message)}),i.waitingForPresent_=!1,i.beginPresent_(),r()):(screen.orientation&&screen.orientation.unlock&&screen.orientation.unlock(),i.removeFullscreenWrapper(),i.disableWakeLock(),i.endPresent_(),i.removeFullscreenListeners_()),i.fireVRDisplayPresentChange_()},function(){i.waitingForPresent_&&(i.removeFullscreenWrapper(),i.removeFullscreenListeners_(),i.disableWakeLock(),i.waitingForPresent_=!1,i.isPresenting=!1,s(new Error("Unable to present.")))}),function(e){if(l())return!1;if(e.requestFullscreen)e.requestFullscreen();else if(e.webkitRequestFullscreen)e.webkitRequestFullscreen();else if(e.mozRequestFullScreen)e.mozRequestFullScreen();else{if(!e.msRequestFullscreen)return!1;e.msRequestFullscreen()}return!0}(d)?(i.enableWakeLock(),i.waitingForPresent_=!0):(o()||l())&&(i.enableWakeLock(),i.isPresenting=!0,i.beginPresent_(),i.fireVRDisplayPresentChange_(),r())}i.waitingForPresent_||o()||(m(),s(new Error("Unable to present.")))}else r()}else s(new Error("VRDisplay is not capable of presenting."))})},ve.prototype.exitPresent=function(){var e=this.isPresenting,t=this;return this.isPresenting=!1,this.layer_=null,this.disableWakeLock(),new Promise(function(i,r){e?(!m()&&o()&&(t.endPresent_(),t.fireVRDisplayPresentChange_()),l()&&(t.removeFullscreenWrapper(),t.removeFullscreenListeners_(),t.endPresent_(),t.fireVRDisplayPresentChange_()),i()):r(new Error("Was not presenting to VRDisplay."))})},ve.prototype.getLayers=function(){return this.layer_?[this.layer_]:[]},ve.prototype.fireVRDisplayPresentChange_=function(){var e=new CustomEvent("vrdisplaypresentchange",{detail:{display:this}});window.dispatchEvent(e)},ve.prototype.fireVRDisplayConnect_=function(){var e=new CustomEvent("vrdisplayconnect",{detail:{display:this}});window.dispatchEvent(e)},ve.prototype.addFullscreenListeners_=function(e,t,i){this.removeFullscreenListeners_(),this.fullscreenEventTarget_=e,this.fullscreenChangeHandler_=t,this.fullscreenErrorHandler_=i,t&&(document.fullscreenEnabled?e.addEventListener("fullscreenchange",t,!1):document.webkitFullscreenEnabled?e.addEventListener("webkitfullscreenchange",t,!1):document.mozFullScreenEnabled?document.addEventListener("mozfullscreenchange",t,!1):document.msFullscreenEnabled&&e.addEventListener("msfullscreenchange",t,!1)),i&&(document.fullscreenEnabled?e.addEventListener("fullscreenerror",i,!1):document.webkitFullscreenEnabled?e.addEventListener("webkitfullscreenerror",i,!1):document.mozFullScreenEnabled?document.addEventListener("mozfullscreenerror",i,!1):document.msFullscreenEnabled&&e.addEventListener("msfullscreenerror",i,!1))},ve.prototype.removeFullscreenListeners_=function(){if(this.fullscreenEventTarget_){var e=this.fullscreenEventTarget_;if(this.fullscreenChangeHandler_){var t=this.fullscreenChangeHandler_;e.removeEventListener("fullscreenchange",t,!1),e.removeEventListener("webkitfullscreenchange",t,!1),document.removeEventListener("mozfullscreenchange",t,!1),e.removeEventListener("msfullscreenchange",t,!1)}if(this.fullscreenErrorHandler_){var i=this.fullscreenErrorHandler_;e.removeEventListener("fullscreenerror",i,!1),e.removeEventListener("webkitfullscreenerror",i,!1),document.removeEventListener("mozfullscreenerror",i,!1),e.removeEventListener("msfullscreenerror",i,!1)}this.fullscreenEventTarget_=null,this.fullscreenChangeHandler_=null,this.fullscreenErrorHandler_=null}},ve.prototype.enableWakeLock=function(){this.wakelock_&&this.wakelock_.enable()},ve.prototype.disableWakeLock=function(){this.wakelock_&&this.wakelock_.disable()},ve.prototype.beginPresent_=function(){},ve.prototype.endPresent_=function(){},ve.prototype.submitFrame=function(e){},ve.prototype.getEyeParameters=function(e){return null};var we={ADDITIONAL_VIEWERS:[],DEFAULT_VIEWER:"",MOBILE_WAKE_LOCK:!0,DEBUG:!1,DPDB_URL:"https://dpdb.webvr.rocks/dpdb.json",K_FILTER:.98,PREDICTION_TIME_S:.04,CARDBOARD_UI_DISABLED:!1,ROTATE_INSTRUCTIONS_DISABLED:!1,YAW_ONLY:!1,BUFFER_SCALE:.5,DIRTY_SUBMIT_FRAME_BINDINGS:!1},ye={LEFT:"left",RIGHT:"right"};function be(e){var t=y({},we);e=y(t,e||{}),ve.call(this,{wakelock:e.MOBILE_WAKE_LOCK}),this.config=e,this.displayName="Cardboard VRDisplay",this.capabilities=new ge({hasPosition:!1,hasOrientation:!0,hasExternalDisplay:!1,canPresent:!0,maxLayers:1}),this.stageParameters=null,this.bufferScale_=this.config.BUFFER_SCALE,this.poseSensor_=new se(this.config),this.distorter_=null,this.cardboardUI_=null,this.dpdb_=new Y(this.config.DPDB_URL,this.onDeviceParamsUpdated_.bind(this)),this.deviceInfo_=new W(this.dpdb_.getDeviceParams(),e.ADDITIONAL_VIEWERS),this.viewerSelector_=new le(e.DEFAULT_VIEWER),this.viewerSelector_.onChange(this.onViewerChanged_.bind(this)),this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer()),this.config.ROTATE_INSTRUCTIONS_DISABLED||(this.rotateInstructions_=new ne),o()&&window.addEventListener("resize",this.onResize_.bind(this))}return be.prototype=Object.create(ve.prototype),be.prototype._getPose=function(){return{position:null,orientation:this.poseSensor_.getOrientation(),linearVelocity:null,linearAcceleration:null,angularVelocity:null,angularAcceleration:null}},be.prototype._resetPose=function(){this.poseSensor_.resetPose&&this.poseSensor_.resetPose()},be.prototype._getFieldOfView=function(e){var t;if(e==ye.LEFT)t=this.deviceInfo_.getFieldOfViewLeftEye();else{if(e!=ye.RIGHT)return console.error("Invalid eye provided: %s",e),null;t=this.deviceInfo_.getFieldOfViewRightEye()}return t},be.prototype._getEyeOffset=function(e){var t;if(e==ye.LEFT)t=[.5*-this.deviceInfo_.viewer.interLensDistance,0,0];else{if(e!=ye.RIGHT)return console.error("Invalid eye provided: %s",e),null;t=[.5*this.deviceInfo_.viewer.interLensDistance,0,0]}return t},be.prototype.getEyeParameters=function(e){var t=this._getEyeOffset(e),i=this._getFieldOfView(e),r={offset:t,renderWidth:.5*this.deviceInfo_.device.width*this.bufferScale_,renderHeight:this.deviceInfo_.device.height*this.bufferScale_};return Object.defineProperty(r,"fieldOfView",{enumerable:!0,get:function(){return x("VRFieldOfView","VRFrameData's projection matrices"),i}}),r},be.prototype.onDeviceParamsUpdated_=function(e){this.config.DEBUG&&console.log("DPDB reported that device params were updated."),this.deviceInfo_.updateDeviceParams(e),this.distorter_&&this.distorter_.updateDeviceInfo(this.deviceInfo_)},be.prototype.updateBounds_=function(){this.layer_&&this.distorter_&&(this.layer_.leftBounds||this.layer_.rightBounds)&&this.distorter_.setTextureBounds(this.layer_.leftBounds,this.layer_.rightBounds)},be.prototype.beginPresent_=function(){var e=this.layer_.source.getContext("webgl");e||(e=this.layer_.source.getContext("experimental-webgl")),e||(e=this.layer_.source.getContext("webgl2")),e&&(this.layer_.predistorted?this.config.CARDBOARD_UI_DISABLED||(e.canvas.width=p()*this.bufferScale_,e.canvas.height=f()*this.bufferScale_,this.cardboardUI_=new I(e)):(this.config.CARDBOARD_UI_DISABLED||(this.cardboardUI_=new I(e)),this.distorter_=new T(e,this.cardboardUI_,this.config.BUFFER_SCALE,this.config.DIRTY_SUBMIT_FRAME_BINDINGS),this.distorter_.updateDeviceInfo(this.deviceInfo_)),this.cardboardUI_&&this.cardboardUI_.listen(function(e){this.viewerSelector_.show(this.layer_.source.parentElement),e.stopPropagation(),e.preventDefault()}.bind(this),function(e){this.exitPresent(),e.stopPropagation(),e.preventDefault()}.bind(this)),this.rotateInstructions_&&(u()&&w()?this.rotateInstructions_.showTemporarily(3e3,this.layer_.source.parentElement):this.rotateInstructions_.update()),this.orientationHandler=this.onOrientationChange_.bind(this),window.addEventListener("orientationchange",this.orientationHandler),this.vrdisplaypresentchangeHandler=this.updateBounds_.bind(this),window.addEventListener("vrdisplaypresentchange",this.vrdisplaypresentchangeHandler),this.fireVRDisplayDeviceParamsChange_())},be.prototype.endPresent_=function(){this.distorter_&&(this.distorter_.destroy(),this.distorter_=null),this.cardboardUI_&&(this.cardboardUI_.destroy(),this.cardboardUI_=null),this.rotateInstructions_&&this.rotateInstructions_.hide(),this.viewerSelector_.hide(),window.removeEventListener("orientationchange",this.orientationHandler),window.removeEventListener("vrdisplaypresentchange",this.vrdisplaypresentchangeHandler)},be.prototype.updatePresent_=function(){this.endPresent_(),this.beginPresent_()},be.prototype.submitFrame=function(e){if(this.distorter_)this.updateBounds_(),this.distorter_.submitFrame();else if(this.cardboardUI_&&this.layer_){var t=this.layer_.source.getContext("webgl");t||(t=this.layer_.source.getContext("experimental-webgl")),t||(t=this.layer_.source.getContext("webgl2"));var i=t.canvas;i.width==this.lastWidth&&i.height==this.lastHeight||this.cardboardUI_.onResize(),this.lastWidth=i.width,this.lastHeight=i.height,this.cardboardUI_.render()}},be.prototype.onOrientationChange_=function(e){this.viewerSelector_.hide(),this.rotateInstructions_&&this.rotateInstructions_.update(),this.onResize_()},be.prototype.onResize_=function(e){if(this.layer_){var t=this.layer_.source.getContext("webgl");t||(t=this.layer_.source.getContext("experimental-webgl")),t||(t=this.layer_.source.getContext("webgl2")),t.canvas.setAttribute("style",["position: absolute","top: 0","left: 0","width: 100vw","height: 100vh","border: 0","margin: 0","padding: 0px","box-sizing: content-box"].join("; ")+";"),b(t.canvas)}},be.prototype.onViewerChanged_=function(e){this.deviceInfo_.setViewer(e),this.distorter_&&this.distorter_.updateDeviceInfo(this.deviceInfo_),this.fireVRDisplayDeviceParamsChange_()},be.prototype.fireVRDisplayDeviceParamsChange_=function(){var e=new CustomEvent("vrdisplaydeviceparamschange",{detail:{vrdisplay:this,deviceInfo:this.deviceInfo_}});window.dispatchEvent(e)},be.VRFrameData=function(){this.leftProjectionMatrix=new Float32Array(16),this.leftViewMatrix=new Float32Array(16),this.rightProjectionMatrix=new Float32Array(16),this.rightViewMatrix=new Float32Array(16),this.pose=null},be.VRDisplay=ve,be}()}(Ce={exports:{}},Ce.exports),Ce.exports),Le=(De=Ie)&&De.__esModule&&Object.prototype.hasOwnProperty.call(De,"default")?De.default:De;class Oe extends i{constructor(e){super(),this.global=e,this.onWindowResize=this.onWindowResize.bind(this),this.global.window.addEventListener("resize",this.onWindowResize),this.environmentBlendMode="opaque"}onBaseLayerSet(e,t){throw new Error("Not implemented")}isSessionSupported(e){throw new Error("Not implemented")}isFeatureSupported(e){throw new Error("Not implemented")}async requestSession(e,t){throw new Error("Not implemented")}requestAnimationFrame(e){throw new Error("Not implemented")}onFrameStart(e){throw new Error("Not implemented")}onFrameEnd(e){throw new Error("Not implemented")}doesSessionSupportReferenceSpace(e,t){throw new Error("Not implemented")}requestStageBounds(){throw new Error("Not implemented")}async requestFrameOfReferenceTransform(e,t){}cancelAnimationFrame(e){throw new Error("Not implemented")}endSession(e){throw new Error("Not implemented")}getViewport(e,t,i,r){throw new Error("Not implemented")}getProjectionMatrix(e){throw new Error("Not implemented")}getBasePoseMatrix(){throw new Error("Not implemented")}getBaseViewMatrix(e){throw new Error("Not implemented")}getInputSources(){throw new Error("Not implemented")}getInputPose(e,t,i){throw new Error("Not implemented")}onWindowResize(){this.onWindowResize()}}let Ne={mapping:"xr-standard",profiles:["oculus-go","generic-trigger-touchpad"],buttons:{length:3,0:1,1:null,2:0},gripTransform:{orientation:[.11*Math.PI,0,0,1]}},Ge={mapping:"xr-standard",displayProfiles:{"Oculus Quest":["oculus-touch-v2","oculus-touch","generic-trigger-squeeze-thumbstick"]},profiles:["oculus-touch","generic-trigger-squeeze-thumbstick"],axes:{length:4,0:null,1:null,2:0,3:1},buttons:{length:7,0:1,1:2,2:null,3:0,4:3,5:4,6:null},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Qe={mapping:"xr-standard",profiles:["htc-vive","generic-trigger-squeeze-touchpad"],displayProfiles:{"HTC Vive":["htc-vive","generic-trigger-squeeze-touchpad"],"HTC Vive DVT":["htc-vive","generic-trigger-squeeze-touchpad"],"Valve Index":["valve-index","generic-trigger-squeeze-touchpad-thumbstick"]},buttons:{length:3,0:1,1:2,2:0},gripTransform:{position:[0,0,.05,1]},targetRayTransform:{orientation:[-.08*Math.PI,0,0,1]},userAgentOverrides:{Firefox:{axes:{invert:[1,3]}}}},ke={mapping:"xr-standard",profiles:["samsung-gearvr","generic-trigger-touchpad"],buttons:{length:3,0:1,1:null,2:0},gripTransform:{orientation:[.11*Math.PI,0,0,1]}},ze={mapping:"xr-standard",profiles:["samsung-odyssey","microsoft-mixed-reality","generic-trigger-squeeze-touchpad-thumbstick"],buttons:{length:4,0:1,1:0,2:2,3:4},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Ue={mapping:"xr-standard",profiles:["microsoft-mixed-reality","generic-trigger-squeeze-touchpad-thumbstick"],buttons:{length:4,0:1,1:0,2:2,3:4},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Ve={"Daydream Controller":{mapping:"",profiles:["google-daydream","generic-trigger-touchpad"],buttons:{length:3,0:null,1:null,2:0}},"Gear VR Controller":ke,"HTC Vive Focus Controller":{mapping:"xr-standard",profiles:["htc-vive-focus","generic-trigger-touchpad"],buttons:{length:3,0:1,1:null,2:0}},"Oculus Go Controller":Ne,"Oculus Touch (Right)":Ge,"Oculus Touch (Left)":Ge,"OpenVR Gamepad":Qe,"Spatial Controller (Spatial Interaction Source) 045E-065A":Ue,"Spatial Controller (Spatial Interaction Source) 045E-065D":ze,"Windows Mixed Reality (Right)":Ue,"Windows Mixed Reality (Left)":Ue};const He=f(.155,-.465,-.15),Xe=f(-.155,-.465,-.15),We=f(0,0,-.25),je=f(0,0,.05),qe=f(-.08,.14,.08),Ye=.4,Ze=.4,Je=.61,Ke=.175,$e=.12,et=.87,tt=180/Math.PI;class it{constructor(){this.hand="right",this.headElbowOffset=He,this.controllerQ=M(),this.lastControllerQ=M(),this.headQ=M(),this.headPos=u(),this.elbowPos=u(),this.wristPos=u(),this.time=null,this.lastTime=null,this.rootQ=M(),this.position=u()}setHandedness(e){this.hand!=e&&(this.hand=e,"left"==this.hand?this.headElbowOffset=Xe:this.headElbowOffset=He)}update(e,t){this.time=X(),e&&(B(this.lastControllerQ,this.controllerQ),B(this.controllerQ,e)),t&&(h(this.headPos,t),c(this.headQ,t));let i=this.getHeadYawOrientation_(),r=this.quatAngle_(this.lastControllerQ,this.controllerQ);r/((this.time-this.lastTime)/1e3)>Je?_(this.rootQ,this.rootQ,i,Math.min(r/Ke,1)):B(this.rootQ,i);let s=f(0,0,-1);E(s,s,this.controllerQ);let n=y(s,[0,1,0]),a=this.clamp_((n-$e)/et,0,1),o=R(this.rootQ);F(o,o),x(o,o,this.controllerQ);let l=this.elbowPos;m(l,this.headPos),g(l,l,this.headElbowOffset);let A=p(qe);v(A,A,a),g(l,l,A);let d=this.quatAngle_(o,M())*tt,u=(1-Math.pow(d/180,4))*(Ye+(1-Ye)*a*Ze),w=M();_(w,w,o,u);let b=F(M(),w),S=R(o);x(S,S,b);let T=this.wristPos;m(T,je),E(T,T,w),g(T,T,We),E(T,T,S),g(T,T,l);let P=p(qe);v(P,P,a),g(this.position,this.wristPos,P),E(this.position,this.position,this.rootQ),this.lastTime=this.time}getPosition(){return this.position}getHeadYawOrientation_(){let e=u();return function(e,t,i){function r(e,t,i){return ei?i:e}var s=t[0]*t[0],n=t[1]*t[1],a=t[2]*t[2],o=t[3]*t[3];if("XYZ"===i)e[0]=Math.atan2(2*(t[0]*t[3]-t[1]*t[2]),o-s-n+a),e[1]=Math.asin(r(2*(t[0]*t[2]+t[1]*t[3]),-1,1)),e[2]=Math.atan2(2*(t[2]*t[3]-t[0]*t[1]),o+s-n-a);else if("YXZ"===i)e[0]=Math.asin(r(2*(t[0]*t[3]-t[1]*t[2]),-1,1)),e[1]=Math.atan2(2*(t[0]*t[2]+t[1]*t[3]),o-s-n+a),e[2]=Math.atan2(2*(t[0]*t[1]+t[2]*t[3]),o-s+n-a);else if("ZXY"===i)e[0]=Math.asin(r(2*(t[0]*t[3]+t[1]*t[2]),-1,1)),e[1]=Math.atan2(2*(t[1]*t[3]-t[2]*t[0]),o-s-n+a),e[2]=Math.atan2(2*(t[2]*t[3]-t[0]*t[1]),o-s+n-a);else if("ZYX"===i)e[0]=Math.atan2(2*(t[0]*t[3]+t[2]*t[1]),o-s-n+a),e[1]=Math.asin(r(2*(t[1]*t[3]-t[0]*t[2]),-1,1)),e[2]=Math.atan2(2*(t[0]*t[1]+t[2]*t[3]),o+s-n-a);else if("YZX"===i)e[0]=Math.atan2(2*(t[0]*t[3]-t[2]*t[1]),o-s+n-a),e[1]=Math.atan2(2*(t[1]*t[3]-t[0]*t[2]),o+s-n-a),e[2]=Math.asin(r(2*(t[0]*t[1]+t[2]*t[3]),-1,1));else{if("XZY"!==i)return void console.log("No order given for quaternion to euler conversion.");e[0]=Math.atan2(2*(t[0]*t[3]+t[1]*t[2]),o-s+n-a),e[1]=Math.atan2(2*(t[0]*t[2]+t[1]*t[3]),o+s-n-a),e[2]=Math.asin(r(2*(t[2]*t[3]-t[0]*t[1]),-1,1))}}(e,this.headQ,"YXZ"),function(e,t,i,r){let s=.5*Math.PI/180;t*=s,i*=s,r*=s;let n=Math.sin(t),a=Math.cos(t),o=Math.sin(i),l=Math.cos(i),A=Math.sin(r),h=Math.cos(r);return e[0]=n*l*h-a*o*A,e[1]=a*o*h+n*l*A,e[2]=a*l*A-n*o*h,e[3]=a*l*h+n*o*A,e}(M(),0,e[1]*tt,0)}clamp_(e,t,i){return Math.min(Math.max(e,t),i)}quatAngle_(e,t){let i=[0,0,-1],r=[0,0,-1];return E(i,i,e),E(r,r,t),function(e,t){let i=f(e[0],e[1],e[2]),r=f(t[0],t[1],t[2]);w(i,i),w(r,r);let s=y(i,r);return s>1?0:s<-1?Math.PI:Math.acos(s)}(i,r)}}const rt=Symbol("@@webxr-polyfill/XRRemappedGamepad"),st={pressed:!1,touched:!1,value:0};Object.freeze(st);class nt{constructor(e,t,i){if(i||(i={}),i.userAgentOverrides)for(let e in i.userAgentOverrides)if(navigator.userAgent.includes(e)){let t=i.userAgentOverrides[e];for(let e in t)e in i?Object.assign(i[e],t[e]):i[e]=t[e];break}let r=new Array(i.axes&&i.axes.length?i.axes.length:e.axes.length),s=new Array(i.buttons&&i.buttons.length?i.buttons.length:e.buttons.length),a=null;if(i.gripTransform){let e=i.gripTransform.orientation||[0,0,0,1];A(a=n(),P(e,e),i.gripTransform.position||[0,0,0])}let o=null;if(i.targetRayTransform){let e=i.targetRayTransform.orientation||[0,0,0,1];A(o=n(),P(e,e),i.targetRayTransform.position||[0,0,0])}let l=i.profiles;i.displayProfiles&&t.displayName in i.displayProfiles&&(l=i.displayProfiles[t.displayName]),this[rt]={gamepad:e,map:i,profiles:l||[e.id],mapping:i.mapping||e.mapping,axes:r,buttons:s,gripTransform:a,targetRayTransform:o},this._update()}_update(){let e=this[rt].gamepad,t=this[rt].map,i=this[rt].axes;for(let r=0;r{ot||this.global.document.body.contains(r)||(i.modifiedCanvasLayer=!0,this.global.document.body.appendChild(r),Be(r)),i.baseLayer=t})}else i.baseLayer=t}isSessionSupported(e){return"immersive-ar"!=e&&("immersive-vr"!=e||!1!==this.canPresent)}isFeatureSupported(e){switch(e){case"viewer":case"local":case"local-floor":return!0;case"bounded":case"unbounded":default:return!1}}async requestSession(e,t){if(!this.isSessionSupported(e))return Promise.reject();let i="immersive-vr"==e;if(i){const e=this.global.document.createElement("canvas");if(!ot){e.getContext("webgl")}await this.display.requestPresent([{source:e,attributes:lt}])}const r=new ct(e,t,{renderContextType:this.HAS_BITMAP_SUPPORT?"bitmaprenderer":"2d"});return this.sessions.set(r.id,r),i&&(this.immersiveSession=r,this.dispatchEvent("@@webxr-polyfill/vr-present-start",r.id)),Promise.resolve(r.id)}requestAnimationFrame(e){return this.display.requestAnimationFrame(e)}getPrimaryButtonIndex(e){let t=0,i=e.id.toLowerCase();for(let e in At)if(i.includes(e)){t=At[e];break}return Math.min(t,e.buttons.length-1)}onFrameStart(e,t){this.display.depthNear=t.depthNear,this.display.depthFar=t.depthFar,this.display.getFrameData(this.frame);const i=this.sessions.get(e);if(i.immersive&&this.CAN_USE_GAMEPAD){let e=this.gamepadInputSources;this.gamepadInputSources={};let t=this.global.navigator.getGamepads();for(let r=0;r0){let t=e[r];if(t||(t=new at(this,this.display,this.getPrimaryButtonIndex(s))),t.updateFromGamepad(s),this.gamepadInputSources[r]=t,-1!=t.primaryButtonIndex){let e=s.buttons[t.primaryButtonIndex].pressed;e&&!t.primaryActionPressed?this.dispatchEvent("@@webxr-polyfill/input-select-start",{sessionId:i.id,inputSource:t.inputSource}):!e&&t.primaryActionPressed&&this.dispatchEvent("@@webxr-polyfill/input-select-end",{sessionId:i.id,inputSource:t.inputSource}),t.primaryActionPressed=e}if(-1!=t.primarySqueezeButtonIndex){let e=s.buttons[t.primarySqueezeButtonIndex].pressed;e&&!t.primarySqueezeActionPressed?this.dispatchEvent("@@webxr-polyfill/input-squeeze-start",{sessionId:i.id,inputSource:t.inputSource}):!e&&t.primarySqueezeActionPressed&&this.dispatchEvent("@@webxr-polyfill/input-squeeze-end",{sessionId:i.id,inputSource:t.inputSource}),t.primarySqueezeActionPressed=e}}}}if(!ot&&!i.immersive&&i.baseLayer){const e=i.baseLayer.context.canvas;d(this.frame.leftProjectionMatrix,t.inlineVerticalFieldOfView,e.width/e.height,t.depthNear,t.depthFar)}}onFrameEnd(e){const t=this.sessions.get(e);if(!t.ended&&t.baseLayer){if(t.outputContext&&(!t.immersive||this.display.capabilities.hasExternalDisplay)){const e=t.immersive&&this.display.capabilities.hasExternalDisplay,i=t.baseLayer.context.canvas,r=e?i.width/2:i.width,s=i.height;if(!ot){const e=t.outputContext.canvas,n=e.width,a=e.height,o=t.renderContext;this.HAS_BITMAP_SUPPORT?i.transferToImageBitmap?o.transferFromImageBitmap(i.transferToImageBitmap()):this.global.createImageBitmap(i,0,0,r,s,{resizeWidth:n,resizeHeight:a}).then(e=>o.transferFromImageBitmap(e)):o.drawImage(i,0,0,r,s,0,0,n,a)}}t.immersive&&t.baseLayer&&this.display.submitFrame()}}cancelAnimationFrame(e){this.display.cancelAnimationFrame(e)}async endSession(e){const t=this.sessions.get(e);if(!t.ended)return t.immersive?this.display.exitPresent():void(t.ended=!0)}doesSessionSupportReferenceSpace(e,t){const i=this.sessions.get(e);return!i.ended&&i.enabledFeatures.has(t)}requestStageBounds(){if(this.display.stageParameters){const e=this.display.stageParameters.sizeX,t=this.display.stageParameters.sizeZ,i=[];return i.push(-e/2),i.push(-t/2),i.push(e/2),i.push(-t/2),i.push(e/2),i.push(t/2),i.push(-e/2),i.push(t/2),i}return null}async requestFrameOfReferenceTransform(e,t){return("local-floor"===e||"bounded-floor"===e)&&this.display.stageParameters&&this.display.stageParameters.sittingToStandingTransform?this.display.stageParameters.sittingToStandingTransform:null}getProjectionMatrix(e){if("left"===e)return this.frame.leftProjectionMatrix;if("right"===e)return this.frame.rightProjectionMatrix;if("none"===e)return this.frame.leftProjectionMatrix;throw new Error("eye must be of type 'left' or 'right'")}getViewport(e,t,i,r){const s=this.sessions.get(e),{width:n,height:a}=i.context.canvas;if(!s.immersive)return r.x=r.y=0,r.width=n,r.height=a,!0;if("left"===t||"none"===t)r.x=0;else{if("right"!==t)return!1;r.x=n/2}return r.y=0,r.width=n/2,r.height=a,!0}getBasePoseMatrix(){let{position:e,orientation:t}=this.frame.pose;return e||t?(e||((e=this.tempVec3)[0]=e[1]=e[2]=0),A(this.baseModelMatrix,t,e),this.baseModelMatrix):this.baseModelMatrix}getBaseViewMatrix(e){if("left"===e||"none"===e)return this.frame.leftViewMatrix;if("right"===e)return this.frame.rightViewMatrix;throw new Error("eye must be of type 'left' or 'right'")}getInputSources(){let e=[];for(let t in this.gamepadInputSources)e.push(this.gamepadInputSources[t].inputSource);return e}getInputPose(e,t,i){if(!t)return null;for(let r in this.gamepadInputSources){let s=this.gamepadInputSources[r];if(s.inputSource===e)return s.getXRPose(t,i)}return null}onWindowResize(){}onVRDisplayPresentChange(e){this.display.isPresenting||this.sessions.forEach(e=>{if(e.immersive&&!e.ended){if(e.modifiedCanvasLayer){const t=e.baseLayer.context.canvas;document.body.removeChild(t),t.setAttribute("style","")}this.immersiveSession===e&&(this.immersiveSession=null),this.dispatchEvent("@@webxr-polyfill/vr-present-end",e.id)}})}}const ut=!1;let pt=0;class ft{constructor(e,t){this.mode=e,this.enabledFeatures=t,this.ended=null,this.baseLayer=null,this.id=++pt}}const mt=async function(e,t){if(t.webvr){let t=await async function(e){let t=null;if("getVRDisplays"in e.navigator)try{const i=await e.navigator.getVRDisplays();i&&i.length&&(t=new dt(e,i[0]))}catch(e){}return t}(e);if(t)return t}let i=(e=>{var t=!1;return Te=e.navigator.userAgent||e.navigator.vendor||e.opera,(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(Te)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(Te.substr(0,4)))&&(t=!0),t})(e);return i&&t.cardboard||!i&&t.allowCardboardOnDesktop?(e.VRFrameData||(e.VRFrameData=function(){this.rightViewMatrix=new Float32Array(16),this.leftViewMatrix=new Float32Array(16),this.rightProjectionMatrix=new Float32Array(16),this.leftProjectionMatrix=new Float32Array(16),this.pose=null}),new class extends dt{constructor(e,t){const i=new Le(t||{});super(e,i),this.display=i,this.frame={rightViewMatrix:new Float32Array(16),leftViewMatrix:new Float32Array(16),rightProjectionMatrix:new Float32Array(16),leftProjectionMatrix:new Float32Array(16),pose:null,timestamp:null}}}(e,t.cardboardConfig)):new class extends Oe{constructor(e){super(e),this.sessions=new Map,this.projectionMatrix=n(),this.identityMatrix=n()}onBaseLayerSet(e,t){this.sessions.get(e).baseLayer=t}isSessionSupported(e){return"inline"==e}isFeatureSupported(e){switch(e){case"viewer":return!0;default:return!1}}async requestSession(e,t){if(!this.isSessionSupported(e))return Promise.reject();const i=new ft(e,t);return this.sessions.set(i.id,i),Promise.resolve(i.id)}requestAnimationFrame(e){return window.requestAnimationFrame(e)}cancelAnimationFrame(e){window.cancelAnimationFrame(e)}onFrameStart(e,t){if(ut)return;const i=this.sessions.get(e);if(i.baseLayer){const e=i.baseLayer.context.canvas;d(this.projectionMatrix,t.inlineVerticalFieldOfView,e.width/e.height,t.depthNear,t.depthFar)}}onFrameEnd(e){}async endSession(e){this.sessions.get(e).ended=!0}doesSessionSupportReferenceSpace(e,t){const i=this.sessions.get(e);return!i.ended&&i.enabledFeatures.has(t)}requestStageBounds(){return null}async requestFrameOfReferenceTransform(e,t){return null}getProjectionMatrix(e){return this.projectionMatrix}getViewport(e,t,i,r){const{width:s,height:n}=i.context.canvas;return this.sessions.get(e),r.x=r.y=0,r.width=s,r.height=n,!0}getBasePoseMatrix(){return this.identityMatrix}getBaseViewMatrix(e){return this.identityMatrix}getInputSources(){return[]}getInputPose(e,t,i){return null}onWindowResize(){}}(e)},gt={global:e,webvr:!0,cardboard:!0,cardboardConfig:null,allowCardboardOnDesktop:!1},vt=["navigator","HTMLCanvasElement","WebGLRenderingContext"];return class{constructor(e={}){this.config=Object.freeze(Object.assign({},gt,e)),this.global=this.config.global,this.nativeWebXR="xr"in this.global.navigator,this.injected=!1,this.nativeWebXR?this._injectCompatibilityShims(this.global):this._injectPolyfill(this.global)}_injectPolyfill(e){if(!vt.every(t=>!!e[t]))throw new Error(`Global must have the following attributes : ${vt}`);for(const t of Object.keys(xe))void 0!==e[t]?console.warn(`${t} already defined on global.`):e[t]=xe[t];_e(e.WebGLRenderingContext)&&(Fe(e.HTMLCanvasElement),e.OffscreenCanvas&&Fe(e.OffscreenCanvas),e.WebGL2RenderingContext&&_e(e.WebGL2RenderingContext)),this.injected=!0,this._patchNavigatorXR()}_patchNavigatorXR(){let e=mt(this.global,this.config);this.xr=new xe.XR(e),Object.defineProperty(this.global.navigator,"xr",{value:this.xr,configurable:!0})}_injectCompatibilityShims(e){if(!vt.every(t=>!!e[t]))throw new Error(`Global must have the following attributes : ${vt}`);if(e.navigator.xr&&"supportsSession"in e.navigator.xr&&!("isSessionSupported"in e.navigator.xr)){let t=e.navigator.xr.supportsSession;e.navigator.xr.isSessionSupported=function(e){return t.call(this,e).then(()=>!0).catch(()=>!1)},e.navigator.xr.supportsSession=function(e){return console.warn("navigator.xr.supportsSession() is deprecated. Please call navigator.xr.isSessionSupported() instead and check the boolean value returned when the promise resolves."),t.call(this,e)}}}}}); diff --git a/build/webxr-polyfill.module.js b/build/webxr-polyfill.module.js deleted file mode 100644 index 07c3dc4..0000000 --- a/build/webxr-polyfill.module.js +++ /dev/null @@ -1,6114 +0,0 @@ -/** - * @license - * webxr-polyfill - * Copyright (c) 2017 Google - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @license - * cardboard-vr-display - * Copyright (c) 2015-2017 Google - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @license - * webvr-polyfill-dpdb - * Copyright (c) 2017 Google - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @license - * wglu-preserve-state - * Copyright (c) 2016, Brandon Jones. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/** - * @license - * nosleep.js - * Copyright (c) 2017, Rich Tibbett - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -const _global = typeof global !== 'undefined' ? global : - typeof self !== 'undefined' ? self : - typeof window !== 'undefined' ? window : {}; - -const PRIVATE = Symbol('@@webxr-polyfill/EventTarget'); -class EventTarget { - constructor() { - this[PRIVATE] = { - listeners: new Map(), - }; - } - addEventListener(type, listener) { - if (typeof type !== 'string') { throw new Error('`type` must be a string'); } - if (typeof listener !== 'function') { throw new Error('`listener` must be a function'); } - const typedListeners = this[PRIVATE].listeners.get(type) || []; - typedListeners.push(listener); - this[PRIVATE].listeners.set(type, typedListeners); - } - removeEventListener(type, listener) { - if (typeof type !== 'string') { throw new Error('`type` must be a string'); } - if (typeof listener !== 'function') { throw new Error('`listener` must be a function'); } - const typedListeners = this[PRIVATE].listeners.get(type) || []; - for (let i = typedListeners.length; i >= 0; i--) { - if (typedListeners[i] === listener) { - typedListeners.pop(); - } - } - } - dispatchEvent(type, event) { - const typedListeners = this[PRIVATE].listeners.get(type) || []; - const queue = []; - for (let i = 0; i < typedListeners.length; i++) { - queue[i] = typedListeners[i]; - } - for (let listener of queue) { - listener(event); - } - if (typeof this[`on${type}`] === 'function') { - this[`on${type}`](event); - } - } -} - -const EPSILON = 0.000001; -let ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; - - -const degree = Math.PI / 180; - -function create() { - let out = new ARRAY_TYPE(16); - if(ARRAY_TYPE != Float32Array) { - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - } - out[0] = 1; - out[5] = 1; - out[10] = 1; - out[15] = 1; - return out; -} - -function copy(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - out[9] = a[9]; - out[10] = a[10]; - out[11] = a[11]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - return out; -} - - -function identity(out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = 1; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 1; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - return out; -} - -function invert(out, a) { - let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; - let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; - let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; - let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; - let b00 = a00 * a11 - a01 * a10; - let b01 = a00 * a12 - a02 * a10; - let b02 = a00 * a13 - a03 * a10; - let b03 = a01 * a12 - a02 * a11; - let b04 = a01 * a13 - a03 * a11; - let b05 = a02 * a13 - a03 * a12; - let b06 = a20 * a31 - a21 * a30; - let b07 = a20 * a32 - a22 * a30; - let b08 = a20 * a33 - a23 * a30; - let b09 = a21 * a32 - a22 * a31; - let b10 = a21 * a33 - a23 * a31; - let b11 = a22 * a33 - a23 * a32; - let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; - if (!det) { - return null; - } - det = 1.0 / det; - out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; - out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; - out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; - out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; - out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; - out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; - out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; - out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; - out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; - out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; - out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; - out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; - out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; - out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; - out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; - out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; - return out; -} - - -function multiply(out, a, b) { - let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; - let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; - let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; - let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; - let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; - out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; - out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; - out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; - out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - return out; -} - - - - - - - - - - - - -function fromRotationTranslation(out, q, v) { - let x = q[0], y = q[1], z = q[2], w = q[3]; - let x2 = x + x; - let y2 = y + y; - let z2 = z + z; - let xx = x * x2; - let xy = x * y2; - let xz = x * z2; - let yy = y * y2; - let yz = y * z2; - let zz = z * z2; - let wx = w * x2; - let wy = w * y2; - let wz = w * z2; - out[0] = 1 - (yy + zz); - out[1] = xy + wz; - out[2] = xz - wy; - out[3] = 0; - out[4] = xy - wz; - out[5] = 1 - (xx + zz); - out[6] = yz + wx; - out[7] = 0; - out[8] = xz + wy; - out[9] = yz - wx; - out[10] = 1 - (xx + yy); - out[11] = 0; - out[12] = v[0]; - out[13] = v[1]; - out[14] = v[2]; - out[15] = 1; - return out; -} - -function getTranslation(out, mat) { - out[0] = mat[12]; - out[1] = mat[13]; - out[2] = mat[14]; - return out; -} - -function getRotation(out, mat) { - let trace = mat[0] + mat[5] + mat[10]; - let S = 0; - if (trace > 0) { - S = Math.sqrt(trace + 1.0) * 2; - out[3] = 0.25 * S; - out[0] = (mat[6] - mat[9]) / S; - out[1] = (mat[8] - mat[2]) / S; - out[2] = (mat[1] - mat[4]) / S; - } else if ((mat[0] > mat[5]) && (mat[0] > mat[10])) { - S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2; - out[3] = (mat[6] - mat[9]) / S; - out[0] = 0.25 * S; - out[1] = (mat[1] + mat[4]) / S; - out[2] = (mat[8] + mat[2]) / S; - } else if (mat[5] > mat[10]) { - S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2; - out[3] = (mat[8] - mat[2]) / S; - out[0] = (mat[1] + mat[4]) / S; - out[1] = 0.25 * S; - out[2] = (mat[6] + mat[9]) / S; - } else { - S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2; - out[3] = (mat[1] - mat[4]) / S; - out[0] = (mat[8] + mat[2]) / S; - out[1] = (mat[6] + mat[9]) / S; - out[2] = 0.25 * S; - } - return out; -} - - - - -function perspective(out, fovy, aspect, near, far) { - let f = 1.0 / Math.tan(fovy / 2), nf; - out[0] = f / aspect; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = f; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[11] = -1; - out[12] = 0; - out[13] = 0; - out[15] = 0; - if (far != null && far !== Infinity) { - nf = 1 / (near - far); - out[10] = (far + near) * nf; - out[14] = (2 * far * near) * nf; - } else { - out[10] = -1; - out[14] = -2 * near; - } - return out; -} - -function create$1() { - let out = new ARRAY_TYPE(3); - if(ARRAY_TYPE != Float32Array) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - } - return out; -} -function clone$1(a) { - var out = new ARRAY_TYPE(3); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - return out; -} -function length(a) { - let x = a[0]; - let y = a[1]; - let z = a[2]; - return Math.sqrt(x*x + y*y + z*z); -} -function fromValues$1(x, y, z) { - let out = new ARRAY_TYPE(3); - out[0] = x; - out[1] = y; - out[2] = z; - return out; -} -function copy$1(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - return out; -} - -function add$1(out, a, b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - return out; -} - - - - - - - - -function scale$1(out, a, b) { - out[0] = a[0] * b; - out[1] = a[1] * b; - out[2] = a[2] * b; - return out; -} - - - - - - -function normalize(out, a) { - let x = a[0]; - let y = a[1]; - let z = a[2]; - let len = x*x + y*y + z*z; - if (len > 0) { - len = 1 / Math.sqrt(len); - out[0] = a[0] * len; - out[1] = a[1] * len; - out[2] = a[2] * len; - } - return out; -} -function dot(a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; -} -function cross(out, a, b) { - let ax = a[0], ay = a[1], az = a[2]; - let bx = b[0], by = b[1], bz = b[2]; - out[0] = ay * bz - az * by; - out[1] = az * bx - ax * bz; - out[2] = ax * by - ay * bx; - return out; -} - - - - - - -function transformQuat(out, a, q) { - let qx = q[0], qy = q[1], qz = q[2], qw = q[3]; - let x = a[0], y = a[1], z = a[2]; - let uvx = qy * z - qz * y, - uvy = qz * x - qx * z, - uvz = qx * y - qy * x; - let uuvx = qy * uvz - qz * uvy, - uuvy = qz * uvx - qx * uvz, - uuvz = qx * uvy - qy * uvx; - let w2 = qw * 2; - uvx *= w2; - uvy *= w2; - uvz *= w2; - uuvx *= 2; - uuvy *= 2; - uuvz *= 2; - out[0] = x + uvx + uuvx; - out[1] = y + uvy + uuvy; - out[2] = z + uvz + uuvz; - return out; -} - - - -function angle(a, b) { - let tempA = fromValues$1(a[0], a[1], a[2]); - let tempB = fromValues$1(b[0], b[1], b[2]); - normalize(tempA, tempA); - normalize(tempB, tempB); - let cosine = dot(tempA, tempB); - if(cosine > 1.0) { - return 0; - } - else if(cosine < -1.0) { - return Math.PI; - } else { - return Math.acos(cosine); - } -} - - - - - - - - -const len = length; - -const forEach = (function() { - let vec = create$1(); - return function(a, stride, offset, count, fn, arg) { - let i, l; - if(!stride) { - stride = 3; - } - if(!offset) { - offset = 0; - } - if(count) { - l = Math.min((count * stride) + offset, a.length); - } else { - l = a.length; - } - for(i = offset; i < l; i += stride) { - vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; - fn(vec, vec, arg); - a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; - } - return a; - }; -})(); - -function create$2() { - let out = new ARRAY_TYPE(9); - if(ARRAY_TYPE != Float32Array) { - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[5] = 0; - out[6] = 0; - out[7] = 0; - } - out[0] = 1; - out[4] = 1; - out[8] = 1; - return out; -} - -function create$3() { - let out = new ARRAY_TYPE(4); - if(ARRAY_TYPE != Float32Array) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 0; - } - return out; -} -function clone$3(a) { - let out = new ARRAY_TYPE(4); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; -} -function fromValues$3(x, y, z, w) { - let out = new ARRAY_TYPE(4); - out[0] = x; - out[1] = y; - out[2] = z; - out[3] = w; - return out; -} -function copy$3(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; -} - - - - - - - - - - - - - - - - - - -function normalize$1(out, a) { - let x = a[0]; - let y = a[1]; - let z = a[2]; - let w = a[3]; - let len = x*x + y*y + z*z + w*w; - if (len > 0) { - len = 1 / Math.sqrt(len); - out[0] = x * len; - out[1] = y * len; - out[2] = z * len; - out[3] = w * len; - } - return out; -} - - - - - - - - - - - - - - - -const forEach$1 = (function() { - let vec = create$3(); - return function(a, stride, offset, count, fn, arg) { - let i, l; - if(!stride) { - stride = 4; - } - if(!offset) { - offset = 0; - } - if(count) { - l = Math.min((count * stride) + offset, a.length); - } else { - l = a.length; - } - for(i = offset; i < l; i += stride) { - vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3]; - fn(vec, vec, arg); - a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3]; - } - return a; - }; -})(); - -function create$4() { - let out = new ARRAY_TYPE(4); - if(ARRAY_TYPE != Float32Array) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - } - out[3] = 1; - return out; -} - -function setAxisAngle(out, axis, rad) { - rad = rad * 0.5; - let s = Math.sin(rad); - out[0] = s * axis[0]; - out[1] = s * axis[1]; - out[2] = s * axis[2]; - out[3] = Math.cos(rad); - return out; -} - -function multiply$4(out, a, b) { - let ax = a[0], ay = a[1], az = a[2], aw = a[3]; - let bx = b[0], by = b[1], bz = b[2], bw = b[3]; - out[0] = ax * bw + aw * bx + ay * bz - az * by; - out[1] = ay * bw + aw * by + az * bx - ax * bz; - out[2] = az * bw + aw * bz + ax * by - ay * bx; - out[3] = aw * bw - ax * bx - ay * by - az * bz; - return out; -} - - - - -function slerp(out, a, b, t) { - let ax = a[0], ay = a[1], az = a[2], aw = a[3]; - let bx = b[0], by = b[1], bz = b[2], bw = b[3]; - let omega, cosom, sinom, scale0, scale1; - cosom = ax * bx + ay * by + az * bz + aw * bw; - if ( cosom < 0.0 ) { - cosom = -cosom; - bx = - bx; - by = - by; - bz = - bz; - bw = - bw; - } - if ( (1.0 - cosom) > EPSILON ) { - omega = Math.acos(cosom); - sinom = Math.sin(omega); - scale0 = Math.sin((1.0 - t) * omega) / sinom; - scale1 = Math.sin(t * omega) / sinom; - } else { - scale0 = 1.0 - t; - scale1 = t; - } - out[0] = scale0 * ax + scale1 * bx; - out[1] = scale0 * ay + scale1 * by; - out[2] = scale0 * az + scale1 * bz; - out[3] = scale0 * aw + scale1 * bw; - return out; -} - -function invert$2(out, a) { - let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; - let dot$$1 = a0*a0 + a1*a1 + a2*a2 + a3*a3; - let invDot = dot$$1 ? 1.0/dot$$1 : 0; - out[0] = -a0*invDot; - out[1] = -a1*invDot; - out[2] = -a2*invDot; - out[3] = a3*invDot; - return out; -} - -function fromMat3(out, m) { - let fTrace = m[0] + m[4] + m[8]; - let fRoot; - if ( fTrace > 0.0 ) { - fRoot = Math.sqrt(fTrace + 1.0); - out[3] = 0.5 * fRoot; - fRoot = 0.5/fRoot; - out[0] = (m[5]-m[7])*fRoot; - out[1] = (m[6]-m[2])*fRoot; - out[2] = (m[1]-m[3])*fRoot; - } else { - let i = 0; - if ( m[4] > m[0] ) - i = 1; - if ( m[8] > m[i*3+i] ) - i = 2; - let j = (i+1)%3; - let k = (i+2)%3; - fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); - out[i] = 0.5 * fRoot; - fRoot = 0.5 / fRoot; - out[3] = (m[j*3+k] - m[k*3+j]) * fRoot; - out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; - out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; - } - return out; -} -function fromEuler(out, x, y, z) { - let halfToRad = 0.5 * Math.PI / 180.0; - x *= halfToRad; - y *= halfToRad; - z *= halfToRad; - let sx = Math.sin(x); - let cx = Math.cos(x); - let sy = Math.sin(y); - let cy = Math.cos(y); - let sz = Math.sin(z); - let cz = Math.cos(z); - out[0] = sx * cy * cz - cx * sy * sz; - out[1] = cx * sy * cz + sx * cy * sz; - out[2] = cx * cy * sz - sx * sy * cz; - out[3] = cx * cy * cz + sx * sy * sz; - return out; -} - -const clone$4 = clone$3; -const fromValues$4 = fromValues$3; -const copy$4 = copy$3; - - - - - - - - - - -const normalize$2 = normalize$1; - - -const rotationTo = (function() { - let tmpvec3 = create$1(); - let xUnitVec3 = fromValues$1(1,0,0); - let yUnitVec3 = fromValues$1(0,1,0); - return function(out, a, b) { - let dot$$1 = dot(a, b); - if (dot$$1 < -0.999999) { - cross(tmpvec3, xUnitVec3, a); - if (len(tmpvec3) < 0.000001) - cross(tmpvec3, yUnitVec3, a); - normalize(tmpvec3, tmpvec3); - setAxisAngle(out, tmpvec3, Math.PI); - return out; - } else if (dot$$1 > 0.999999) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 1; - return out; - } else { - cross(tmpvec3, a, b); - out[0] = tmpvec3[0]; - out[1] = tmpvec3[1]; - out[2] = tmpvec3[2]; - out[3] = 1 + dot$$1; - return normalize$2(out, out); - } - }; -})(); -const sqlerp = (function () { - let temp1 = create$4(); - let temp2 = create$4(); - return function (out, a, b, c, d, t) { - slerp(temp1, a, d, t); - slerp(temp2, b, c, t); - slerp(out, temp1, temp2, 2 * t * (1 - t)); - return out; - }; -}()); -const setAxes = (function() { - let matr = create$2(); - return function(out, view, right, up) { - matr[0] = right[0]; - matr[3] = right[1]; - matr[6] = right[2]; - matr[1] = up[0]; - matr[4] = up[1]; - matr[7] = up[2]; - matr[2] = -view[0]; - matr[5] = -view[1]; - matr[8] = -view[2]; - return normalize$2(out, fromMat3(out, matr)); - }; -})(); - -const PRIVATE$1 = Symbol('@@webxr-polyfill/XRRigidTransform'); -class XRRigidTransform$1 { - constructor() { - this[PRIVATE$1] = { - matrix: null, - position: null, - orientation: null, - inverse: null, - }; - if (arguments.length === 0) { - this[PRIVATE$1].matrix = identity(new Float32Array(16)); - } else if (arguments.length === 1) { - if (arguments[0] instanceof Float32Array) { - this[PRIVATE$1].matrix = arguments[0]; - } else { - this[PRIVATE$1].position = this._getPoint(arguments[0]); - this[PRIVATE$1].orientation = DOMPointReadOnly.fromPoint({ - x: 0, y: 0, z: 0, w: 1 - }); - } - } else if (arguments.length === 2) { - this[PRIVATE$1].position = this._getPoint(arguments[0]); - this[PRIVATE$1].orientation = this._getPoint(arguments[1]); - } else { - throw new Error("Too many arguments!"); - } - if (this[PRIVATE$1].matrix) { - let position = create$1(); - getTranslation(position, this[PRIVATE$1].matrix); - this[PRIVATE$1].position = DOMPointReadOnly.fromPoint({ - x: position[0], - y: position[1], - z: position[2] - }); - let orientation = create$4(); - getRotation(orientation, this[PRIVATE$1].matrix); - this[PRIVATE$1].orientation = DOMPointReadOnly.fromPoint({ - x: orientation[0], - y: orientation[1], - z: orientation[2], - w: orientation[3] - }); - } else { - this[PRIVATE$1].matrix = identity(new Float32Array(16)); - fromRotationTranslation( - this[PRIVATE$1].matrix, - fromValues$4( - this[PRIVATE$1].orientation.x, - this[PRIVATE$1].orientation.y, - this[PRIVATE$1].orientation.z, - this[PRIVATE$1].orientation.w), - fromValues$1( - this[PRIVATE$1].position.x, - this[PRIVATE$1].position.y, - this[PRIVATE$1].position.z) - ); - } - } - _getPoint(arg) { - if (arg instanceof DOMPointReadOnly) { - return arg; - } - return DOMPointReadOnly.fromPoint(arg); - } - get matrix() { return this[PRIVATE$1].matrix; } - get position() { return this[PRIVATE$1].position; } - get orientation() { return this[PRIVATE$1].orientation; } - get inverse() { - if (this[PRIVATE$1].inverse === null) { - let invMatrix = identity(new Float32Array(16)); - invert(invMatrix, this[PRIVATE$1].matrix); - this[PRIVATE$1].inverse = new XRRigidTransform$1(invMatrix); - this[PRIVATE$1].inverse[PRIVATE$1].inverse = this; - } - return this[PRIVATE$1].inverse; - } -} - -const PRIVATE$2 = Symbol('@@webxr-polyfill/XRSpace'); - -class XRSpace { - constructor(specialType = null, inputSource = null) { - this[PRIVATE$2] = { - specialType, - inputSource, - baseMatrix: null, - inverseBaseMatrix: null, - lastFrameId: -1 - }; - } - get _specialType() { - return this[PRIVATE$2].specialType; - } - get _inputSource() { - return this[PRIVATE$2].inputSource; - } - _ensurePoseUpdated(device, frameId) { - if (frameId == this[PRIVATE$2].lastFrameId) return; - this[PRIVATE$2].lastFrameId = frameId; - this._onPoseUpdate(device); - } - _onPoseUpdate(device) { - if (this[PRIVATE$2].specialType == 'viewer') { - this._baseMatrix = device.getBasePoseMatrix(); - } - } - set _baseMatrix(matrix) { - this[PRIVATE$2].baseMatrix = matrix; - this[PRIVATE$2].inverseBaseMatrix = null; - } - get _baseMatrix() { - if (!this[PRIVATE$2].baseMatrix) { - if (this[PRIVATE$2].inverseBaseMatrix) { - this[PRIVATE$2].baseMatrix = new Float32Array(16); - invert(this[PRIVATE$2].baseMatrix, this[PRIVATE$2].inverseBaseMatrix); - } - } - return this[PRIVATE$2].baseMatrix; - } - set _inverseBaseMatrix(matrix) { - this[PRIVATE$2].inverseBaseMatrix = matrix; - this[PRIVATE$2].baseMatrix = null; - } - get _inverseBaseMatrix() { - if (!this[PRIVATE$2].inverseBaseMatrix) { - if (this[PRIVATE$2].baseMatrix) { - this[PRIVATE$2].inverseBaseMatrix = new Float32Array(16); - invert(this[PRIVATE$2].inverseBaseMatrix, this[PRIVATE$2].baseMatrix); - } - } - return this[PRIVATE$2].inverseBaseMatrix; - } - _getSpaceRelativeTransform(space) { - if (!this._inverseBaseMatrix || !space._baseMatrix) { - return null; - } - let out = new Float32Array(16); - multiply(out, this._inverseBaseMatrix, space._baseMatrix); - return new XRRigidTransform$1(out); - } -} - -const DEFAULT_EMULATION_HEIGHT = 1.6; -const PRIVATE$3 = Symbol('@@webxr-polyfill/XRReferenceSpace'); -const XRReferenceSpaceTypes = [ - 'viewer', - 'local', - 'local-floor', - 'bounded-floor', - 'unbounded' -]; -function isFloor(type) { - return type === 'bounded-floor' || type === 'local-floor'; -} -class XRReferenceSpace extends XRSpace { - constructor(type, transform = null) { - if (!XRReferenceSpaceTypes.includes(type)) { - throw new Error(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`); - } - super(type); - if (type === 'bounded-floor' && !transform) { - throw new Error(`XRReferenceSpace cannot use 'bounded-floor' type if the platform does not provide the floor level`); - } - if (isFloor(type) && !transform) { - transform = identity(new Float32Array(16)); - transform[13] = DEFAULT_EMULATION_HEIGHT; - } - this._inverseBaseMatrix = transform || identity(new Float32Array(16)); - this[PRIVATE$3] = { - type, - transform, - originOffset : identity(new Float32Array(16)), - }; - } - _transformBasePoseMatrix(out, pose) { - multiply(out, this._inverseBaseMatrix, pose); - } - _originOffsetMatrix() { - return this[PRIVATE$3].originOffset; - } - _adjustForOriginOffset(transformMatrix) { - let inverseOriginOffsetMatrix = new Float32Array(16); - invert(inverseOriginOffsetMatrix, this[PRIVATE$3].originOffset); - multiply(transformMatrix, inverseOriginOffsetMatrix, transformMatrix); - } - _getSpaceRelativeTransform(space) { - let transform = super._getSpaceRelativeTransform(space); - this._adjustForOriginOffset(transform.matrix); - return new XRRigidTransform(transform.matrix); - } - getOffsetReferenceSpace(additionalOffset) { - let newSpace = new XRReferenceSpace( - this[PRIVATE$3].type, - this[PRIVATE$3].transform, - this[PRIVATE$3].bounds); - multiply(newSpace[PRIVATE$3].originOffset, this[PRIVATE$3].originOffset, additionalOffset.matrix); - return newSpace; - } -} - -const PRIVATE$4 = Symbol('@@webxr-polyfill/XR'); -const XRSessionModes = ['inline', 'immersive-vr', 'immersive-ar']; -const DEFAULT_SESSION_OPTIONS = { - 'inline': { - requiredFeatures: ['viewer'], - optionalFeatures: [], - }, - 'immersive-vr': { - requiredFeatures: ['viewer', 'local'], - optionalFeatures: [], - }, - 'immersive-ar': { - requiredFeatures: ['viewer', 'local'], - optionalFeatures: [], - } -}; -const POLYFILL_REQUEST_SESSION_ERROR = -`Polyfill Error: Must call navigator.xr.isSessionSupported() with any XRSessionMode -or navigator.xr.requestSession('inline') prior to requesting an immersive -session. This is a limitation specific to the WebXR Polyfill and does not apply -to native implementations of the API.`; -class XR extends EventTarget { - constructor(devicePromise) { - super(); - this[PRIVATE$4] = { - device: null, - devicePromise, - immersiveSession: null, - inlineSessions: new Set(), - }; - devicePromise.then((device) => { this[PRIVATE$4].device = device; }); - } - async isSessionSupported(mode) { - if (!this[PRIVATE$4].device) { - await this[PRIVATE$4].devicePromise; - } - if (mode != 'inline') { - return Promise.resolve(this[PRIVATE$4].device.isSessionSupported(mode)); - } - return Promise.resolve(true); - } - async requestSession(mode, options) { - if (!this[PRIVATE$4].device) { - if (mode != 'inline') { - throw new Error(POLYFILL_REQUEST_SESSION_ERROR); - } else { - await this[PRIVATE$4].devicePromise; - } - } - if (!XRSessionModes.includes(mode)) { - throw new TypeError( - `The provided value '${mode}' is not a valid enum value of type XRSessionMode`); - } - const defaultOptions = DEFAULT_SESSION_OPTIONS[mode]; - const requiredFeatures = defaultOptions.requiredFeatures.concat( - options && options.requiredFeatures ? options.requiredFeatures : []); - const optionalFeatures = defaultOptions.optionalFeatures.concat( - options && options.optionalFeatures ? options.optionalFeatures : []); - const enabledFeatures = new Set(); - let requirementsFailed = false; - for (let feature of requiredFeatures) { - if (!this[PRIVATE$4].device.isFeatureSupported(feature)) { - console.error(`The required feature '${feature}' is not supported`); - requirementsFailed = true; - } else { - enabledFeatures.add(feature); - } - } - if (requirementsFailed) { - throw new DOMException('Session does not support some required features', 'NotSupportedError'); - } - for (let feature of optionalFeatures) { - if (!this[PRIVATE$4].device.isFeatureSupported(feature)) { - console.log(`The optional feature '${feature}' is not supported`); - } else { - enabledFeatures.add(feature); - } - } - const sessionId = await this[PRIVATE$4].device.requestSession(mode, enabledFeatures); - const session = new XRSession(this[PRIVATE$4].device, mode, sessionId); - if (mode == 'inline') { - this[PRIVATE$4].inlineSessions.add(session); - } else { - this[PRIVATE$4].immersiveSession = session; - } - const onSessionEnd = () => { - if (mode == 'inline') { - this[PRIVATE$4].inlineSessions.delete(session); - } else { - this[PRIVATE$4].immersiveSession = null; - } - session.removeEventListener('end', onSessionEnd); - }; - session.addEventListener('end', onSessionEnd); - return session; - } -} - -let now; -if ('performance' in _global === false) { - let startTime = Date.now(); - now = () => Date.now() - startTime; -} else { - now = () => performance.now(); -} -var now$1 = now; - -const PRIVATE$5 = Symbol('@@webxr-polyfill/XRPose'); -class XRPose$1 { - constructor(transform, emulatedPosition) { - this[PRIVATE$5] = { - transform, - emulatedPosition, - }; - } - get transform() { return this[PRIVATE$5].transform; } - get emulatedPosition() { return this[PRIVATE$5].emulatedPosition; } -} - -const PRIVATE$6 = Symbol('@@webxr-polyfill/XRViewerPose'); -class XRViewerPose extends XRPose$1 { - constructor(transform, views, emulatedPosition = false) { - super(transform, emulatedPosition); - this[PRIVATE$6] = { - views - }; - } - get views() { - return this[PRIVATE$6].views; - } -} - -const PRIVATE$7 = Symbol('@@webxr-polyfill/XRViewport'); -class XRViewport { - constructor(target) { - this[PRIVATE$7] = { target }; - } - get x() { return this[PRIVATE$7].target.x; } - get y() { return this[PRIVATE$7].target.y; } - get width() { return this[PRIVATE$7].target.width; } - get height() { return this[PRIVATE$7].target.height; } -} - -const XREyes = ['left', 'right', 'none']; -const PRIVATE$8 = Symbol('@@webxr-polyfill/XRView'); -class XRView { - constructor(device, transform, eye, sessionId) { - if (!XREyes.includes(eye)) { - throw new Error(`XREye must be one of: ${XREyes}`); - } - const temp = Object.create(null); - const viewport = new XRViewport(temp); - this[PRIVATE$8] = { - device, - eye, - viewport, - temp, - sessionId, - transform, - }; - } - get eye() { return this[PRIVATE$8].eye; } - get projectionMatrix() { return this[PRIVATE$8].device.getProjectionMatrix(this.eye); } - get transform() { return this[PRIVATE$8].transform; } - _getViewport(layer) { - if (this[PRIVATE$8].device.getViewport(this[PRIVATE$8].sessionId, - this.eye, - layer, - this[PRIVATE$8].temp)) { - return this[PRIVATE$8].viewport; - } - return undefined; - } -} - -const PRIVATE$9 = Symbol('@@webxr-polyfill/XRFrame'); -const NON_ACTIVE_MSG = "XRFrame access outside the callback that produced it is invalid."; -const NON_ANIMFRAME_MSG = "getViewerPose can only be called on XRFrame objects passed to XRSession.requestAnimationFrame callbacks."; -let NEXT_FRAME_ID = 0; -class XRFrame { - constructor(device, session, sessionId) { - this[PRIVATE$9] = { - id: ++NEXT_FRAME_ID, - active: false, - animationFrame: false, - device, - session, - sessionId - }; - } - get session() { return this[PRIVATE$9].session; } - getViewerPose(referenceSpace) { - if (!this[PRIVATE$9].animationFrame) { - throw new DOMException(NON_ANIMFRAME_MSG, 'InvalidStateError'); - } - if (!this[PRIVATE$9].active) { - throw new DOMException(NON_ACTIVE_MSG, 'InvalidStateError'); - } - const device = this[PRIVATE$9].device; - const session = this[PRIVATE$9].session; - session[PRIVATE$15].viewerSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); - referenceSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); - let viewerTransform = referenceSpace._getSpaceRelativeTransform(session[PRIVATE$15].viewerSpace); - const views = []; - for (let viewSpace of session[PRIVATE$15].viewSpaces) { - viewSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); - let viewTransform = referenceSpace._getSpaceRelativeTransform(viewSpace); - let view = new XRView(device, viewTransform, viewSpace.eye, this[PRIVATE$9].sessionId); - views.push(view); - } - let viewerPose = new XRViewerPose(viewerTransform, views, false ); - return viewerPose; - } - getPose(space, baseSpace) { - if (!this[PRIVATE$9].active) { - throw new DOMException(NON_ACTIVE_MSG, 'InvalidStateError'); - } - const device = this[PRIVATE$9].device; - if (space._specialType === "target-ray" || space._specialType === "grip") { - return device.getInputPose( - space._inputSource, baseSpace, space._specialType); - } else { - space._ensurePoseUpdated(device, this[PRIVATE$9].id); - baseSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); - let transform = baseSpace._getSpaceRelativeTransform(space); - if (!transform) { return null; } - return new XRPose(transform, false ); - } - return null; - } -} - -const PRIVATE$10 = Symbol('@@webxr-polyfill/XRRenderState'); -const XRRenderStateInit = Object.freeze({ - depthNear: 0.1, - depthFar: 1000.0, - inlineVerticalFieldOfView: null, - baseLayer: null -}); -class XRRenderState { - constructor(stateInit = {}) { - const config = Object.assign({}, XRRenderStateInit, stateInit); - this[PRIVATE$10] = { config }; - } - get depthNear() { return this[PRIVATE$10].config.depthNear; } - get depthFar() { return this[PRIVATE$10].config.depthFar; } - get inlineVerticalFieldOfView() { return this[PRIVATE$10].config.inlineVerticalFieldOfView; } - get baseLayer() { return this[PRIVATE$10].config.baseLayer; } -} - -const POLYFILLED_XR_COMPATIBLE = Symbol('@@webxr-polyfill/polyfilled-xr-compatible'); -const XR_COMPATIBLE = Symbol('@@webxr-polyfill/xr-compatible'); - -const PRIVATE$11 = Symbol('@@webxr-polyfill/XRWebGLLayer'); -const XRWebGLLayerInit = Object.freeze({ - antialias: true, - depth: false, - stencil: false, - alpha: true, - multiview: false, - ignoreDepthValues: false, - framebufferScaleFactor: 1.0, -}); -class XRWebGLLayer { - constructor(session, context, layerInit={}) { - const config = Object.assign({}, XRWebGLLayerInit, layerInit); - if (!(session instanceof XRSession$1)) { - throw new Error('session must be a XRSession'); - } - if (session.ended) { - throw new Error(`InvalidStateError`); - } - if (context[POLYFILLED_XR_COMPATIBLE]) { - if (context[XR_COMPATIBLE] !== true) { - throw new Error(`InvalidStateError`); - } - } - const framebuffer = context.getParameter(context.FRAMEBUFFER_BINDING); - this[PRIVATE$11] = { - context, - config, - framebuffer, - session, - }; - } - get context() { return this[PRIVATE$11].context; } - get antialias() { return this[PRIVATE$11].config.antialias; } - get ignoreDepthValues() { return true; } - get framebuffer() { return this[PRIVATE$11].framebuffer; } - get framebufferWidth() { return this[PRIVATE$11].context.drawingBufferWidth; } - get framebufferHeight() { return this[PRIVATE$11].context.drawingBufferHeight; } - get _session() { return this[PRIVATE$11].session; } - getViewport(view) { - return view._getViewport(this); - } - static getNativeFramebufferScaleFactor(session) { - if (!session) { - throw new TypeError('getNativeFramebufferScaleFactor must be passed a session.') - } - if (session[PRIVATE$15].ended) { return 0.0; } - return 1.0; - } -} - -const PRIVATE$12 = Symbol('@@webxr-polyfill/XRInputSourceEvent'); -class XRInputSourceEvent extends Event { - constructor(type, eventInitDict) { - super(type, eventInitDict); - this[PRIVATE$12] = { - frame: eventInitDict.frame, - inputSource: eventInitDict.inputSource - }; - } - get frame() { return this[PRIVATE$12].frame; } - get inputSource() { return this[PRIVATE$12].inputSource; } -} - -const PRIVATE$13 = Symbol('@@webxr-polyfill/XRSessionEvent'); -class XRSessionEvent extends Event { - constructor(type, eventInitDict) { - super(type, eventInitDict); - this[PRIVATE$13] = { - session: eventInitDict.session - }; - } - get session() { return this[PRIVATE$13].session; } -} - -const PRIVATE$14 = Symbol('@@webxr-polyfill/XRInputSourcesChangeEvent'); -class XRInputSourcesChangeEvent extends Event { - constructor(type, eventInitDict) { - super(type, eventInitDict); - this[PRIVATE$14] = { - session: eventInitDict.session, - added: eventInitDict.added, - removed: eventInitDict.removed - }; - } - get session() { return this[PRIVATE$14].session; } - get added() { return this[PRIVATE$14].added; } - get removed() { return this[PRIVATE$14].removed; } -} - -const PRIVATE$15 = Symbol('@@webxr-polyfill/XRSession'); -class XRViewSpace extends XRSpace { - constructor(eye) { - super(eye); - } - get eye() { - return this._specialType; - } - _onPoseUpdate(device) { - this._inverseBaseMatrix = device.getBaseViewMatrix(this._specialType); - } -} -class XRSession$1 extends EventTarget { - constructor(device, mode, id) { - super(); - let immersive = mode != 'inline'; - let initialRenderState = new XRRenderState({ - inlineVerticalFieldOfView: immersive ? null : Math.PI * 0.5 - }); - this[PRIVATE$15] = { - device, - mode, - immersive, - ended: false, - suspended: false, - frameCallbacks: [], - currentFrameCallbacks: null, - frameHandle: 0, - deviceFrameHandle: null, - id, - activeRenderState: initialRenderState, - pendingRenderState: null, - viewerSpace: new XRReferenceSpace("viewer"), - viewSpaces: [], - currentInputSources: [] - }; - if (immersive) { - this[PRIVATE$15].viewSpaces.push(new XRViewSpace('left'), - new XRViewSpace('right')); - } else { - this[PRIVATE$15].viewSpaces.push(new XRViewSpace('none')); - } - this[PRIVATE$15].onDeviceFrame = () => { - if (this[PRIVATE$15].ended || this[PRIVATE$15].suspended) { - return; - } - this[PRIVATE$15].deviceFrameHandle = null; - this[PRIVATE$15].startDeviceFrameLoop(); - if (this[PRIVATE$15].pendingRenderState !== null) { - this[PRIVATE$15].activeRenderState = new XRRenderState(this[PRIVATE$15].pendingRenderState); - this[PRIVATE$15].pendingRenderState = null; - if (this[PRIVATE$15].activeRenderState.baseLayer) { - this[PRIVATE$15].device.onBaseLayerSet( - this[PRIVATE$15].id, - this[PRIVATE$15].activeRenderState.baseLayer); - } - } - if (this[PRIVATE$15].activeRenderState.baseLayer === null) { - return; - } - const frame = new XRFrame(device, this, this[PRIVATE$15].id); - const callbacks = this[PRIVATE$15].currentFrameCallbacks = this[PRIVATE$15].frameCallbacks; - this[PRIVATE$15].frameCallbacks = []; - frame[PRIVATE$9].active = true; - frame[PRIVATE$9].animationFrame = true; - this[PRIVATE$15].device.onFrameStart(this[PRIVATE$15].id, this[PRIVATE$15].activeRenderState); - this._checkInputSourcesChange(); - const rightNow = now$1(); - for (let i = 0; i < callbacks.length; i++) { - try { - if (!callbacks[i].cancelled && typeof callbacks[i].callback === 'function') { - callbacks[i].callback(rightNow, frame); - } - } catch(err) { - console.error(err); - } - } - this[PRIVATE$15].currentFrameCallbacks = null; - frame[PRIVATE$9].active = false; - this[PRIVATE$15].device.onFrameEnd(this[PRIVATE$15].id); - }; - this[PRIVATE$15].startDeviceFrameLoop = () => { - if (this[PRIVATE$15].deviceFrameHandle === null) { - this[PRIVATE$15].deviceFrameHandle = this[PRIVATE$15].device.requestAnimationFrame( - this[PRIVATE$15].onDeviceFrame - ); - } - }; - this[PRIVATE$15].stopDeviceFrameLoop = () => { - const handle = this[PRIVATE$15].deviceFrameHandle; - if (handle !== null) { - this[PRIVATE$15].device.cancelAnimationFrame(handle); - this[PRIVATE$15].deviceFrameHandle = null; - } - }; - this[PRIVATE$15].onPresentationEnd = sessionId => { - if (sessionId !== this[PRIVATE$15].id) { - this[PRIVATE$15].suspended = false; - this[PRIVATE$15].startDeviceFrameLoop(); - this.dispatchEvent('focus', { session: this }); - return; - } - this[PRIVATE$15].ended = true; - this[PRIVATE$15].stopDeviceFrameLoop(); - device.removeEventListener('@webvr-polyfill/vr-present-end', this[PRIVATE$15].onPresentationEnd); - device.removeEventListener('@webvr-polyfill/vr-present-start', this[PRIVATE$15].onPresentationStart); - device.removeEventListener('@@webvr-polyfill/input-select-start', this[PRIVATE$15].onSelectStart); - device.removeEventListener('@@webvr-polyfill/input-select-end', this[PRIVATE$15].onSelectEnd); - this.dispatchEvent('end', new XRSessionEvent('end', { session: this })); - }; - device.addEventListener('@@webxr-polyfill/vr-present-end', this[PRIVATE$15].onPresentationEnd); - this[PRIVATE$15].onPresentationStart = sessionId => { - if (sessionId === this[PRIVATE$15].id) { - return; - } - this[PRIVATE$15].suspended = true; - this[PRIVATE$15].stopDeviceFrameLoop(); - this.dispatchEvent('blur', { session: this }); - }; - device.addEventListener('@@webxr-polyfill/vr-present-start', this[PRIVATE$15].onPresentationStart); - this[PRIVATE$15].onSelectStart = evt => { - if (evt.sessionId !== this[PRIVATE$15].id) { - return; - } - this[PRIVATE$15].dispatchInputSourceEvent('selectstart', evt.inputSource); - }; - device.addEventListener('@@webxr-polyfill/input-select-start', this[PRIVATE$15].onSelectStart); - this[PRIVATE$15].onSelectEnd = evt => { - if (evt.sessionId !== this[PRIVATE$15].id) { - return; - } - this[PRIVATE$15].dispatchInputSourceEvent('selectend', evt.inputSource); - this[PRIVATE$15].dispatchInputSourceEvent('select', evt.inputSource); - }; - device.addEventListener('@@webxr-polyfill/input-select-end', this[PRIVATE$15].onSelectEnd); - this[PRIVATE$15].onSqueezeStart = evt => { - if (evt.sessionId !== this[PRIVATE$15].id) { - return; - } - this[PRIVATE$15].dispatchInputSourceEvent('squeezestart', evt.inputSource); - }; - device.addEventListener('@@webxr-polyfill/input-squeeze-start', this[PRIVATE$15].onSqueezeStart); - this[PRIVATE$15].onSqueezeEnd = evt => { - if (evt.sessionId !== this[PRIVATE$15].id) { - return; - } - this[PRIVATE$15].dispatchInputSourceEvent('squeezeend', evt.inputSource); - this[PRIVATE$15].dispatchInputSourceEvent('squeeze', evt.inputSource); - }; - device.addEventListener('@@webxr-polyfill/input-squeeze-end', this[PRIVATE$15].onSqueezeEnd); - this[PRIVATE$15].dispatchInputSourceEvent = (type, inputSource) => { - const frame = new XRFrame(device, this, this[PRIVATE$15].id); - const event = new XRInputSourceEvent(type, { frame, inputSource }); - frame[PRIVATE$9].active = true; - this.dispatchEvent(type, event); - frame[PRIVATE$9].active = false; - }; - this[PRIVATE$15].startDeviceFrameLoop(); - this.onblur = undefined; - this.onfocus = undefined; - this.onresetpose = undefined; - this.onend = undefined; - this.onselect = undefined; - this.onselectstart = undefined; - this.onselectend = undefined; - } - get renderState() { return this[PRIVATE$15].activeRenderState; } - get environmentBlendMode() { - return this[PRIVATE$15].device.environmentBlendMode || 'opaque'; - } - async requestReferenceSpace(type) { - if (this[PRIVATE$15].ended) { - return; - } - if (!XRReferenceSpaceTypes.includes(type)) { - throw new TypeError(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`); - } - if (!this[PRIVATE$15].device.doesSessionSupportReferenceSpace(this[PRIVATE$15].id, type)) { - throw new DOMException(`The ${type} reference space is not supported by this session.`, 'NotSupportedError'); - } - if (type === 'viewer') { - return this[PRIVATE$15].viewerSpace; - } - let transform = await this[PRIVATE$15].device.requestFrameOfReferenceTransform(type); - if (type === 'bounded-floor') { - if (!transform) { - throw new DOMException(`${type} XRReferenceSpace not supported by this device.`, 'NotSupportedError'); - } - let bounds = this[PRIVATE$15].device.requestStageBounds(); - if (!bounds) { - throw new DOMException(`${type} XRReferenceSpace not supported by this device.`, 'NotSupportedError'); - } - throw new DOMException(`The WebXR polyfill does not support the ${type} reference space yet.`, 'NotSupportedError'); - } - return new XRReferenceSpace(type, transform); - } - requestAnimationFrame(callback) { - if (this[PRIVATE$15].ended) { - return; - } - const handle = ++this[PRIVATE$15].frameHandle; - this[PRIVATE$15].frameCallbacks.push({ - handle, - callback, - cancelled: false - }); - return handle; - } - cancelAnimationFrame(handle) { - let callbacks = this[PRIVATE$15].frameCallbacks; - let index = callbacks.findIndex(d => d && d.handle === handle); - if (index > -1) { - callbacks[index].cancelled = true; - callbacks.splice(index, 1); - } - callbacks = this[PRIVATE$15].currentFrameCallbacks; - if (callbacks) { - index = callbacks.findIndex(d => d && d.handle === handle); - if (index > -1) { - callbacks[index].cancelled = true; - } - } - } - get inputSources() { - return this[PRIVATE$15].device.getInputSources(); - } - async end() { - if (this[PRIVATE$15].ended) { - return; - } - if (this[PRIVATE$15].immersive) { - this[PRIVATE$15].ended = true; - this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/vr-present-start', - this[PRIVATE$15].onPresentationStart); - this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/vr-present-end', - this[PRIVATE$15].onPresentationEnd); - this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/input-select-start', - this[PRIVATE$15].onSelectStart); - this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/input-select-end', - this[PRIVATE$15].onSelectEnd); - this.dispatchEvent('end', new XRSessionEvent('end', { session: this })); - } - this[PRIVATE$15].stopDeviceFrameLoop(); - return this[PRIVATE$15].device.endSession(this[PRIVATE$15].id); - } - updateRenderState(newState) { - if (this[PRIVATE$15].ended) { - const message = "Can't call updateRenderState on an XRSession " + - "that has already ended."; - throw new Error(message); - } - if (newState.baseLayer && (newState.baseLayer._session !== this)) { - const message = "Called updateRenderState with a base layer that was " + - "created by a different session."; - throw new Error(message); - } - const fovSet = (newState.inlineVerticalFieldOfView !== null) && - (newState.inlineVerticalFieldOfView !== undefined); - if (fovSet) { - if (this[PRIVATE$15].immersive) { - const message = "inlineVerticalFieldOfView must not be set for an " + - "XRRenderState passed to updateRenderState for an " + - "immersive session."; - throw new Error(message); - } else { - newState.inlineVerticalFieldOfView = Math.min( - 3.13, Math.max(0.01, newState.inlineVerticalFieldOfView)); - } - } - if (this[PRIVATE$15].pendingRenderState === null) { - const activeRenderState = this[PRIVATE$15].activeRenderState; - this[PRIVATE$15].pendingRenderState = { - depthNear: activeRenderState.depthNear, - depthFar: activeRenderState.depthFar, - inlineVerticalFieldOfView: activeRenderState.inlineVerticalFieldOfView, - baseLayer: activeRenderState.baseLayer - }; - } - Object.assign(this[PRIVATE$15].pendingRenderState, newState); - } - _checkInputSourcesChange() { - const added = []; - const removed = []; - const newInputSources = this.inputSources; - const oldInputSources = this[PRIVATE$15].currentInputSources; - for (const newInputSource of newInputSources) { - if (!oldInputSources.includes(newInputSource)) { - added.push(newInputSource); - } - } - for (const oldInputSource of oldInputSources) { - if (!newInputSources.includes(oldInputSource)) { - removed.push(oldInputSource); - } - } - if (added.length > 0 || removed.length > 0) { - this.dispatchEvent('inputsourceschange', new XRInputSourcesChangeEvent('inputsourceschange', { - session: this, - added: added, - removed: removed - })); - } - this[PRIVATE$15].currentInputSources.length = 0; - for (const newInputSource of newInputSources) { - this[PRIVATE$15].currentInputSources.push(newInputSource); - } - } -} - -const PRIVATE$16 = Symbol('@@webxr-polyfill/XRInputSource'); -class XRInputSource { - constructor(impl) { - this[PRIVATE$16] = { - impl, - gripSpace: new XRSpace("grip", this), - targetRaySpace: new XRSpace("target-ray", this) - }; - } - get handedness() { return this[PRIVATE$16].impl.handedness; } - get targetRayMode() { return this[PRIVATE$16].impl.targetRayMode; } - get gripSpace() { - let mode = this[PRIVATE$16].impl.targetRayMode; - if (mode === "gaze" || mode === "screen") { - return null; - } - return this[PRIVATE$16].gripSpace; - } - get targetRaySpace() { return this[PRIVATE$16].targetRaySpace; } - get profiles() { return this[PRIVATE$16].impl.profiles; } - get gamepad() { return this[PRIVATE$16].impl.gamepad; } -} - -const PRIVATE$17 = Symbol('@@webxr-polyfill/XRReferenceSpaceEvent'); -class XRReferenceSpaceEvent extends Event { - constructor(type, eventInitDict) { - super(type, eventInitDict); - this[PRIVATE$17] = { - referenceSpace: eventInitDict.referenceSpace, - transform: eventInitDict.transform || null - }; - } - get referenceSpace() { return this[PRIVATE$17].referenceSpace; } - get transform() { return this[PRIVATE$17].transform; } -} - -var API = { - XR, - XRSession: XRSession$1, - XRSessionEvent, - XRFrame, - XRView, - XRViewport, - XRViewerPose, - XRWebGLLayer, - XRSpace, - XRReferenceSpace, - XRReferenceSpaceEvent, - XRInputSource, - XRInputSourceEvent, - XRInputSourcesChangeEvent, - XRRenderState, - XRRigidTransform: XRRigidTransform$1, - XRPose: XRPose$1, -}; - -const polyfillMakeXRCompatible = Context => { - if (typeof Context.prototype.makeXRCompatible === 'function') { - return false; - } - Context.prototype.makeXRCompatible = function () { - this[XR_COMPATIBLE] = true; - return Promise.resolve(); - }; - return true; -}; -const polyfillGetContext = (Canvas) => { - const getContext = Canvas.prototype.getContext; - Canvas.prototype.getContext = function (contextType, glAttribs) { - const ctx = getContext.call(this, contextType, glAttribs); - if (ctx) { - ctx[POLYFILLED_XR_COMPATIBLE] = true; - if (glAttribs && ('xrCompatible' in glAttribs)) { - ctx[XR_COMPATIBLE] = glAttribs.xrCompatible; - } - } - return ctx; - }; -}; - -const isImageBitmapSupported = global => - !!(global.ImageBitmapRenderingContext && - global.createImageBitmap); -const isMobile = global => { - var check = false; - (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true;})(global.navigator.userAgent||global.navigator.vendor||global.opera); - return check; -}; -const applyCanvasStylesForMinimalRendering = canvas => { - canvas.style.display = 'block'; - canvas.style.position = 'absolute'; - canvas.style.width = canvas.style.height = '1px'; - canvas.style.top = canvas.style.left = '0px'; -}; - -var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - - - -function unwrapExports (x) { - return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; -} - -function createCommonjsModule(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; -} - -var cardboardVrDisplay = createCommonjsModule(function (module, exports) { -(function (global, factory) { - module.exports = factory(); -}(commonjsGlobal, (function () { var classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -}; -var createClass = function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; -}(); -var slicedToArray = function () { - function sliceIterator(arr, i) { - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"]) _i["return"](); - } finally { - if (_d) throw _e; - } - } - return _arr; - } - return function (arr, i) { - if (Array.isArray(arr)) { - return arr; - } else if (Symbol.iterator in Object(arr)) { - return sliceIterator(arr, i); - } else { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - }; -}(); -var MIN_TIMESTEP = 0.001; -var MAX_TIMESTEP = 1; -var dataUri = function dataUri(mimeType, svg) { - return 'data:' + mimeType + ',' + encodeURIComponent(svg); -}; -var lerp = function lerp(a, b, t) { - return a + (b - a) * t; -}; -var isIOS = function () { - var isIOS = /iPad|iPhone|iPod/.test(navigator.platform); - return function () { - return isIOS; - }; -}(); -var isWebViewAndroid = function () { - var isWebViewAndroid = navigator.userAgent.indexOf('Version') !== -1 && navigator.userAgent.indexOf('Android') !== -1 && navigator.userAgent.indexOf('Chrome') !== -1; - return function () { - return isWebViewAndroid; - }; -}(); -var isSafari = function () { - var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); - return function () { - return isSafari; - }; -}(); -var isFirefoxAndroid = function () { - var isFirefoxAndroid = navigator.userAgent.indexOf('Firefox') !== -1 && navigator.userAgent.indexOf('Android') !== -1; - return function () { - return isFirefoxAndroid; - }; -}(); -var getChromeVersion = function () { - var match = navigator.userAgent.match(/.*Chrome\/([0-9]+)/); - var value = match ? parseInt(match[1], 10) : null; - return function () { - return value; - }; -}(); -var isChromeWithoutDeviceMotion = function () { - var value = false; - if (getChromeVersion() === 65) { - var match = navigator.userAgent.match(/.*Chrome\/([0-9\.]*)/); - if (match) { - var _match$1$split = match[1].split('.'), - _match$1$split2 = slicedToArray(_match$1$split, 4), - major = _match$1$split2[0], - minor = _match$1$split2[1], - branch = _match$1$split2[2], - build = _match$1$split2[3]; - value = parseInt(branch, 10) === 3325 && parseInt(build, 10) < 148; - } - } - return function () { - return value; - }; -}(); -var isR7 = function () { - var isR7 = navigator.userAgent.indexOf('R7 Build') !== -1; - return function () { - return isR7; - }; -}(); -var isLandscapeMode = function isLandscapeMode() { - var rtn = window.orientation == 90 || window.orientation == -90; - return isR7() ? !rtn : rtn; -}; -var isTimestampDeltaValid = function isTimestampDeltaValid(timestampDeltaS) { - if (isNaN(timestampDeltaS)) { - return false; - } - if (timestampDeltaS <= MIN_TIMESTEP) { - return false; - } - if (timestampDeltaS > MAX_TIMESTEP) { - return false; - } - return true; -}; -var getScreenWidth = function getScreenWidth() { - return Math.max(window.screen.width, window.screen.height) * window.devicePixelRatio; -}; -var getScreenHeight = function getScreenHeight() { - return Math.min(window.screen.width, window.screen.height) * window.devicePixelRatio; -}; -var requestFullscreen = function requestFullscreen(element) { - if (isWebViewAndroid()) { - return false; - } - if (element.requestFullscreen) { - element.requestFullscreen(); - } else if (element.webkitRequestFullscreen) { - element.webkitRequestFullscreen(); - } else if (element.mozRequestFullScreen) { - element.mozRequestFullScreen(); - } else if (element.msRequestFullscreen) { - element.msRequestFullscreen(); - } else { - return false; - } - return true; -}; -var exitFullscreen = function exitFullscreen() { - if (document.exitFullscreen) { - document.exitFullscreen(); - } else if (document.webkitExitFullscreen) { - document.webkitExitFullscreen(); - } else if (document.mozCancelFullScreen) { - document.mozCancelFullScreen(); - } else if (document.msExitFullscreen) { - document.msExitFullscreen(); - } else { - return false; - } - return true; -}; -var getFullscreenElement = function getFullscreenElement() { - return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement; -}; -var linkProgram = function linkProgram(gl, vertexSource, fragmentSource, attribLocationMap) { - var vertexShader = gl.createShader(gl.VERTEX_SHADER); - gl.shaderSource(vertexShader, vertexSource); - gl.compileShader(vertexShader); - var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); - gl.shaderSource(fragmentShader, fragmentSource); - gl.compileShader(fragmentShader); - var program = gl.createProgram(); - gl.attachShader(program, vertexShader); - gl.attachShader(program, fragmentShader); - for (var attribName in attribLocationMap) { - gl.bindAttribLocation(program, attribLocationMap[attribName], attribName); - }gl.linkProgram(program); - gl.deleteShader(vertexShader); - gl.deleteShader(fragmentShader); - return program; -}; -var getProgramUniforms = function getProgramUniforms(gl, program) { - var uniforms = {}; - var uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); - var uniformName = ''; - for (var i = 0; i < uniformCount; i++) { - var uniformInfo = gl.getActiveUniform(program, i); - uniformName = uniformInfo.name.replace('[0]', ''); - uniforms[uniformName] = gl.getUniformLocation(program, uniformName); - } - return uniforms; -}; -var orthoMatrix = function orthoMatrix(out, left, right, bottom, top, near, far) { - var lr = 1 / (left - right), - bt = 1 / (bottom - top), - nf = 1 / (near - far); - out[0] = -2 * lr; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = -2 * bt; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 2 * nf; - out[11] = 0; - out[12] = (left + right) * lr; - out[13] = (top + bottom) * bt; - out[14] = (far + near) * nf; - out[15] = 1; - return out; -}; -var isMobile = function isMobile() { - var check = false; - (function (a) { - if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true; - })(navigator.userAgent || navigator.vendor || window.opera); - return check; -}; -var extend = function extend(dest, src) { - for (var key in src) { - if (src.hasOwnProperty(key)) { - dest[key] = src[key]; - } - } - return dest; -}; -var safariCssSizeWorkaround = function safariCssSizeWorkaround(canvas) { - if (isIOS()) { - var width = canvas.style.width; - var height = canvas.style.height; - canvas.style.width = parseInt(width) + 1 + 'px'; - canvas.style.height = parseInt(height) + 'px'; - setTimeout(function () { - canvas.style.width = width; - canvas.style.height = height; - }, 100); - } - window.canvas = canvas; -}; -var frameDataFromPose = function () { - var piOver180 = Math.PI / 180.0; - var rad45 = Math.PI * 0.25; - function mat4_perspectiveFromFieldOfView(out, fov, near, far) { - var upTan = Math.tan(fov ? fov.upDegrees * piOver180 : rad45), - downTan = Math.tan(fov ? fov.downDegrees * piOver180 : rad45), - leftTan = Math.tan(fov ? fov.leftDegrees * piOver180 : rad45), - rightTan = Math.tan(fov ? fov.rightDegrees * piOver180 : rad45), - xScale = 2.0 / (leftTan + rightTan), - yScale = 2.0 / (upTan + downTan); - out[0] = xScale; - out[1] = 0.0; - out[2] = 0.0; - out[3] = 0.0; - out[4] = 0.0; - out[5] = yScale; - out[6] = 0.0; - out[7] = 0.0; - out[8] = -((leftTan - rightTan) * xScale * 0.5); - out[9] = (upTan - downTan) * yScale * 0.5; - out[10] = far / (near - far); - out[11] = -1.0; - out[12] = 0.0; - out[13] = 0.0; - out[14] = far * near / (near - far); - out[15] = 0.0; - return out; - } - function mat4_fromRotationTranslation(out, q, v) { - var x = q[0], - y = q[1], - z = q[2], - w = q[3], - x2 = x + x, - y2 = y + y, - z2 = z + z, - xx = x * x2, - xy = x * y2, - xz = x * z2, - yy = y * y2, - yz = y * z2, - zz = z * z2, - wx = w * x2, - wy = w * y2, - wz = w * z2; - out[0] = 1 - (yy + zz); - out[1] = xy + wz; - out[2] = xz - wy; - out[3] = 0; - out[4] = xy - wz; - out[5] = 1 - (xx + zz); - out[6] = yz + wx; - out[7] = 0; - out[8] = xz + wy; - out[9] = yz - wx; - out[10] = 1 - (xx + yy); - out[11] = 0; - out[12] = v[0]; - out[13] = v[1]; - out[14] = v[2]; - out[15] = 1; - return out; - } - function mat4_translate(out, a, v) { - var x = v[0], - y = v[1], - z = v[2], - a00, - a01, - a02, - a03, - a10, - a11, - a12, - a13, - a20, - a21, - a22, - a23; - if (a === out) { - out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; - out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; - out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; - out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; - } else { - a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3]; - a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7]; - a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11]; - out[0] = a00;out[1] = a01;out[2] = a02;out[3] = a03; - out[4] = a10;out[5] = a11;out[6] = a12;out[7] = a13; - out[8] = a20;out[9] = a21;out[10] = a22;out[11] = a23; - out[12] = a00 * x + a10 * y + a20 * z + a[12]; - out[13] = a01 * x + a11 * y + a21 * z + a[13]; - out[14] = a02 * x + a12 * y + a22 * z + a[14]; - out[15] = a03 * x + a13 * y + a23 * z + a[15]; - } - return out; - } - function mat4_invert(out, a) { - var a00 = a[0], - a01 = a[1], - a02 = a[2], - a03 = a[3], - a10 = a[4], - a11 = a[5], - a12 = a[6], - a13 = a[7], - a20 = a[8], - a21 = a[9], - a22 = a[10], - a23 = a[11], - a30 = a[12], - a31 = a[13], - a32 = a[14], - a33 = a[15], - b00 = a00 * a11 - a01 * a10, - b01 = a00 * a12 - a02 * a10, - b02 = a00 * a13 - a03 * a10, - b03 = a01 * a12 - a02 * a11, - b04 = a01 * a13 - a03 * a11, - b05 = a02 * a13 - a03 * a12, - b06 = a20 * a31 - a21 * a30, - b07 = a20 * a32 - a22 * a30, - b08 = a20 * a33 - a23 * a30, - b09 = a21 * a32 - a22 * a31, - b10 = a21 * a33 - a23 * a31, - b11 = a22 * a33 - a23 * a32, - det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; - if (!det) { - return null; - } - det = 1.0 / det; - out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; - out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; - out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; - out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; - out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; - out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; - out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; - out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; - out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; - out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; - out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; - out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; - out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; - out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; - out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; - out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; - return out; - } - var defaultOrientation = new Float32Array([0, 0, 0, 1]); - var defaultPosition = new Float32Array([0, 0, 0]); - function updateEyeMatrices(projection, view, pose, fov, offset, vrDisplay) { - mat4_perspectiveFromFieldOfView(projection, fov || null, vrDisplay.depthNear, vrDisplay.depthFar); - var orientation = pose.orientation || defaultOrientation; - var position = pose.position || defaultPosition; - mat4_fromRotationTranslation(view, orientation, position); - if (offset) mat4_translate(view, view, offset); - mat4_invert(view, view); - } - return function (frameData, pose, vrDisplay) { - if (!frameData || !pose) return false; - frameData.pose = pose; - frameData.timestamp = pose.timestamp; - updateEyeMatrices(frameData.leftProjectionMatrix, frameData.leftViewMatrix, pose, vrDisplay._getFieldOfView("left"), vrDisplay._getEyeOffset("left"), vrDisplay); - updateEyeMatrices(frameData.rightProjectionMatrix, frameData.rightViewMatrix, pose, vrDisplay._getFieldOfView("right"), vrDisplay._getEyeOffset("right"), vrDisplay); - return true; - }; -}(); -var isInsideCrossOriginIFrame = function isInsideCrossOriginIFrame() { - var isFramed = window.self !== window.top; - var refOrigin = getOriginFromUrl(document.referrer); - var thisOrigin = getOriginFromUrl(window.location.href); - return isFramed && refOrigin !== thisOrigin; -}; -var getOriginFromUrl = function getOriginFromUrl(url) { - var domainIdx; - var protoSepIdx = url.indexOf("://"); - if (protoSepIdx !== -1) { - domainIdx = protoSepIdx + 3; - } else { - domainIdx = 0; - } - var domainEndIdx = url.indexOf('/', domainIdx); - if (domainEndIdx === -1) { - domainEndIdx = url.length; - } - return url.substring(0, domainEndIdx); -}; -var getQuaternionAngle = function getQuaternionAngle(quat) { - if (quat.w > 1) { - console.warn('getQuaternionAngle: w > 1'); - return 0; - } - var angle = 2 * Math.acos(quat.w); - return angle; -}; -var warnOnce = function () { - var observedWarnings = {}; - return function (key, message) { - if (observedWarnings[key] === undefined) { - console.warn('webvr-polyfill: ' + message); - observedWarnings[key] = true; - } - }; -}(); -var deprecateWarning = function deprecateWarning(deprecated, suggested) { - var alternative = suggested ? 'Please use ' + suggested + ' instead.' : ''; - warnOnce(deprecated, deprecated + ' has been deprecated. ' + 'This may not work on native WebVR displays. ' + alternative); -}; -function WGLUPreserveGLState(gl, bindings, callback) { - if (!bindings) { - callback(gl); - return; - } - var boundValues = []; - var activeTexture = null; - for (var i = 0; i < bindings.length; ++i) { - var binding = bindings[i]; - switch (binding) { - case gl.TEXTURE_BINDING_2D: - case gl.TEXTURE_BINDING_CUBE_MAP: - var textureUnit = bindings[++i]; - if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) { - console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit"); - boundValues.push(null, null); - break; - } - if (!activeTexture) { - activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE); - } - gl.activeTexture(textureUnit); - boundValues.push(gl.getParameter(binding), null); - break; - case gl.ACTIVE_TEXTURE: - activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE); - boundValues.push(null); - break; - default: - boundValues.push(gl.getParameter(binding)); - break; - } - } - callback(gl); - for (var i = 0; i < bindings.length; ++i) { - var binding = bindings[i]; - var boundValue = boundValues[i]; - switch (binding) { - case gl.ACTIVE_TEXTURE: - break; - case gl.ARRAY_BUFFER_BINDING: - gl.bindBuffer(gl.ARRAY_BUFFER, boundValue); - break; - case gl.COLOR_CLEAR_VALUE: - gl.clearColor(boundValue[0], boundValue[1], boundValue[2], boundValue[3]); - break; - case gl.COLOR_WRITEMASK: - gl.colorMask(boundValue[0], boundValue[1], boundValue[2], boundValue[3]); - break; - case gl.CURRENT_PROGRAM: - gl.useProgram(boundValue); - break; - case gl.ELEMENT_ARRAY_BUFFER_BINDING: - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boundValue); - break; - case gl.FRAMEBUFFER_BINDING: - gl.bindFramebuffer(gl.FRAMEBUFFER, boundValue); - break; - case gl.RENDERBUFFER_BINDING: - gl.bindRenderbuffer(gl.RENDERBUFFER, boundValue); - break; - case gl.TEXTURE_BINDING_2D: - var textureUnit = bindings[++i]; - if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) - break; - gl.activeTexture(textureUnit); - gl.bindTexture(gl.TEXTURE_2D, boundValue); - break; - case gl.TEXTURE_BINDING_CUBE_MAP: - var textureUnit = bindings[++i]; - if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) - break; - gl.activeTexture(textureUnit); - gl.bindTexture(gl.TEXTURE_CUBE_MAP, boundValue); - break; - case gl.VIEWPORT: - gl.viewport(boundValue[0], boundValue[1], boundValue[2], boundValue[3]); - break; - case gl.BLEND: - case gl.CULL_FACE: - case gl.DEPTH_TEST: - case gl.SCISSOR_TEST: - case gl.STENCIL_TEST: - if (boundValue) { - gl.enable(binding); - } else { - gl.disable(binding); - } - break; - default: - console.log("No GL restore behavior for 0x" + binding.toString(16)); - break; - } - if (activeTexture) { - gl.activeTexture(activeTexture); - } - } -} -var glPreserveState = WGLUPreserveGLState; -var distortionVS = ['attribute vec2 position;', 'attribute vec3 texCoord;', 'varying vec2 vTexCoord;', 'uniform vec4 viewportOffsetScale[2];', 'void main() {', ' vec4 viewport = viewportOffsetScale[int(texCoord.z)];', ' vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;', ' gl_Position = vec4( position, 1.0, 1.0 );', '}'].join('\n'); -var distortionFS = ['precision mediump float;', 'uniform sampler2D diffuse;', 'varying vec2 vTexCoord;', 'void main() {', ' gl_FragColor = texture2D(diffuse, vTexCoord);', '}'].join('\n'); -function CardboardDistorter(gl, cardboardUI, bufferScale, dirtySubmitFrameBindings) { - this.gl = gl; - this.cardboardUI = cardboardUI; - this.bufferScale = bufferScale; - this.dirtySubmitFrameBindings = dirtySubmitFrameBindings; - this.ctxAttribs = gl.getContextAttributes(); - this.meshWidth = 20; - this.meshHeight = 20; - this.bufferWidth = gl.drawingBufferWidth; - this.bufferHeight = gl.drawingBufferHeight; - this.realBindFramebuffer = gl.bindFramebuffer; - this.realEnable = gl.enable; - this.realDisable = gl.disable; - this.realColorMask = gl.colorMask; - this.realClearColor = gl.clearColor; - this.realViewport = gl.viewport; - if (!isIOS()) { - this.realCanvasWidth = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'width'); - this.realCanvasHeight = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'height'); - } - this.isPatched = false; - this.lastBoundFramebuffer = null; - this.cullFace = false; - this.depthTest = false; - this.blend = false; - this.scissorTest = false; - this.stencilTest = false; - this.viewport = [0, 0, 0, 0]; - this.colorMask = [true, true, true, true]; - this.clearColor = [0, 0, 0, 0]; - this.attribs = { - position: 0, - texCoord: 1 - }; - this.program = linkProgram(gl, distortionVS, distortionFS, this.attribs); - this.uniforms = getProgramUniforms(gl, this.program); - this.viewportOffsetScale = new Float32Array(8); - this.setTextureBounds(); - this.vertexBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - this.indexCount = 0; - this.renderTarget = gl.createTexture(); - this.framebuffer = gl.createFramebuffer(); - this.depthStencilBuffer = null; - this.depthBuffer = null; - this.stencilBuffer = null; - if (this.ctxAttribs.depth && this.ctxAttribs.stencil) { - this.depthStencilBuffer = gl.createRenderbuffer(); - } else if (this.ctxAttribs.depth) { - this.depthBuffer = gl.createRenderbuffer(); - } else if (this.ctxAttribs.stencil) { - this.stencilBuffer = gl.createRenderbuffer(); - } - this.patch(); - this.onResize(); -} -CardboardDistorter.prototype.destroy = function () { - var gl = this.gl; - this.unpatch(); - gl.deleteProgram(this.program); - gl.deleteBuffer(this.vertexBuffer); - gl.deleteBuffer(this.indexBuffer); - gl.deleteTexture(this.renderTarget); - gl.deleteFramebuffer(this.framebuffer); - if (this.depthStencilBuffer) { - gl.deleteRenderbuffer(this.depthStencilBuffer); - } - if (this.depthBuffer) { - gl.deleteRenderbuffer(this.depthBuffer); - } - if (this.stencilBuffer) { - gl.deleteRenderbuffer(this.stencilBuffer); - } - if (this.cardboardUI) { - this.cardboardUI.destroy(); - } -}; -CardboardDistorter.prototype.onResize = function () { - var gl = this.gl; - var self = this; - var glState = [gl.RENDERBUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0]; - glPreserveState(gl, glState, function (gl) { - self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null); - if (self.scissorTest) { - self.realDisable.call(gl, gl.SCISSOR_TEST); - } - self.realColorMask.call(gl, true, true, true, true); - self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - self.realClearColor.call(gl, 0, 0, 0, 1); - gl.clear(gl.COLOR_BUFFER_BIT); - self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.framebuffer); - gl.bindTexture(gl.TEXTURE_2D, self.renderTarget); - gl.texImage2D(gl.TEXTURE_2D, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, self.bufferWidth, self.bufferHeight, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, gl.UNSIGNED_BYTE, null); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, self.renderTarget, 0); - if (self.ctxAttribs.depth && self.ctxAttribs.stencil) { - gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthStencilBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, self.bufferWidth, self.bufferHeight); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.depthStencilBuffer); - } else if (self.ctxAttribs.depth) { - gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, self.bufferWidth, self.bufferHeight); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, self.depthBuffer); - } else if (self.ctxAttribs.stencil) { - gl.bindRenderbuffer(gl.RENDERBUFFER, self.stencilBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, self.bufferWidth, self.bufferHeight); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.stencilBuffer); - } - if (!gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) { - console.error('Framebuffer incomplete!'); - } - self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer); - if (self.scissorTest) { - self.realEnable.call(gl, gl.SCISSOR_TEST); - } - self.realColorMask.apply(gl, self.colorMask); - self.realViewport.apply(gl, self.viewport); - self.realClearColor.apply(gl, self.clearColor); - }); - if (this.cardboardUI) { - this.cardboardUI.onResize(); - } -}; -CardboardDistorter.prototype.patch = function () { - if (this.isPatched) { - return; - } - var self = this; - var canvas = this.gl.canvas; - var gl = this.gl; - if (!isIOS()) { - canvas.width = getScreenWidth() * this.bufferScale; - canvas.height = getScreenHeight() * this.bufferScale; - Object.defineProperty(canvas, 'width', { - configurable: true, - enumerable: true, - get: function get() { - return self.bufferWidth; - }, - set: function set(value) { - self.bufferWidth = value; - self.realCanvasWidth.set.call(canvas, value); - self.onResize(); - } - }); - Object.defineProperty(canvas, 'height', { - configurable: true, - enumerable: true, - get: function get() { - return self.bufferHeight; - }, - set: function set(value) { - self.bufferHeight = value; - self.realCanvasHeight.set.call(canvas, value); - self.onResize(); - } - }); - } - this.lastBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING); - if (this.lastBoundFramebuffer == null) { - this.lastBoundFramebuffer = this.framebuffer; - this.gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer); - } - this.gl.bindFramebuffer = function (target, framebuffer) { - self.lastBoundFramebuffer = framebuffer ? framebuffer : self.framebuffer; - self.realBindFramebuffer.call(gl, target, self.lastBoundFramebuffer); - }; - this.cullFace = gl.getParameter(gl.CULL_FACE); - this.depthTest = gl.getParameter(gl.DEPTH_TEST); - this.blend = gl.getParameter(gl.BLEND); - this.scissorTest = gl.getParameter(gl.SCISSOR_TEST); - this.stencilTest = gl.getParameter(gl.STENCIL_TEST); - gl.enable = function (pname) { - switch (pname) { - case gl.CULL_FACE: - self.cullFace = true;break; - case gl.DEPTH_TEST: - self.depthTest = true;break; - case gl.BLEND: - self.blend = true;break; - case gl.SCISSOR_TEST: - self.scissorTest = true;break; - case gl.STENCIL_TEST: - self.stencilTest = true;break; - } - self.realEnable.call(gl, pname); - }; - gl.disable = function (pname) { - switch (pname) { - case gl.CULL_FACE: - self.cullFace = false;break; - case gl.DEPTH_TEST: - self.depthTest = false;break; - case gl.BLEND: - self.blend = false;break; - case gl.SCISSOR_TEST: - self.scissorTest = false;break; - case gl.STENCIL_TEST: - self.stencilTest = false;break; - } - self.realDisable.call(gl, pname); - }; - this.colorMask = gl.getParameter(gl.COLOR_WRITEMASK); - gl.colorMask = function (r, g, b, a) { - self.colorMask[0] = r; - self.colorMask[1] = g; - self.colorMask[2] = b; - self.colorMask[3] = a; - self.realColorMask.call(gl, r, g, b, a); - }; - this.clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE); - gl.clearColor = function (r, g, b, a) { - self.clearColor[0] = r; - self.clearColor[1] = g; - self.clearColor[2] = b; - self.clearColor[3] = a; - self.realClearColor.call(gl, r, g, b, a); - }; - this.viewport = gl.getParameter(gl.VIEWPORT); - gl.viewport = function (x, y, w, h) { - self.viewport[0] = x; - self.viewport[1] = y; - self.viewport[2] = w; - self.viewport[3] = h; - self.realViewport.call(gl, x, y, w, h); - }; - this.isPatched = true; - safariCssSizeWorkaround(canvas); -}; -CardboardDistorter.prototype.unpatch = function () { - if (!this.isPatched) { - return; - } - var gl = this.gl; - var canvas = this.gl.canvas; - if (!isIOS()) { - Object.defineProperty(canvas, 'width', this.realCanvasWidth); - Object.defineProperty(canvas, 'height', this.realCanvasHeight); - } - canvas.width = this.bufferWidth; - canvas.height = this.bufferHeight; - gl.bindFramebuffer = this.realBindFramebuffer; - gl.enable = this.realEnable; - gl.disable = this.realDisable; - gl.colorMask = this.realColorMask; - gl.clearColor = this.realClearColor; - gl.viewport = this.realViewport; - if (this.lastBoundFramebuffer == this.framebuffer) { - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - } - this.isPatched = false; - setTimeout(function () { - safariCssSizeWorkaround(canvas); - }, 1); -}; -CardboardDistorter.prototype.setTextureBounds = function (leftBounds, rightBounds) { - if (!leftBounds) { - leftBounds = [0, 0, 0.5, 1]; - } - if (!rightBounds) { - rightBounds = [0.5, 0, 0.5, 1]; - } - this.viewportOffsetScale[0] = leftBounds[0]; - this.viewportOffsetScale[1] = leftBounds[1]; - this.viewportOffsetScale[2] = leftBounds[2]; - this.viewportOffsetScale[3] = leftBounds[3]; - this.viewportOffsetScale[4] = rightBounds[0]; - this.viewportOffsetScale[5] = rightBounds[1]; - this.viewportOffsetScale[6] = rightBounds[2]; - this.viewportOffsetScale[7] = rightBounds[3]; -}; -CardboardDistorter.prototype.submitFrame = function () { - var gl = this.gl; - var self = this; - var glState = []; - if (!this.dirtySubmitFrameBindings) { - glState.push(gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0); - } - glPreserveState(gl, glState, function (gl) { - self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null); - if (self.cullFace) { - self.realDisable.call(gl, gl.CULL_FACE); - } - if (self.depthTest) { - self.realDisable.call(gl, gl.DEPTH_TEST); - } - if (self.blend) { - self.realDisable.call(gl, gl.BLEND); - } - if (self.scissorTest) { - self.realDisable.call(gl, gl.SCISSOR_TEST); - } - if (self.stencilTest) { - self.realDisable.call(gl, gl.STENCIL_TEST); - } - self.realColorMask.call(gl, true, true, true, true); - self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - if (self.ctxAttribs.alpha || isIOS()) { - self.realClearColor.call(gl, 0, 0, 0, 1); - gl.clear(gl.COLOR_BUFFER_BIT); - } - gl.useProgram(self.program); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer); - gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer); - gl.enableVertexAttribArray(self.attribs.position); - gl.enableVertexAttribArray(self.attribs.texCoord); - gl.vertexAttribPointer(self.attribs.position, 2, gl.FLOAT, false, 20, 0); - gl.vertexAttribPointer(self.attribs.texCoord, 3, gl.FLOAT, false, 20, 8); - gl.activeTexture(gl.TEXTURE0); - gl.uniform1i(self.uniforms.diffuse, 0); - gl.bindTexture(gl.TEXTURE_2D, self.renderTarget); - gl.uniform4fv(self.uniforms.viewportOffsetScale, self.viewportOffsetScale); - gl.drawElements(gl.TRIANGLES, self.indexCount, gl.UNSIGNED_SHORT, 0); - if (self.cardboardUI) { - self.cardboardUI.renderNoState(); - } - self.realBindFramebuffer.call(self.gl, gl.FRAMEBUFFER, self.framebuffer); - if (!self.ctxAttribs.preserveDrawingBuffer) { - self.realClearColor.call(gl, 0, 0, 0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - } - if (!self.dirtySubmitFrameBindings) { - self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer); - } - if (self.cullFace) { - self.realEnable.call(gl, gl.CULL_FACE); - } - if (self.depthTest) { - self.realEnable.call(gl, gl.DEPTH_TEST); - } - if (self.blend) { - self.realEnable.call(gl, gl.BLEND); - } - if (self.scissorTest) { - self.realEnable.call(gl, gl.SCISSOR_TEST); - } - if (self.stencilTest) { - self.realEnable.call(gl, gl.STENCIL_TEST); - } - self.realColorMask.apply(gl, self.colorMask); - self.realViewport.apply(gl, self.viewport); - if (self.ctxAttribs.alpha || !self.ctxAttribs.preserveDrawingBuffer) { - self.realClearColor.apply(gl, self.clearColor); - } - }); - if (isIOS()) { - var canvas = gl.canvas; - if (canvas.width != self.bufferWidth || canvas.height != self.bufferHeight) { - self.bufferWidth = canvas.width; - self.bufferHeight = canvas.height; - self.onResize(); - } - } -}; -CardboardDistorter.prototype.updateDeviceInfo = function (deviceInfo) { - var gl = this.gl; - var self = this; - var glState = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING]; - glPreserveState(gl, glState, function (gl) { - var vertices = self.computeMeshVertices_(self.meshWidth, self.meshHeight, deviceInfo); - gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); - if (!self.indexCount) { - var indices = self.computeMeshIndices_(self.meshWidth, self.meshHeight); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); - self.indexCount = indices.length; - } - }); -}; -CardboardDistorter.prototype.computeMeshVertices_ = function (width, height, deviceInfo) { - var vertices = new Float32Array(2 * width * height * 5); - var lensFrustum = deviceInfo.getLeftEyeVisibleTanAngles(); - var noLensFrustum = deviceInfo.getLeftEyeNoLensTanAngles(); - var viewport = deviceInfo.getLeftEyeVisibleScreenRect(noLensFrustum); - var vidx = 0; - for (var e = 0; e < 2; e++) { - for (var j = 0; j < height; j++) { - for (var i = 0; i < width; i++, vidx++) { - var u = i / (width - 1); - var v = j / (height - 1); - var s = u; - var t = v; - var x = lerp(lensFrustum[0], lensFrustum[2], u); - var y = lerp(lensFrustum[3], lensFrustum[1], v); - var d = Math.sqrt(x * x + y * y); - var r = deviceInfo.distortion.distortInverse(d); - var p = x * r / d; - var q = y * r / d; - u = (p - noLensFrustum[0]) / (noLensFrustum[2] - noLensFrustum[0]); - v = (q - noLensFrustum[3]) / (noLensFrustum[1] - noLensFrustum[3]); - u = (viewport.x + u * viewport.width - 0.5) * 2.0; - v = (viewport.y + v * viewport.height - 0.5) * 2.0; - vertices[vidx * 5 + 0] = u; - vertices[vidx * 5 + 1] = v; - vertices[vidx * 5 + 2] = s; - vertices[vidx * 5 + 3] = t; - vertices[vidx * 5 + 4] = e; - } - } - var w = lensFrustum[2] - lensFrustum[0]; - lensFrustum[0] = -(w + lensFrustum[0]); - lensFrustum[2] = w - lensFrustum[2]; - w = noLensFrustum[2] - noLensFrustum[0]; - noLensFrustum[0] = -(w + noLensFrustum[0]); - noLensFrustum[2] = w - noLensFrustum[2]; - viewport.x = 1 - (viewport.x + viewport.width); - } - return vertices; -}; -CardboardDistorter.prototype.computeMeshIndices_ = function (width, height) { - var indices = new Uint16Array(2 * (width - 1) * (height - 1) * 6); - var halfwidth = width / 2; - var halfheight = height / 2; - var vidx = 0; - var iidx = 0; - for (var e = 0; e < 2; e++) { - for (var j = 0; j < height; j++) { - for (var i = 0; i < width; i++, vidx++) { - if (i == 0 || j == 0) continue; - if (i <= halfwidth == j <= halfheight) { - indices[iidx++] = vidx; - indices[iidx++] = vidx - width - 1; - indices[iidx++] = vidx - width; - indices[iidx++] = vidx - width - 1; - indices[iidx++] = vidx; - indices[iidx++] = vidx - 1; - } else { - indices[iidx++] = vidx - 1; - indices[iidx++] = vidx - width; - indices[iidx++] = vidx; - indices[iidx++] = vidx - width; - indices[iidx++] = vidx - 1; - indices[iidx++] = vidx - width - 1; - } - } - } - } - return indices; -}; -CardboardDistorter.prototype.getOwnPropertyDescriptor_ = function (proto, attrName) { - var descriptor = Object.getOwnPropertyDescriptor(proto, attrName); - if (descriptor.get === undefined || descriptor.set === undefined) { - descriptor.configurable = true; - descriptor.enumerable = true; - descriptor.get = function () { - return this.getAttribute(attrName); - }; - descriptor.set = function (val) { - this.setAttribute(attrName, val); - }; - } - return descriptor; -}; -var uiVS = ['attribute vec2 position;', 'uniform mat4 projectionMat;', 'void main() {', ' gl_Position = projectionMat * vec4( position, -1.0, 1.0 );', '}'].join('\n'); -var uiFS = ['precision mediump float;', 'uniform vec4 color;', 'void main() {', ' gl_FragColor = color;', '}'].join('\n'); -var DEG2RAD = Math.PI / 180.0; -var kAnglePerGearSection = 60; -var kOuterRimEndAngle = 12; -var kInnerRimBeginAngle = 20; -var kOuterRadius = 1; -var kMiddleRadius = 0.75; -var kInnerRadius = 0.3125; -var kCenterLineThicknessDp = 4; -var kButtonWidthDp = 28; -var kTouchSlopFactor = 1.5; -function CardboardUI(gl) { - this.gl = gl; - this.attribs = { - position: 0 - }; - this.program = linkProgram(gl, uiVS, uiFS, this.attribs); - this.uniforms = getProgramUniforms(gl, this.program); - this.vertexBuffer = gl.createBuffer(); - this.gearOffset = 0; - this.gearVertexCount = 0; - this.arrowOffset = 0; - this.arrowVertexCount = 0; - this.projMat = new Float32Array(16); - this.listener = null; - this.onResize(); -} -CardboardUI.prototype.destroy = function () { - var gl = this.gl; - if (this.listener) { - gl.canvas.removeEventListener('click', this.listener, false); - } - gl.deleteProgram(this.program); - gl.deleteBuffer(this.vertexBuffer); -}; -CardboardUI.prototype.listen = function (optionsCallback, backCallback) { - var canvas = this.gl.canvas; - this.listener = function (event) { - var midline = canvas.clientWidth / 2; - var buttonSize = kButtonWidthDp * kTouchSlopFactor; - if (event.clientX > midline - buttonSize && event.clientX < midline + buttonSize && event.clientY > canvas.clientHeight - buttonSize) { - optionsCallback(event); - } - else if (event.clientX < buttonSize && event.clientY < buttonSize) { - backCallback(event); - } - }; - canvas.addEventListener('click', this.listener, false); -}; -CardboardUI.prototype.onResize = function () { - var gl = this.gl; - var self = this; - var glState = [gl.ARRAY_BUFFER_BINDING]; - glPreserveState(gl, glState, function (gl) { - var vertices = []; - var midline = gl.drawingBufferWidth / 2; - var physicalPixels = Math.max(screen.width, screen.height) * window.devicePixelRatio; - var scalingRatio = gl.drawingBufferWidth / physicalPixels; - var dps = scalingRatio * window.devicePixelRatio; - var lineWidth = kCenterLineThicknessDp * dps / 2; - var buttonSize = kButtonWidthDp * kTouchSlopFactor * dps; - var buttonScale = kButtonWidthDp * dps / 2; - var buttonBorder = (kButtonWidthDp * kTouchSlopFactor - kButtonWidthDp) * dps; - vertices.push(midline - lineWidth, buttonSize); - vertices.push(midline - lineWidth, gl.drawingBufferHeight); - vertices.push(midline + lineWidth, buttonSize); - vertices.push(midline + lineWidth, gl.drawingBufferHeight); - self.gearOffset = vertices.length / 2; - function addGearSegment(theta, r) { - var angle = (90 - theta) * DEG2RAD; - var x = Math.cos(angle); - var y = Math.sin(angle); - vertices.push(kInnerRadius * x * buttonScale + midline, kInnerRadius * y * buttonScale + buttonScale); - vertices.push(r * x * buttonScale + midline, r * y * buttonScale + buttonScale); - } - for (var i = 0; i <= 6; i++) { - var segmentTheta = i * kAnglePerGearSection; - addGearSegment(segmentTheta, kOuterRadius); - addGearSegment(segmentTheta + kOuterRimEndAngle, kOuterRadius); - addGearSegment(segmentTheta + kInnerRimBeginAngle, kMiddleRadius); - addGearSegment(segmentTheta + (kAnglePerGearSection - kInnerRimBeginAngle), kMiddleRadius); - addGearSegment(segmentTheta + (kAnglePerGearSection - kOuterRimEndAngle), kOuterRadius); - } - self.gearVertexCount = vertices.length / 2 - self.gearOffset; - self.arrowOffset = vertices.length / 2; - function addArrowVertex(x, y) { - vertices.push(buttonBorder + x, gl.drawingBufferHeight - buttonBorder - y); - } - var angledLineWidth = lineWidth / Math.sin(45 * DEG2RAD); - addArrowVertex(0, buttonScale); - addArrowVertex(buttonScale, 0); - addArrowVertex(buttonScale + angledLineWidth, angledLineWidth); - addArrowVertex(angledLineWidth, buttonScale + angledLineWidth); - addArrowVertex(angledLineWidth, buttonScale - angledLineWidth); - addArrowVertex(0, buttonScale); - addArrowVertex(buttonScale, buttonScale * 2); - addArrowVertex(buttonScale + angledLineWidth, buttonScale * 2 - angledLineWidth); - addArrowVertex(angledLineWidth, buttonScale - angledLineWidth); - addArrowVertex(0, buttonScale); - addArrowVertex(angledLineWidth, buttonScale - lineWidth); - addArrowVertex(kButtonWidthDp * dps, buttonScale - lineWidth); - addArrowVertex(angledLineWidth, buttonScale + lineWidth); - addArrowVertex(kButtonWidthDp * dps, buttonScale + lineWidth); - self.arrowVertexCount = vertices.length / 2 - self.arrowOffset; - gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); - }); -}; -CardboardUI.prototype.render = function () { - var gl = this.gl; - var self = this; - var glState = [gl.CULL_FACE, gl.DEPTH_TEST, gl.BLEND, gl.SCISSOR_TEST, gl.STENCIL_TEST, gl.COLOR_WRITEMASK, gl.VIEWPORT, gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING]; - glPreserveState(gl, glState, function (gl) { - gl.disable(gl.CULL_FACE); - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.BLEND); - gl.disable(gl.SCISSOR_TEST); - gl.disable(gl.STENCIL_TEST); - gl.colorMask(true, true, true, true); - gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - self.renderNoState(); - }); -}; -CardboardUI.prototype.renderNoState = function () { - var gl = this.gl; - gl.useProgram(this.program); - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.enableVertexAttribArray(this.attribs.position); - gl.vertexAttribPointer(this.attribs.position, 2, gl.FLOAT, false, 8, 0); - gl.uniform4f(this.uniforms.color, 1.0, 1.0, 1.0, 1.0); - orthoMatrix(this.projMat, 0, gl.drawingBufferWidth, 0, gl.drawingBufferHeight, 0.1, 1024.0); - gl.uniformMatrix4fv(this.uniforms.projectionMat, false, this.projMat); - gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); - gl.drawArrays(gl.TRIANGLE_STRIP, this.gearOffset, this.gearVertexCount); - gl.drawArrays(gl.TRIANGLE_STRIP, this.arrowOffset, this.arrowVertexCount); -}; -function Distortion(coefficients) { - this.coefficients = coefficients; -} -Distortion.prototype.distortInverse = function (radius) { - var r0 = 0; - var r1 = 1; - var dr0 = radius - this.distort(r0); - while (Math.abs(r1 - r0) > 0.0001 ) { - var dr1 = radius - this.distort(r1); - var r2 = r1 - dr1 * ((r1 - r0) / (dr1 - dr0)); - r0 = r1; - r1 = r2; - dr0 = dr1; - } - return r1; -}; -Distortion.prototype.distort = function (radius) { - var r2 = radius * radius; - var ret = 0; - for (var i = 0; i < this.coefficients.length; i++) { - ret = r2 * (ret + this.coefficients[i]); - } - return (ret + 1) * radius; -}; -var degToRad = Math.PI / 180; -var radToDeg = 180 / Math.PI; -var Vector3 = function Vector3(x, y, z) { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; -}; -Vector3.prototype = { - constructor: Vector3, - set: function set(x, y, z) { - this.x = x; - this.y = y; - this.z = z; - return this; - }, - copy: function copy(v) { - this.x = v.x; - this.y = v.y; - this.z = v.z; - return this; - }, - length: function length() { - return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); - }, - normalize: function normalize() { - var scalar = this.length(); - if (scalar !== 0) { - var invScalar = 1 / scalar; - this.multiplyScalar(invScalar); - } else { - this.x = 0; - this.y = 0; - this.z = 0; - } - return this; - }, - multiplyScalar: function multiplyScalar(scalar) { - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - }, - applyQuaternion: function applyQuaternion(q) { - var x = this.x; - var y = this.y; - var z = this.z; - var qx = q.x; - var qy = q.y; - var qz = q.z; - var qw = q.w; - var ix = qw * x + qy * z - qz * y; - var iy = qw * y + qz * x - qx * z; - var iz = qw * z + qx * y - qy * x; - var iw = -qx * x - qy * y - qz * z; - this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; - this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; - this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; - return this; - }, - dot: function dot(v) { - return this.x * v.x + this.y * v.y + this.z * v.z; - }, - crossVectors: function crossVectors(a, b) { - var ax = a.x, - ay = a.y, - az = a.z; - var bx = b.x, - by = b.y, - bz = b.z; - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; - return this; - } -}; -var Quaternion = function Quaternion(x, y, z, w) { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = w !== undefined ? w : 1; -}; -Quaternion.prototype = { - constructor: Quaternion, - set: function set(x, y, z, w) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - return this; - }, - copy: function copy(quaternion) { - this.x = quaternion.x; - this.y = quaternion.y; - this.z = quaternion.z; - this.w = quaternion.w; - return this; - }, - setFromEulerXYZ: function setFromEulerXYZ(x, y, z) { - var c1 = Math.cos(x / 2); - var c2 = Math.cos(y / 2); - var c3 = Math.cos(z / 2); - var s1 = Math.sin(x / 2); - var s2 = Math.sin(y / 2); - var s3 = Math.sin(z / 2); - this.x = s1 * c2 * c3 + c1 * s2 * s3; - this.y = c1 * s2 * c3 - s1 * c2 * s3; - this.z = c1 * c2 * s3 + s1 * s2 * c3; - this.w = c1 * c2 * c3 - s1 * s2 * s3; - return this; - }, - setFromEulerYXZ: function setFromEulerYXZ(x, y, z) { - var c1 = Math.cos(x / 2); - var c2 = Math.cos(y / 2); - var c3 = Math.cos(z / 2); - var s1 = Math.sin(x / 2); - var s2 = Math.sin(y / 2); - var s3 = Math.sin(z / 2); - this.x = s1 * c2 * c3 + c1 * s2 * s3; - this.y = c1 * s2 * c3 - s1 * c2 * s3; - this.z = c1 * c2 * s3 - s1 * s2 * c3; - this.w = c1 * c2 * c3 + s1 * s2 * s3; - return this; - }, - setFromAxisAngle: function setFromAxisAngle(axis, angle) { - var halfAngle = angle / 2, - s = Math.sin(halfAngle); - this.x = axis.x * s; - this.y = axis.y * s; - this.z = axis.z * s; - this.w = Math.cos(halfAngle); - return this; - }, - multiply: function multiply(q) { - return this.multiplyQuaternions(this, q); - }, - multiplyQuaternions: function multiplyQuaternions(a, b) { - var qax = a.x, - qay = a.y, - qaz = a.z, - qaw = a.w; - var qbx = b.x, - qby = b.y, - qbz = b.z, - qbw = b.w; - this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; - this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; - this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; - this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - return this; - }, - inverse: function inverse() { - this.x *= -1; - this.y *= -1; - this.z *= -1; - this.normalize(); - return this; - }, - normalize: function normalize() { - var l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); - if (l === 0) { - this.x = 0; - this.y = 0; - this.z = 0; - this.w = 1; - } else { - l = 1 / l; - this.x = this.x * l; - this.y = this.y * l; - this.z = this.z * l; - this.w = this.w * l; - } - return this; - }, - slerp: function slerp(qb, t) { - if (t === 0) return this; - if (t === 1) return this.copy(qb); - var x = this.x, - y = this.y, - z = this.z, - w = this.w; - var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z; - if (cosHalfTheta < 0) { - this.w = -qb.w; - this.x = -qb.x; - this.y = -qb.y; - this.z = -qb.z; - cosHalfTheta = -cosHalfTheta; - } else { - this.copy(qb); - } - if (cosHalfTheta >= 1.0) { - this.w = w; - this.x = x; - this.y = y; - this.z = z; - return this; - } - var halfTheta = Math.acos(cosHalfTheta); - var sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); - if (Math.abs(sinHalfTheta) < 0.001) { - this.w = 0.5 * (w + this.w); - this.x = 0.5 * (x + this.x); - this.y = 0.5 * (y + this.y); - this.z = 0.5 * (z + this.z); - return this; - } - var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta, - ratioB = Math.sin(t * halfTheta) / sinHalfTheta; - this.w = w * ratioA + this.w * ratioB; - this.x = x * ratioA + this.x * ratioB; - this.y = y * ratioA + this.y * ratioB; - this.z = z * ratioA + this.z * ratioB; - return this; - }, - setFromUnitVectors: function () { - var v1, r; - var EPS = 0.000001; - return function (vFrom, vTo) { - if (v1 === undefined) v1 = new Vector3(); - r = vFrom.dot(vTo) + 1; - if (r < EPS) { - r = 0; - if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) { - v1.set(-vFrom.y, vFrom.x, 0); - } else { - v1.set(0, -vFrom.z, vFrom.y); - } - } else { - v1.crossVectors(vFrom, vTo); - } - this.x = v1.x; - this.y = v1.y; - this.z = v1.z; - this.w = r; - this.normalize(); - return this; - }; - }() -}; -function Device(params) { - this.width = params.width || getScreenWidth(); - this.height = params.height || getScreenHeight(); - this.widthMeters = params.widthMeters; - this.heightMeters = params.heightMeters; - this.bevelMeters = params.bevelMeters; -} -var DEFAULT_ANDROID = new Device({ - widthMeters: 0.110, - heightMeters: 0.062, - bevelMeters: 0.004 -}); -var DEFAULT_IOS = new Device({ - widthMeters: 0.1038, - heightMeters: 0.0584, - bevelMeters: 0.004 -}); -var Viewers = { - CardboardV1: new CardboardViewer({ - id: 'CardboardV1', - label: 'Cardboard I/O 2014', - fov: 40, - interLensDistance: 0.060, - baselineLensDistance: 0.035, - screenLensDistance: 0.042, - distortionCoefficients: [0.441, 0.156], - inverseCoefficients: [-0.4410035, 0.42756155, -0.4804439, 0.5460139, -0.58821183, 0.5733938, -0.48303202, 0.33299083, -0.17573841, 0.0651772, -0.01488963, 0.001559834] - }), - CardboardV2: new CardboardViewer({ - id: 'CardboardV2', - label: 'Cardboard I/O 2015', - fov: 60, - interLensDistance: 0.064, - baselineLensDistance: 0.035, - screenLensDistance: 0.039, - distortionCoefficients: [0.34, 0.55], - inverseCoefficients: [-0.33836704, -0.18162185, 0.862655, -1.2462051, 1.0560602, -0.58208317, 0.21609078, -0.05444823, 0.009177956, -9.904169E-4, 6.183535E-5, -1.6981803E-6] - }) -}; -function DeviceInfo(deviceParams, additionalViewers) { - this.viewer = Viewers.CardboardV2; - this.updateDeviceParams(deviceParams); - this.distortion = new Distortion(this.viewer.distortionCoefficients); - for (var i = 0; i < additionalViewers.length; i++) { - var viewer = additionalViewers[i]; - Viewers[viewer.id] = new CardboardViewer(viewer); - } -} -DeviceInfo.prototype.updateDeviceParams = function (deviceParams) { - this.device = this.determineDevice_(deviceParams) || this.device; -}; -DeviceInfo.prototype.getDevice = function () { - return this.device; -}; -DeviceInfo.prototype.setViewer = function (viewer) { - this.viewer = viewer; - this.distortion = new Distortion(this.viewer.distortionCoefficients); -}; -DeviceInfo.prototype.determineDevice_ = function (deviceParams) { - if (!deviceParams) { - if (isIOS()) { - console.warn('Using fallback iOS device measurements.'); - return DEFAULT_IOS; - } else { - console.warn('Using fallback Android device measurements.'); - return DEFAULT_ANDROID; - } - } - var METERS_PER_INCH = 0.0254; - var metersPerPixelX = METERS_PER_INCH / deviceParams.xdpi; - var metersPerPixelY = METERS_PER_INCH / deviceParams.ydpi; - var width = getScreenWidth(); - var height = getScreenHeight(); - return new Device({ - widthMeters: metersPerPixelX * width, - heightMeters: metersPerPixelY * height, - bevelMeters: deviceParams.bevelMm * 0.001 - }); -}; -DeviceInfo.prototype.getDistortedFieldOfViewLeftEye = function () { - var viewer = this.viewer; - var device = this.device; - var distortion = this.distortion; - var eyeToScreenDistance = viewer.screenLensDistance; - var outerDist = (device.widthMeters - viewer.interLensDistance) / 2; - var innerDist = viewer.interLensDistance / 2; - var bottomDist = viewer.baselineLensDistance - device.bevelMeters; - var topDist = device.heightMeters - bottomDist; - var outerAngle = radToDeg * Math.atan(distortion.distort(outerDist / eyeToScreenDistance)); - var innerAngle = radToDeg * Math.atan(distortion.distort(innerDist / eyeToScreenDistance)); - var bottomAngle = radToDeg * Math.atan(distortion.distort(bottomDist / eyeToScreenDistance)); - var topAngle = radToDeg * Math.atan(distortion.distort(topDist / eyeToScreenDistance)); - return { - leftDegrees: Math.min(outerAngle, viewer.fov), - rightDegrees: Math.min(innerAngle, viewer.fov), - downDegrees: Math.min(bottomAngle, viewer.fov), - upDegrees: Math.min(topAngle, viewer.fov) - }; -}; -DeviceInfo.prototype.getLeftEyeVisibleTanAngles = function () { - var viewer = this.viewer; - var device = this.device; - var distortion = this.distortion; - var fovLeft = Math.tan(-degToRad * viewer.fov); - var fovTop = Math.tan(degToRad * viewer.fov); - var fovRight = Math.tan(degToRad * viewer.fov); - var fovBottom = Math.tan(-degToRad * viewer.fov); - var halfWidth = device.widthMeters / 4; - var halfHeight = device.heightMeters / 2; - var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight; - var centerX = viewer.interLensDistance / 2 - halfWidth; - var centerY = -verticalLensOffset; - var centerZ = viewer.screenLensDistance; - var screenLeft = distortion.distort((centerX - halfWidth) / centerZ); - var screenTop = distortion.distort((centerY + halfHeight) / centerZ); - var screenRight = distortion.distort((centerX + halfWidth) / centerZ); - var screenBottom = distortion.distort((centerY - halfHeight) / centerZ); - var result = new Float32Array(4); - result[0] = Math.max(fovLeft, screenLeft); - result[1] = Math.min(fovTop, screenTop); - result[2] = Math.min(fovRight, screenRight); - result[3] = Math.max(fovBottom, screenBottom); - return result; -}; -DeviceInfo.prototype.getLeftEyeNoLensTanAngles = function () { - var viewer = this.viewer; - var device = this.device; - var distortion = this.distortion; - var result = new Float32Array(4); - var fovLeft = distortion.distortInverse(Math.tan(-degToRad * viewer.fov)); - var fovTop = distortion.distortInverse(Math.tan(degToRad * viewer.fov)); - var fovRight = distortion.distortInverse(Math.tan(degToRad * viewer.fov)); - var fovBottom = distortion.distortInverse(Math.tan(-degToRad * viewer.fov)); - var halfWidth = device.widthMeters / 4; - var halfHeight = device.heightMeters / 2; - var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight; - var centerX = viewer.interLensDistance / 2 - halfWidth; - var centerY = -verticalLensOffset; - var centerZ = viewer.screenLensDistance; - var screenLeft = (centerX - halfWidth) / centerZ; - var screenTop = (centerY + halfHeight) / centerZ; - var screenRight = (centerX + halfWidth) / centerZ; - var screenBottom = (centerY - halfHeight) / centerZ; - result[0] = Math.max(fovLeft, screenLeft); - result[1] = Math.min(fovTop, screenTop); - result[2] = Math.min(fovRight, screenRight); - result[3] = Math.max(fovBottom, screenBottom); - return result; -}; -DeviceInfo.prototype.getLeftEyeVisibleScreenRect = function (undistortedFrustum) { - var viewer = this.viewer; - var device = this.device; - var dist = viewer.screenLensDistance; - var eyeX = (device.widthMeters - viewer.interLensDistance) / 2; - var eyeY = viewer.baselineLensDistance - device.bevelMeters; - var left = (undistortedFrustum[0] * dist + eyeX) / device.widthMeters; - var top = (undistortedFrustum[1] * dist + eyeY) / device.heightMeters; - var right = (undistortedFrustum[2] * dist + eyeX) / device.widthMeters; - var bottom = (undistortedFrustum[3] * dist + eyeY) / device.heightMeters; - return { - x: left, - y: bottom, - width: right - left, - height: top - bottom - }; -}; -DeviceInfo.prototype.getFieldOfViewLeftEye = function (opt_isUndistorted) { - return opt_isUndistorted ? this.getUndistortedFieldOfViewLeftEye() : this.getDistortedFieldOfViewLeftEye(); -}; -DeviceInfo.prototype.getFieldOfViewRightEye = function (opt_isUndistorted) { - var fov = this.getFieldOfViewLeftEye(opt_isUndistorted); - return { - leftDegrees: fov.rightDegrees, - rightDegrees: fov.leftDegrees, - upDegrees: fov.upDegrees, - downDegrees: fov.downDegrees - }; -}; -DeviceInfo.prototype.getUndistortedFieldOfViewLeftEye = function () { - var p = this.getUndistortedParams_(); - return { - leftDegrees: radToDeg * Math.atan(p.outerDist), - rightDegrees: radToDeg * Math.atan(p.innerDist), - downDegrees: radToDeg * Math.atan(p.bottomDist), - upDegrees: radToDeg * Math.atan(p.topDist) - }; -}; -DeviceInfo.prototype.getUndistortedViewportLeftEye = function () { - var p = this.getUndistortedParams_(); - var viewer = this.viewer; - var device = this.device; - var eyeToScreenDistance = viewer.screenLensDistance; - var screenWidth = device.widthMeters / eyeToScreenDistance; - var screenHeight = device.heightMeters / eyeToScreenDistance; - var xPxPerTanAngle = device.width / screenWidth; - var yPxPerTanAngle = device.height / screenHeight; - var x = Math.round((p.eyePosX - p.outerDist) * xPxPerTanAngle); - var y = Math.round((p.eyePosY - p.bottomDist) * yPxPerTanAngle); - return { - x: x, - y: y, - width: Math.round((p.eyePosX + p.innerDist) * xPxPerTanAngle) - x, - height: Math.round((p.eyePosY + p.topDist) * yPxPerTanAngle) - y - }; -}; -DeviceInfo.prototype.getUndistortedParams_ = function () { - var viewer = this.viewer; - var device = this.device; - var distortion = this.distortion; - var eyeToScreenDistance = viewer.screenLensDistance; - var halfLensDistance = viewer.interLensDistance / 2 / eyeToScreenDistance; - var screenWidth = device.widthMeters / eyeToScreenDistance; - var screenHeight = device.heightMeters / eyeToScreenDistance; - var eyePosX = screenWidth / 2 - halfLensDistance; - var eyePosY = (viewer.baselineLensDistance - device.bevelMeters) / eyeToScreenDistance; - var maxFov = viewer.fov; - var viewerMax = distortion.distortInverse(Math.tan(degToRad * maxFov)); - var outerDist = Math.min(eyePosX, viewerMax); - var innerDist = Math.min(halfLensDistance, viewerMax); - var bottomDist = Math.min(eyePosY, viewerMax); - var topDist = Math.min(screenHeight - eyePosY, viewerMax); - return { - outerDist: outerDist, - innerDist: innerDist, - topDist: topDist, - bottomDist: bottomDist, - eyePosX: eyePosX, - eyePosY: eyePosY - }; -}; -function CardboardViewer(params) { - this.id = params.id; - this.label = params.label; - this.fov = params.fov; - this.interLensDistance = params.interLensDistance; - this.baselineLensDistance = params.baselineLensDistance; - this.screenLensDistance = params.screenLensDistance; - this.distortionCoefficients = params.distortionCoefficients; - this.inverseCoefficients = params.inverseCoefficients; -} -DeviceInfo.Viewers = Viewers; -var format = 1; -var last_updated = "2019-11-09T17:36:14Z"; -var devices = [{"type":"android","rules":[{"mdmh":"asus/*/Nexus 7/*"},{"ua":"Nexus 7"}],"dpi":[320.8,323],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_X00PD/*"},{"ua":"ASUS_X00PD"}],"dpi":245,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_X008D/*"},{"ua":"ASUS_X008D"}],"dpi":282,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_Z00AD/*"},{"ua":"ASUS_Z00AD"}],"dpi":[403,404.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2 XL/*"},{"ua":"Pixel 2 XL"}],"dpi":537.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3 XL/*"},{"ua":"Pixel 3 XL"}],"dpi":[558.5,553.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel XL/*"},{"ua":"Pixel XL"}],"dpi":[537.9,533],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3/*"},{"ua":"Pixel 3"}],"dpi":442.4,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2/*"},{"ua":"Pixel 2"}],"dpi":441,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Google/*/Pixel/*"},{"ua":"Pixel"}],"dpi":[432.6,436.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC6435LVW/*"},{"ua":"HTC6435LVW"}],"dpi":[449.7,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One XL/*"},{"ua":"HTC One XL"}],"dpi":[315.3,314.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"htc/*/Nexus 9/*"},{"ua":"Nexus 9"}],"dpi":289,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One M9/*"},{"ua":"HTC One M9"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One_M8/*"},{"ua":"HTC One_M8"}],"dpi":[449.7,447.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One/*"},{"ua":"HTC One"}],"dpi":472.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/Nexus 6P/*"},{"ua":"Nexus 6P"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/BLN-L24/*"},{"ua":"HONORBLN-L24"}],"dpi":480,"bw":4,"ac":500},{"type":"android","rules":[{"mdmh":"Huawei/*/BKL-L09/*"},{"ua":"BKL-L09"}],"dpi":403,"bw":3.47,"ac":500},{"type":"android","rules":[{"mdmh":"LENOVO/*/Lenovo PB2-690Y/*"},{"ua":"Lenovo PB2-690Y"}],"dpi":[457.2,454.713],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5X/*"},{"ua":"Nexus 5X"}],"dpi":[422,419.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS345/*"},{"ua":"LGMS345"}],"dpi":[221.7,219.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D800/*"},{"ua":"LG-D800"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D850/*"},{"ua":"LG-D850"}],"dpi":[537.9,541.9],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/VS985 4G/*"},{"ua":"VS985 4G"}],"dpi":[537.9,535.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5/*"},{"ua":"Nexus 5 B"}],"dpi":[442.4,444.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 4/*"},{"ua":"Nexus 4"}],"dpi":[319.8,318.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LG-P769/*"},{"ua":"LG-P769"}],"dpi":[240.6,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS323/*"},{"ua":"LGMS323"}],"dpi":[206.6,204.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGLS996/*"},{"ua":"LGLS996"}],"dpi":[403.4,401.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/4560MMX/*"},{"ua":"4560MMX"}],"dpi":[240,219.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/A250/*"},{"ua":"Micromax A250"}],"dpi":[480,446.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/Micromax AQ4501/*"},{"ua":"Micromax AQ4501"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/G5/*"},{"ua":"Moto G (5) Plus"}],"dpi":[403.4,403],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/DROID RAZR/*"},{"ua":"DROID RAZR"}],"dpi":[368.1,256.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT830C/*"},{"ua":"XT830C"}],"dpi":[254,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1021/*"},{"ua":"XT1021"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1023/*"},{"ua":"XT1023"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1028/*"},{"ua":"XT1028"}],"dpi":[326.6,327.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1034/*"},{"ua":"XT1034"}],"dpi":[326.6,328.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1053/*"},{"ua":"XT1053"}],"dpi":[315.3,316.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1562/*"},{"ua":"XT1562"}],"dpi":[403.4,402.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/Nexus 6/*"},{"ua":"Nexus 6 B"}],"dpi":[494.3,489.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1063/*"},{"ua":"XT1063"}],"dpi":[295,296.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1064/*"},{"ua":"XT1064"}],"dpi":[295,295.6],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1092/*"},{"ua":"XT1092"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1095/*"},{"ua":"XT1095"}],"dpi":[422,423.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/G4/*"},{"ua":"Moto G (4)"}],"dpi":401,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/A0001/*"},{"ua":"A0001"}],"dpi":[403.4,401],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1001/*"},{"ua":"ONE E1001"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1003/*"},{"ua":"ONE E1003"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1005/*"},{"ua":"ONE E1005"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2001/*"},{"ua":"ONE A2001"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2003/*"},{"ua":"ONE A2003"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2005/*"},{"ua":"ONE A2005"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A3000/*"},{"ua":"ONEPLUS A3000"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A3003/*"},{"ua":"ONEPLUS A3003"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A3010/*"},{"ua":"ONEPLUS A3010"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A5000/*"},{"ua":"ONEPLUS A5000 "}],"dpi":[403.411,399.737],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A5010/*"},{"ua":"ONEPLUS A5010"}],"dpi":[403,400],"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6000/*"},{"ua":"ONEPLUS A6000"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6003/*"},{"ua":"ONEPLUS A6003"}],"dpi":401,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6010/*"},{"ua":"ONEPLUS A6010"}],"dpi":401,"bw":2,"ac":500},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A6013/*"},{"ua":"ONEPLUS A6013"}],"dpi":401,"bw":2,"ac":500},{"type":"android","rules":[{"mdmh":"OPPO/*/X909/*"},{"ua":"X909"}],"dpi":[442.4,444.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9082/*"},{"ua":"GT-I9082"}],"dpi":[184.7,185.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G360P/*"},{"ua":"SM-G360P"}],"dpi":[196.7,205.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Nexus S/*"},{"ua":"Nexus S"}],"dpi":[234.5,229.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[304.8,303.9],"bw":5,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T230NU/*"},{"ua":"SM-T230NU"}],"dpi":216,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-T399/*"},{"ua":"SGH-T399"}],"dpi":[217.7,231.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-M919/*"},{"ua":"SGH-M919"}],"dpi":[440.8,437.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N9005/*"},{"ua":"SM-N9005"}],"dpi":[386.4,387],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SM-N900A/*"},{"ua":"SAMSUNG-SM-N900A"}],"dpi":[386.4,387.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9500/*"},{"ua":"GT-I9500"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9505/*"},{"ua":"GT-I9505"}],"dpi":439.4,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900F/*"},{"ua":"SM-G900F"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900M/*"},{"ua":"SM-G900M"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G800F/*"},{"ua":"SM-G800F"}],"dpi":326.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G906S/*"},{"ua":"SM-G906S"}],"dpi":[562.7,572.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[306.7,304.8],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T535/*"},{"ua":"SM-T535"}],"dpi":[142.6,136.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920C/*"},{"ua":"SM-N920C"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920P/*"},{"ua":"SM-N920P"}],"dpi":[386.3655,390.144],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920W8/*"},{"ua":"SM-N920W8"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300I/*"},{"ua":"GT-I9300I"}],"dpi":[304.8,305.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9195/*"},{"ua":"GT-I9195"}],"dpi":[249.4,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-L520/*"},{"ua":"SPH-L520"}],"dpi":[249.4,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SGH-I717/*"},{"ua":"SAMSUNG-SGH-I717"}],"dpi":285.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-D710/*"},{"ua":"SPH-D710"}],"dpi":[217.7,204.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-N7100/*"},{"ua":"GT-N7100"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SCH-I605/*"},{"ua":"SCH-I605"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Galaxy Nexus/*"},{"ua":"Galaxy Nexus"}],"dpi":[315.3,314.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910H/*"},{"ua":"SM-N910H"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910C/*"},{"ua":"SM-N910C"}],"dpi":[515.2,520.2],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G130M/*"},{"ua":"SM-G130M"}],"dpi":[165.9,164.8],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G928I/*"},{"ua":"SM-G928I"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920F/*"},{"ua":"SM-G920F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920P/*"},{"ua":"SM-G920P"}],"dpi":[522.5,577],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925F/*"},{"ua":"SM-G925F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925V/*"},{"ua":"SM-G925V"}],"dpi":[522.5,576.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G930F/*"},{"ua":"SM-G930F"}],"dpi":576.6,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G935F/*"},{"ua":"SM-G935F"}],"dpi":533,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G950F/*"},{"ua":"SM-G950F"}],"dpi":[562.707,565.293],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955U/*"},{"ua":"SM-G955U"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955F/*"},{"ua":"SM-G955F"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960F/*"},{"ua":"SM-G960F"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G9600/*"},{"ua":"SM-G9600"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960T/*"},{"ua":"SM-G960T"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960N/*"},{"ua":"SM-G960N"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960U/*"},{"ua":"SM-G960U"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G9608/*"},{"ua":"SM-G9608"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960FD/*"},{"ua":"SM-G960FD"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G960W/*"},{"ua":"SM-G960W"}],"dpi":[569.575,571.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G965F/*"},{"ua":"SM-G965F"}],"dpi":529,"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/C6903/*"},{"ua":"C6903"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/D6653/*"},{"ua":"D6653"}],"dpi":[428.6,427.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6653/*"},{"ua":"E6653"}],"dpi":[428.6,425.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6853/*"},{"ua":"E6853"}],"dpi":[403.4,401.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/SGP321/*"},{"ua":"SGP321"}],"dpi":[224.7,224.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{"ua":"ALCATEL ONE TOUCH Fierce"}],"dpi":[240,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"THL/*/thl 5000/*"},{"ua":"thl 5000"}],"dpi":[480,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Fly/*/IQ4412/*"},{"ua":"IQ4412"}],"dpi":307.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"ZTE/*/ZTE Blade L2/*"},{"ua":"ZTE Blade L2"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"BENEVE/*/VR518/*"},{"ua":"VR518"}],"dpi":480,"bw":3,"ac":500},{"type":"ios","rules":[{"res":[640,960]}],"dpi":[325.1,328.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[640,1136]}],"dpi":[317.1,320.2],"bw":3,"ac":1000},{"type":"ios","rules":[{"res":[750,1334]}],"dpi":326.4,"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1242,2208]}],"dpi":[453.6,458.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2001]}],"dpi":[410.9,415.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2436]}],"dpi":458,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/EML-L29/*"},{"ua":"EML-L29"}],"dpi":428,"bw":3.45,"ac":500},{"type":"android","rules":[{"mdmh":"Nokia/*/Nokia 7.1/*"},{"ua":"Nokia 7.1"}],"dpi":[432,431.9],"bw":3,"ac":500},{"type":"ios","rules":[{"res":[1242,2688]}],"dpi":458,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G570M/*"},{"ua":"SM-G570M"}],"dpi":320,"bw":3.684,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G970F/*"},{"ua":"SM-G970F"}],"dpi":438,"bw":2.281,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G973F/*"},{"ua":"SM-G973F"}],"dpi":550,"bw":2.002,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G975F/*"},{"ua":"SM-G975F"}],"dpi":522,"bw":2.054,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G977F/*"},{"ua":"SM-G977F"}],"dpi":505,"bw":2.334,"ac":500},{"type":"ios","rules":[{"res":[828,1792]}],"dpi":326,"bw":5,"ac":500}]; -var DPDB_CACHE = { - format: format, - last_updated: last_updated, - devices: devices -}; -function Dpdb(url, onDeviceParamsUpdated) { - this.dpdb = DPDB_CACHE; - this.recalculateDeviceParams_(); - if (url) { - this.onDeviceParamsUpdated = onDeviceParamsUpdated; - var xhr = new XMLHttpRequest(); - var obj = this; - xhr.open('GET', url, true); - xhr.addEventListener('load', function () { - obj.loading = false; - if (xhr.status >= 200 && xhr.status <= 299) { - obj.dpdb = JSON.parse(xhr.response); - obj.recalculateDeviceParams_(); - } else { - console.error('Error loading online DPDB!'); - } - }); - xhr.send(); - } -} -Dpdb.prototype.getDeviceParams = function () { - return this.deviceParams; -}; -Dpdb.prototype.recalculateDeviceParams_ = function () { - var newDeviceParams = this.calcDeviceParams_(); - if (newDeviceParams) { - this.deviceParams = newDeviceParams; - if (this.onDeviceParamsUpdated) { - this.onDeviceParamsUpdated(this.deviceParams); - } - } else { - console.error('Failed to recalculate device parameters.'); - } -}; -Dpdb.prototype.calcDeviceParams_ = function () { - var db = this.dpdb; - if (!db) { - console.error('DPDB not available.'); - return null; - } - if (db.format != 1) { - console.error('DPDB has unexpected format version.'); - return null; - } - if (!db.devices || !db.devices.length) { - console.error('DPDB does not have a devices section.'); - return null; - } - var userAgent = navigator.userAgent || navigator.vendor || window.opera; - var width = getScreenWidth(); - var height = getScreenHeight(); - if (!db.devices) { - console.error('DPDB has no devices section.'); - return null; - } - for (var i = 0; i < db.devices.length; i++) { - var device = db.devices[i]; - if (!device.rules) { - console.warn('Device[' + i + '] has no rules section.'); - continue; - } - if (device.type != 'ios' && device.type != 'android') { - console.warn('Device[' + i + '] has invalid type.'); - continue; - } - if (isIOS() != (device.type == 'ios')) continue; - var matched = false; - for (var j = 0; j < device.rules.length; j++) { - var rule = device.rules[j]; - if (this.ruleMatches_(rule, userAgent, width, height)) { - matched = true; - break; - } - } - if (!matched) continue; - var xdpi = device.dpi[0] || device.dpi; - var ydpi = device.dpi[1] || device.dpi; - return new DeviceParams({ xdpi: xdpi, ydpi: ydpi, bevelMm: device.bw }); - } - console.warn('No DPDB device match.'); - return null; -}; -Dpdb.prototype.ruleMatches_ = function (rule, ua, screenWidth, screenHeight) { - if (!rule.ua && !rule.res) return false; - if (rule.ua && rule.ua.substring(0, 2) === 'SM') rule.ua = rule.ua.substring(0, 7); - if (rule.ua && ua.indexOf(rule.ua) < 0) return false; - if (rule.res) { - if (!rule.res[0] || !rule.res[1]) return false; - var resX = rule.res[0]; - var resY = rule.res[1]; - if (Math.min(screenWidth, screenHeight) != Math.min(resX, resY) || Math.max(screenWidth, screenHeight) != Math.max(resX, resY)) { - return false; - } - } - return true; -}; -function DeviceParams(params) { - this.xdpi = params.xdpi; - this.ydpi = params.ydpi; - this.bevelMm = params.bevelMm; -} -function SensorSample(sample, timestampS) { - this.set(sample, timestampS); -} -SensorSample.prototype.set = function (sample, timestampS) { - this.sample = sample; - this.timestampS = timestampS; -}; -SensorSample.prototype.copy = function (sensorSample) { - this.set(sensorSample.sample, sensorSample.timestampS); -}; -function ComplementaryFilter(kFilter, isDebug) { - this.kFilter = kFilter; - this.isDebug = isDebug; - this.currentAccelMeasurement = new SensorSample(); - this.currentGyroMeasurement = new SensorSample(); - this.previousGyroMeasurement = new SensorSample(); - if (isIOS()) { - this.filterQ = new Quaternion(-1, 0, 0, 1); - } else { - this.filterQ = new Quaternion(1, 0, 0, 1); - } - this.previousFilterQ = new Quaternion(); - this.previousFilterQ.copy(this.filterQ); - this.accelQ = new Quaternion(); - this.isOrientationInitialized = false; - this.estimatedGravity = new Vector3(); - this.measuredGravity = new Vector3(); - this.gyroIntegralQ = new Quaternion(); -} -ComplementaryFilter.prototype.addAccelMeasurement = function (vector, timestampS) { - this.currentAccelMeasurement.set(vector, timestampS); -}; -ComplementaryFilter.prototype.addGyroMeasurement = function (vector, timestampS) { - this.currentGyroMeasurement.set(vector, timestampS); - var deltaT = timestampS - this.previousGyroMeasurement.timestampS; - if (isTimestampDeltaValid(deltaT)) { - this.run_(); - } - this.previousGyroMeasurement.copy(this.currentGyroMeasurement); -}; -ComplementaryFilter.prototype.run_ = function () { - if (!this.isOrientationInitialized) { - this.accelQ = this.accelToQuaternion_(this.currentAccelMeasurement.sample); - this.previousFilterQ.copy(this.accelQ); - this.isOrientationInitialized = true; - return; - } - var deltaT = this.currentGyroMeasurement.timestampS - this.previousGyroMeasurement.timestampS; - var gyroDeltaQ = this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample, deltaT); - this.gyroIntegralQ.multiply(gyroDeltaQ); - this.filterQ.copy(this.previousFilterQ); - this.filterQ.multiply(gyroDeltaQ); - var invFilterQ = new Quaternion(); - invFilterQ.copy(this.filterQ); - invFilterQ.inverse(); - this.estimatedGravity.set(0, 0, -1); - this.estimatedGravity.applyQuaternion(invFilterQ); - this.estimatedGravity.normalize(); - this.measuredGravity.copy(this.currentAccelMeasurement.sample); - this.measuredGravity.normalize(); - var deltaQ = new Quaternion(); - deltaQ.setFromUnitVectors(this.estimatedGravity, this.measuredGravity); - deltaQ.inverse(); - if (this.isDebug) { - console.log('Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)', radToDeg * getQuaternionAngle(deltaQ), this.estimatedGravity.x.toFixed(1), this.estimatedGravity.y.toFixed(1), this.estimatedGravity.z.toFixed(1), this.measuredGravity.x.toFixed(1), this.measuredGravity.y.toFixed(1), this.measuredGravity.z.toFixed(1)); - } - var targetQ = new Quaternion(); - targetQ.copy(this.filterQ); - targetQ.multiply(deltaQ); - this.filterQ.slerp(targetQ, 1 - this.kFilter); - this.previousFilterQ.copy(this.filterQ); -}; -ComplementaryFilter.prototype.getOrientation = function () { - return this.filterQ; -}; -ComplementaryFilter.prototype.accelToQuaternion_ = function (accel) { - var normAccel = new Vector3(); - normAccel.copy(accel); - normAccel.normalize(); - var quat = new Quaternion(); - quat.setFromUnitVectors(new Vector3(0, 0, -1), normAccel); - quat.inverse(); - return quat; -}; -ComplementaryFilter.prototype.gyroToQuaternionDelta_ = function (gyro, dt) { - var quat = new Quaternion(); - var axis = new Vector3(); - axis.copy(gyro); - axis.normalize(); - quat.setFromAxisAngle(axis, gyro.length() * dt); - return quat; -}; -function PosePredictor(predictionTimeS, isDebug) { - this.predictionTimeS = predictionTimeS; - this.isDebug = isDebug; - this.previousQ = new Quaternion(); - this.previousTimestampS = null; - this.deltaQ = new Quaternion(); - this.outQ = new Quaternion(); -} -PosePredictor.prototype.getPrediction = function (currentQ, gyro, timestampS) { - if (!this.previousTimestampS) { - this.previousQ.copy(currentQ); - this.previousTimestampS = timestampS; - return currentQ; - } - var axis = new Vector3(); - axis.copy(gyro); - axis.normalize(); - var angularSpeed = gyro.length(); - if (angularSpeed < degToRad * 20) { - if (this.isDebug) { - console.log('Moving slowly, at %s deg/s: no prediction', (radToDeg * angularSpeed).toFixed(1)); - } - this.outQ.copy(currentQ); - this.previousQ.copy(currentQ); - return this.outQ; - } - var predictAngle = angularSpeed * this.predictionTimeS; - this.deltaQ.setFromAxisAngle(axis, predictAngle); - this.outQ.copy(this.previousQ); - this.outQ.multiply(this.deltaQ); - this.previousQ.copy(currentQ); - this.previousTimestampS = timestampS; - return this.outQ; -}; -function FusionPoseSensor(kFilter, predictionTime, yawOnly, isDebug) { - this.yawOnly = yawOnly; - this.accelerometer = new Vector3(); - this.gyroscope = new Vector3(); - this.filter = new ComplementaryFilter(kFilter, isDebug); - this.posePredictor = new PosePredictor(predictionTime, isDebug); - this.isFirefoxAndroid = isFirefoxAndroid(); - this.isIOS = isIOS(); - var chromeVersion = getChromeVersion(); - this.isDeviceMotionInRadians = !this.isIOS && chromeVersion && chromeVersion < 66; - this.isWithoutDeviceMotion = isChromeWithoutDeviceMotion(); - this.filterToWorldQ = new Quaternion(); - if (isIOS()) { - this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2); - } else { - this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2); - } - this.inverseWorldToScreenQ = new Quaternion(); - this.worldToScreenQ = new Quaternion(); - this.originalPoseAdjustQ = new Quaternion(); - this.originalPoseAdjustQ.setFromAxisAngle(new Vector3(0, 0, 1), -window.orientation * Math.PI / 180); - this.setScreenTransform_(); - if (isLandscapeMode()) { - this.filterToWorldQ.multiply(this.inverseWorldToScreenQ); - } - this.resetQ = new Quaternion(); - this.orientationOut_ = new Float32Array(4); - this.start(); -} -FusionPoseSensor.prototype.getPosition = function () { - return null; -}; -FusionPoseSensor.prototype.getOrientation = function () { - var orientation = void 0; - if (this.isWithoutDeviceMotion && this._deviceOrientationQ) { - this.deviceOrientationFixQ = this.deviceOrientationFixQ || function () { - var z = new Quaternion().setFromAxisAngle(new Vector3(0, 0, -1), 0); - var y = new Quaternion(); - if (window.orientation === -90) { - y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / -2); - } else { - y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 2); - } - return z.multiply(y); - }(); - this.deviceOrientationFilterToWorldQ = this.deviceOrientationFilterToWorldQ || function () { - var q = new Quaternion(); - q.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2); - return q; - }(); - orientation = this._deviceOrientationQ; - var out = new Quaternion(); - out.copy(orientation); - out.multiply(this.deviceOrientationFilterToWorldQ); - out.multiply(this.resetQ); - out.multiply(this.worldToScreenQ); - out.multiplyQuaternions(this.deviceOrientationFixQ, out); - if (this.yawOnly) { - out.x = 0; - out.z = 0; - out.normalize(); - } - this.orientationOut_[0] = out.x; - this.orientationOut_[1] = out.y; - this.orientationOut_[2] = out.z; - this.orientationOut_[3] = out.w; - return this.orientationOut_; - } else { - var filterOrientation = this.filter.getOrientation(); - orientation = this.posePredictor.getPrediction(filterOrientation, this.gyroscope, this.previousTimestampS); - } - var out = new Quaternion(); - out.copy(this.filterToWorldQ); - out.multiply(this.resetQ); - out.multiply(orientation); - out.multiply(this.worldToScreenQ); - if (this.yawOnly) { - out.x = 0; - out.z = 0; - out.normalize(); - } - this.orientationOut_[0] = out.x; - this.orientationOut_[1] = out.y; - this.orientationOut_[2] = out.z; - this.orientationOut_[3] = out.w; - return this.orientationOut_; -}; -FusionPoseSensor.prototype.resetPose = function () { - this.resetQ.copy(this.filter.getOrientation()); - this.resetQ.x = 0; - this.resetQ.y = 0; - this.resetQ.z *= -1; - this.resetQ.normalize(); - if (isLandscapeMode()) { - this.resetQ.multiply(this.inverseWorldToScreenQ); - } - this.resetQ.multiply(this.originalPoseAdjustQ); -}; -FusionPoseSensor.prototype.onDeviceOrientation_ = function (e) { - this._deviceOrientationQ = this._deviceOrientationQ || new Quaternion(); - var alpha = e.alpha, - beta = e.beta, - gamma = e.gamma; - alpha = (alpha || 0) * Math.PI / 180; - beta = (beta || 0) * Math.PI / 180; - gamma = (gamma || 0) * Math.PI / 180; - this._deviceOrientationQ.setFromEulerYXZ(beta, alpha, -gamma); -}; -FusionPoseSensor.prototype.onDeviceMotion_ = function (deviceMotion) { - this.updateDeviceMotion_(deviceMotion); -}; -FusionPoseSensor.prototype.updateDeviceMotion_ = function (deviceMotion) { - var accGravity = deviceMotion.accelerationIncludingGravity; - var rotRate = deviceMotion.rotationRate; - var timestampS = deviceMotion.timeStamp / 1000; - var deltaS = timestampS - this.previousTimestampS; - if (deltaS < 0) { - warnOnce('fusion-pose-sensor:invalid:non-monotonic', 'Invalid timestamps detected: non-monotonic timestamp from devicemotion'); - this.previousTimestampS = timestampS; - return; - } else if (deltaS <= MIN_TIMESTEP || deltaS > MAX_TIMESTEP) { - warnOnce('fusion-pose-sensor:invalid:outside-threshold', 'Invalid timestamps detected: Timestamp from devicemotion outside expected range.'); - this.previousTimestampS = timestampS; - return; - } - this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z); - if (isR7()) { - this.gyroscope.set(-rotRate.beta, rotRate.alpha, rotRate.gamma); - } else { - this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma); - } - if (!this.isDeviceMotionInRadians) { - this.gyroscope.multiplyScalar(Math.PI / 180); - } - this.filter.addAccelMeasurement(this.accelerometer, timestampS); - this.filter.addGyroMeasurement(this.gyroscope, timestampS); - this.previousTimestampS = timestampS; -}; -FusionPoseSensor.prototype.onOrientationChange_ = function (screenOrientation) { - this.setScreenTransform_(); -}; -FusionPoseSensor.prototype.onMessage_ = function (event) { - var message = event.data; - if (!message || !message.type) { - return; - } - var type = message.type.toLowerCase(); - if (type !== 'devicemotion') { - return; - } - this.updateDeviceMotion_(message.deviceMotionEvent); -}; -FusionPoseSensor.prototype.setScreenTransform_ = function () { - this.worldToScreenQ.set(0, 0, 0, 1); - switch (window.orientation) { - case 0: - break; - case 90: - this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), -Math.PI / 2); - break; - case -90: - this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), Math.PI / 2); - break; - case 180: - break; - } - this.inverseWorldToScreenQ.copy(this.worldToScreenQ); - this.inverseWorldToScreenQ.inverse(); -}; -FusionPoseSensor.prototype.start = function () { - this.onDeviceMotionCallback_ = this.onDeviceMotion_.bind(this); - this.onOrientationChangeCallback_ = this.onOrientationChange_.bind(this); - this.onMessageCallback_ = this.onMessage_.bind(this); - this.onDeviceOrientationCallback_ = this.onDeviceOrientation_.bind(this); - if (isIOS() && isInsideCrossOriginIFrame()) { - window.addEventListener('message', this.onMessageCallback_); - } - window.addEventListener('orientationchange', this.onOrientationChangeCallback_); - if (this.isWithoutDeviceMotion) { - window.addEventListener('deviceorientation', this.onDeviceOrientationCallback_); - } else { - window.addEventListener('devicemotion', this.onDeviceMotionCallback_); - } -}; -FusionPoseSensor.prototype.stop = function () { - window.removeEventListener('devicemotion', this.onDeviceMotionCallback_); - window.removeEventListener('deviceorientation', this.onDeviceOrientationCallback_); - window.removeEventListener('orientationchange', this.onOrientationChangeCallback_); - window.removeEventListener('message', this.onMessageCallback_); -}; -var SENSOR_FREQUENCY = 60; -var X_AXIS = new Vector3(1, 0, 0); -var Z_AXIS = new Vector3(0, 0, 1); -var SENSOR_TO_VR = new Quaternion(); -SENSOR_TO_VR.setFromAxisAngle(X_AXIS, -Math.PI / 2); -SENSOR_TO_VR.multiply(new Quaternion().setFromAxisAngle(Z_AXIS, Math.PI / 2)); -var PoseSensor = function () { - function PoseSensor(config) { - classCallCheck(this, PoseSensor); - this.config = config; - this.sensor = null; - this.fusionSensor = null; - this._out = new Float32Array(4); - this.api = null; - this.errors = []; - this._sensorQ = new Quaternion(); - this._outQ = new Quaternion(); - this._onSensorRead = this._onSensorRead.bind(this); - this._onSensorError = this._onSensorError.bind(this); - this.init(); - } - createClass(PoseSensor, [{ - key: 'init', - value: function init() { - var sensor = null; - try { - sensor = new RelativeOrientationSensor({ - frequency: SENSOR_FREQUENCY, - referenceFrame: 'screen' - }); - sensor.addEventListener('error', this._onSensorError); - } catch (error) { - this.errors.push(error); - if (error.name === 'SecurityError') { - console.error('Cannot construct sensors due to the Feature Policy'); - console.warn('Attempting to fall back using "devicemotion"; however this will ' + 'fail in the future without correct permissions.'); - this.useDeviceMotion(); - } else if (error.name === 'ReferenceError') { - this.useDeviceMotion(); - } else { - console.error(error); - } - } - if (sensor) { - this.api = 'sensor'; - this.sensor = sensor; - this.sensor.addEventListener('reading', this._onSensorRead); - this.sensor.start(); - } - } - }, { - key: 'useDeviceMotion', - value: function useDeviceMotion() { - this.api = 'devicemotion'; - this.fusionSensor = new FusionPoseSensor(this.config.K_FILTER, this.config.PREDICTION_TIME_S, this.config.YAW_ONLY, this.config.DEBUG); - if (this.sensor) { - this.sensor.removeEventListener('reading', this._onSensorRead); - this.sensor.removeEventListener('error', this._onSensorError); - this.sensor = null; - } - } - }, { - key: 'getOrientation', - value: function getOrientation() { - if (this.fusionSensor) { - return this.fusionSensor.getOrientation(); - } - if (!this.sensor || !this.sensor.quaternion) { - this._out[0] = this._out[1] = this._out[2] = 0; - this._out[3] = 1; - return this._out; - } - var q = this.sensor.quaternion; - this._sensorQ.set(q[0], q[1], q[2], q[3]); - var out = this._outQ; - out.copy(SENSOR_TO_VR); - out.multiply(this._sensorQ); - if (this.config.YAW_ONLY) { - out.x = out.z = 0; - out.normalize(); - } - this._out[0] = out.x; - this._out[1] = out.y; - this._out[2] = out.z; - this._out[3] = out.w; - return this._out; - } - }, { - key: '_onSensorError', - value: function _onSensorError(event) { - this.errors.push(event.error); - if (event.error.name === 'NotAllowedError') { - console.error('Permission to access sensor was denied'); - } else if (event.error.name === 'NotReadableError') { - console.error('Sensor could not be read'); - } else { - console.error(event.error); - } - this.useDeviceMotion(); - } - }, { - key: '_onSensorRead', - value: function _onSensorRead() {} - }]); - return PoseSensor; -}(); -var rotateInstructionsAsset = ""; -function RotateInstructions() { - this.loadIcon_(); - var overlay = document.createElement('div'); - var s = overlay.style; - s.position = 'fixed'; - s.top = 0; - s.right = 0; - s.bottom = 0; - s.left = 0; - s.backgroundColor = 'gray'; - s.fontFamily = 'sans-serif'; - s.zIndex = 1000000; - var img = document.createElement('img'); - img.src = this.icon; - var s = img.style; - s.marginLeft = '25%'; - s.marginTop = '25%'; - s.width = '50%'; - overlay.appendChild(img); - var text = document.createElement('div'); - var s = text.style; - s.textAlign = 'center'; - s.fontSize = '16px'; - s.lineHeight = '24px'; - s.margin = '24px 25%'; - s.width = '50%'; - text.innerHTML = 'Place your phone into your Cardboard viewer.'; - overlay.appendChild(text); - var snackbar = document.createElement('div'); - var s = snackbar.style; - s.backgroundColor = '#CFD8DC'; - s.position = 'fixed'; - s.bottom = 0; - s.width = '100%'; - s.height = '48px'; - s.padding = '14px 24px'; - s.boxSizing = 'border-box'; - s.color = '#656A6B'; - overlay.appendChild(snackbar); - var snackbarText = document.createElement('div'); - snackbarText.style.float = 'left'; - snackbarText.innerHTML = 'No Cardboard viewer?'; - var snackbarButton = document.createElement('a'); - snackbarButton.href = 'https://www.google.com/get/cardboard/get-cardboard/'; - snackbarButton.innerHTML = 'get one'; - snackbarButton.target = '_blank'; - var s = snackbarButton.style; - s.float = 'right'; - s.fontWeight = 600; - s.textTransform = 'uppercase'; - s.borderLeft = '1px solid gray'; - s.paddingLeft = '24px'; - s.textDecoration = 'none'; - s.color = '#656A6B'; - snackbar.appendChild(snackbarText); - snackbar.appendChild(snackbarButton); - this.overlay = overlay; - this.text = text; - this.hide(); -} -RotateInstructions.prototype.show = function (parent) { - if (!parent && !this.overlay.parentElement) { - document.body.appendChild(this.overlay); - } else if (parent) { - if (this.overlay.parentElement && this.overlay.parentElement != parent) this.overlay.parentElement.removeChild(this.overlay); - parent.appendChild(this.overlay); - } - this.overlay.style.display = 'block'; - var img = this.overlay.querySelector('img'); - var s = img.style; - if (isLandscapeMode()) { - s.width = '20%'; - s.marginLeft = '40%'; - s.marginTop = '3%'; - } else { - s.width = '50%'; - s.marginLeft = '25%'; - s.marginTop = '25%'; - } -}; -RotateInstructions.prototype.hide = function () { - this.overlay.style.display = 'none'; -}; -RotateInstructions.prototype.showTemporarily = function (ms, parent) { - this.show(parent); - this.timer = setTimeout(this.hide.bind(this), ms); -}; -RotateInstructions.prototype.disableShowTemporarily = function () { - clearTimeout(this.timer); -}; -RotateInstructions.prototype.update = function () { - this.disableShowTemporarily(); - if (!isLandscapeMode() && isMobile()) { - this.show(); - } else { - this.hide(); - } -}; -RotateInstructions.prototype.loadIcon_ = function () { - this.icon = dataUri('image/svg+xml', rotateInstructionsAsset); -}; -var DEFAULT_VIEWER = 'CardboardV1'; -var VIEWER_KEY = 'WEBVR_CARDBOARD_VIEWER'; -var CLASS_NAME = 'webvr-polyfill-viewer-selector'; -function ViewerSelector(defaultViewer) { - try { - this.selectedKey = localStorage.getItem(VIEWER_KEY); - } catch (error) { - console.error('Failed to load viewer profile: %s', error); - } - if (!this.selectedKey) { - this.selectedKey = defaultViewer || DEFAULT_VIEWER; - } - this.dialog = this.createDialog_(DeviceInfo.Viewers); - this.root = null; - this.onChangeCallbacks_ = []; -} -ViewerSelector.prototype.show = function (root) { - this.root = root; - root.appendChild(this.dialog); - var selected = this.dialog.querySelector('#' + this.selectedKey); - selected.checked = true; - this.dialog.style.display = 'block'; -}; -ViewerSelector.prototype.hide = function () { - if (this.root && this.root.contains(this.dialog)) { - this.root.removeChild(this.dialog); - } - this.dialog.style.display = 'none'; -}; -ViewerSelector.prototype.getCurrentViewer = function () { - return DeviceInfo.Viewers[this.selectedKey]; -}; -ViewerSelector.prototype.getSelectedKey_ = function () { - var input = this.dialog.querySelector('input[name=field]:checked'); - if (input) { - return input.id; - } - return null; -}; -ViewerSelector.prototype.onChange = function (cb) { - this.onChangeCallbacks_.push(cb); -}; -ViewerSelector.prototype.fireOnChange_ = function (viewer) { - for (var i = 0; i < this.onChangeCallbacks_.length; i++) { - this.onChangeCallbacks_[i](viewer); - } -}; -ViewerSelector.prototype.onSave_ = function () { - this.selectedKey = this.getSelectedKey_(); - if (!this.selectedKey || !DeviceInfo.Viewers[this.selectedKey]) { - console.error('ViewerSelector.onSave_: this should never happen!'); - return; - } - this.fireOnChange_(DeviceInfo.Viewers[this.selectedKey]); - try { - localStorage.setItem(VIEWER_KEY, this.selectedKey); - } catch (error) { - console.error('Failed to save viewer profile: %s', error); - } - this.hide(); -}; -ViewerSelector.prototype.createDialog_ = function (options) { - var container = document.createElement('div'); - container.classList.add(CLASS_NAME); - container.style.display = 'none'; - var overlay = document.createElement('div'); - var s = overlay.style; - s.position = 'fixed'; - s.left = 0; - s.top = 0; - s.width = '100%'; - s.height = '100%'; - s.background = 'rgba(0, 0, 0, 0.3)'; - overlay.addEventListener('click', this.hide.bind(this)); - var width = 280; - var dialog = document.createElement('div'); - var s = dialog.style; - s.boxSizing = 'border-box'; - s.position = 'fixed'; - s.top = '24px'; - s.left = '50%'; - s.marginLeft = -width / 2 + 'px'; - s.width = width + 'px'; - s.padding = '24px'; - s.overflow = 'hidden'; - s.background = '#fafafa'; - s.fontFamily = "'Roboto', sans-serif"; - s.boxShadow = '0px 5px 20px #666'; - dialog.appendChild(this.createH1_('Select your viewer')); - for (var id in options) { - dialog.appendChild(this.createChoice_(id, options[id].label)); - } - dialog.appendChild(this.createButton_('Save', this.onSave_.bind(this))); - container.appendChild(overlay); - container.appendChild(dialog); - return container; -}; -ViewerSelector.prototype.createH1_ = function (name) { - var h1 = document.createElement('h1'); - var s = h1.style; - s.color = 'black'; - s.fontSize = '20px'; - s.fontWeight = 'bold'; - s.marginTop = 0; - s.marginBottom = '24px'; - h1.innerHTML = name; - return h1; -}; -ViewerSelector.prototype.createChoice_ = function (id, name) { - var div = document.createElement('div'); - div.style.marginTop = '8px'; - div.style.color = 'black'; - var input = document.createElement('input'); - input.style.fontSize = '30px'; - input.setAttribute('id', id); - input.setAttribute('type', 'radio'); - input.setAttribute('value', id); - input.setAttribute('name', 'field'); - var label = document.createElement('label'); - label.style.marginLeft = '4px'; - label.setAttribute('for', id); - label.innerHTML = name; - div.appendChild(input); - div.appendChild(label); - return div; -}; -ViewerSelector.prototype.createButton_ = function (label, onclick) { - var button = document.createElement('button'); - button.innerHTML = label; - var s = button.style; - s.float = 'right'; - s.textTransform = 'uppercase'; - s.color = '#1094f7'; - s.fontSize = '14px'; - s.letterSpacing = 0; - s.border = 0; - s.background = 'none'; - s.marginTop = '16px'; - button.addEventListener('click', onclick); - return button; -}; -var commonjsGlobal$$1 = typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {}; -function unwrapExports$$1 (x) { - return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; -} -function createCommonjsModule$$1(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; -} -var NoSleep = createCommonjsModule$$1(function (module, exports) { -(function webpackUniversalModuleDefinition(root, factory) { - module.exports = factory(); -})(commonjsGlobal$$1, function() { -return (function(modules) { - var installedModules = {}; - function __webpack_require__(moduleId) { - if(installedModules[moduleId]) { - return installedModules[moduleId].exports; - } - var module = installedModules[moduleId] = { - i: moduleId, - l: false, - exports: {} - }; - modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - module.l = true; - return module.exports; - } - __webpack_require__.m = modules; - __webpack_require__.c = installedModules; - __webpack_require__.d = function(exports, name, getter) { - if(!__webpack_require__.o(exports, name)) { - Object.defineProperty(exports, name, { - configurable: false, - enumerable: true, - get: getter - }); - } - }; - __webpack_require__.n = function(module) { - var getter = module && module.__esModule ? - function getDefault() { return module['default']; } : - function getModuleExports() { return module; }; - __webpack_require__.d(getter, 'a', getter); - return getter; - }; - __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; - __webpack_require__.p = ""; - return __webpack_require__(__webpack_require__.s = 0); - }) - ([ - (function(module, exports, __webpack_require__) { -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -var mediaFile = __webpack_require__(1); -var oldIOS = typeof navigator !== 'undefined' && parseFloat(('' + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ''])[1]).replace('undefined', '3_2').replace('_', '.').replace('_', '')) < 10 && !window.MSStream; -var NoSleep = function () { - function NoSleep() { - _classCallCheck(this, NoSleep); - if (oldIOS) { - this.noSleepTimer = null; - } else { - this.noSleepVideo = document.createElement('video'); - this.noSleepVideo.setAttribute('playsinline', ''); - this.noSleepVideo.setAttribute('src', mediaFile); - this.noSleepVideo.addEventListener('timeupdate', function (e) { - if (this.noSleepVideo.currentTime > 0.5) { - this.noSleepVideo.currentTime = Math.random(); - } - }.bind(this)); - } - } - _createClass(NoSleep, [{ - key: 'enable', - value: function enable() { - if (oldIOS) { - this.disable(); - this.noSleepTimer = window.setInterval(function () { - window.location.href = '/'; - window.setTimeout(window.stop, 0); - }, 15000); - } else { - this.noSleepVideo.play(); - } - } - }, { - key: 'disable', - value: function disable() { - if (oldIOS) { - if (this.noSleepTimer) { - window.clearInterval(this.noSleepTimer); - this.noSleepTimer = null; - } - } else { - this.noSleepVideo.pause(); - } - } - }]); - return NoSleep; -}(); -module.exports = NoSleep; - }), - (function(module, exports, __webpack_require__) { -module.exports = 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA='; - }) - ]); -}); -}); -var NoSleep$1 = unwrapExports$$1(NoSleep); -var nextDisplayId = 1000; -var defaultLeftBounds = [0, 0, 0.5, 1]; -var defaultRightBounds = [0.5, 0, 0.5, 1]; -var raf = window.requestAnimationFrame; -var caf = window.cancelAnimationFrame; -function VRFrameData() { - this.leftProjectionMatrix = new Float32Array(16); - this.leftViewMatrix = new Float32Array(16); - this.rightProjectionMatrix = new Float32Array(16); - this.rightViewMatrix = new Float32Array(16); - this.pose = null; -} -function VRDisplayCapabilities(config) { - Object.defineProperties(this, { - hasPosition: { - writable: false, enumerable: true, value: config.hasPosition - }, - hasExternalDisplay: { - writable: false, enumerable: true, value: config.hasExternalDisplay - }, - canPresent: { - writable: false, enumerable: true, value: config.canPresent - }, - maxLayers: { - writable: false, enumerable: true, value: config.maxLayers - }, - hasOrientation: { - enumerable: true, get: function get() { - deprecateWarning('VRDisplayCapabilities.prototype.hasOrientation', 'VRDisplay.prototype.getFrameData'); - return config.hasOrientation; - } - } - }); -} -function VRDisplay(config) { - config = config || {}; - var USE_WAKELOCK = 'wakelock' in config ? config.wakelock : true; - this.isPolyfilled = true; - this.displayId = nextDisplayId++; - this.displayName = ''; - this.depthNear = 0.01; - this.depthFar = 10000.0; - this.isPresenting = false; - Object.defineProperty(this, 'isConnected', { - get: function get() { - deprecateWarning('VRDisplay.prototype.isConnected', 'VRDisplayCapabilities.prototype.hasExternalDisplay'); - return false; - } - }); - this.capabilities = new VRDisplayCapabilities({ - hasPosition: false, - hasOrientation: false, - hasExternalDisplay: false, - canPresent: false, - maxLayers: 1 - }); - this.stageParameters = null; - this.waitingForPresent_ = false; - this.layer_ = null; - this.originalParent_ = null; - this.fullscreenElement_ = null; - this.fullscreenWrapper_ = null; - this.fullscreenElementCachedStyle_ = null; - this.fullscreenEventTarget_ = null; - this.fullscreenChangeHandler_ = null; - this.fullscreenErrorHandler_ = null; - if (USE_WAKELOCK && isMobile()) { - this.wakelock_ = new NoSleep$1(); - } -} -VRDisplay.prototype.getFrameData = function (frameData) { - return frameDataFromPose(frameData, this._getPose(), this); -}; -VRDisplay.prototype.getPose = function () { - deprecateWarning('VRDisplay.prototype.getPose', 'VRDisplay.prototype.getFrameData'); - return this._getPose(); -}; -VRDisplay.prototype.resetPose = function () { - deprecateWarning('VRDisplay.prototype.resetPose'); - return this._resetPose(); -}; -VRDisplay.prototype.getImmediatePose = function () { - deprecateWarning('VRDisplay.prototype.getImmediatePose', 'VRDisplay.prototype.getFrameData'); - return this._getPose(); -}; -VRDisplay.prototype.requestAnimationFrame = function (callback) { - return raf(callback); -}; -VRDisplay.prototype.cancelAnimationFrame = function (id) { - return caf(id); -}; -VRDisplay.prototype.wrapForFullscreen = function (element) { - if (isIOS()) { - return element; - } - if (!this.fullscreenWrapper_) { - this.fullscreenWrapper_ = document.createElement('div'); - var cssProperties = ['height: ' + Math.min(screen.height, screen.width) + 'px !important', 'top: 0 !important', 'left: 0 !important', 'right: 0 !important', 'border: 0', 'margin: 0', 'padding: 0', 'z-index: 999999 !important', 'position: fixed']; - this.fullscreenWrapper_.setAttribute('style', cssProperties.join('; ') + ';'); - this.fullscreenWrapper_.classList.add('webvr-polyfill-fullscreen-wrapper'); - } - if (this.fullscreenElement_ == element) { - return this.fullscreenWrapper_; - } - if (this.fullscreenElement_) { - if (this.originalParent_) { - this.originalParent_.appendChild(this.fullscreenElement_); - } else { - this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_); - } - } - this.fullscreenElement_ = element; - this.originalParent_ = element.parentElement; - if (!this.originalParent_) { - document.body.appendChild(element); - } - if (!this.fullscreenWrapper_.parentElement) { - var parent = this.fullscreenElement_.parentElement; - parent.insertBefore(this.fullscreenWrapper_, this.fullscreenElement_); - parent.removeChild(this.fullscreenElement_); - } - this.fullscreenWrapper_.insertBefore(this.fullscreenElement_, this.fullscreenWrapper_.firstChild); - this.fullscreenElementCachedStyle_ = this.fullscreenElement_.getAttribute('style'); - var self = this; - function applyFullscreenElementStyle() { - if (!self.fullscreenElement_) { - return; - } - var cssProperties = ['position: absolute', 'top: 0', 'left: 0', 'width: ' + Math.max(screen.width, screen.height) + 'px', 'height: ' + Math.min(screen.height, screen.width) + 'px', 'border: 0', 'margin: 0', 'padding: 0']; - self.fullscreenElement_.setAttribute('style', cssProperties.join('; ') + ';'); - } - applyFullscreenElementStyle(); - return this.fullscreenWrapper_; -}; -VRDisplay.prototype.removeFullscreenWrapper = function () { - if (!this.fullscreenElement_) { - return; - } - var element = this.fullscreenElement_; - if (this.fullscreenElementCachedStyle_) { - element.setAttribute('style', this.fullscreenElementCachedStyle_); - } else { - element.removeAttribute('style'); - } - this.fullscreenElement_ = null; - this.fullscreenElementCachedStyle_ = null; - var parent = this.fullscreenWrapper_.parentElement; - this.fullscreenWrapper_.removeChild(element); - if (this.originalParent_ === parent) { - parent.insertBefore(element, this.fullscreenWrapper_); - } - else if (this.originalParent_) { - this.originalParent_.appendChild(element); - } - parent.removeChild(this.fullscreenWrapper_); - return element; -}; -VRDisplay.prototype.requestPresent = function (layers) { - var wasPresenting = this.isPresenting; - var self = this; - if (!(layers instanceof Array)) { - deprecateWarning('VRDisplay.prototype.requestPresent with non-array argument', 'an array of VRLayers as the first argument'); - layers = [layers]; - } - return new Promise(function (resolve, reject) { - if (!self.capabilities.canPresent) { - reject(new Error('VRDisplay is not capable of presenting.')); - return; - } - if (layers.length == 0 || layers.length > self.capabilities.maxLayers) { - reject(new Error('Invalid number of layers.')); - return; - } - var incomingLayer = layers[0]; - if (!incomingLayer.source) { - resolve(); - return; - } - var leftBounds = incomingLayer.leftBounds || defaultLeftBounds; - var rightBounds = incomingLayer.rightBounds || defaultRightBounds; - if (wasPresenting) { - var layer = self.layer_; - if (layer.source !== incomingLayer.source) { - layer.source = incomingLayer.source; - } - for (var i = 0; i < 4; i++) { - layer.leftBounds[i] = leftBounds[i]; - layer.rightBounds[i] = rightBounds[i]; - } - self.wrapForFullscreen(self.layer_.source); - self.updatePresent_(); - resolve(); - return; - } - self.layer_ = { - predistorted: incomingLayer.predistorted, - source: incomingLayer.source, - leftBounds: leftBounds.slice(0), - rightBounds: rightBounds.slice(0) - }; - self.waitingForPresent_ = false; - if (self.layer_ && self.layer_.source) { - var fullscreenElement = self.wrapForFullscreen(self.layer_.source); - var onFullscreenChange = function onFullscreenChange() { - var actualFullscreenElement = getFullscreenElement(); - self.isPresenting = fullscreenElement === actualFullscreenElement; - if (self.isPresenting) { - if (screen.orientation && screen.orientation.lock) { - screen.orientation.lock('landscape-primary').catch(function (error) { - console.error('screen.orientation.lock() failed due to', error.message); - }); - } - self.waitingForPresent_ = false; - self.beginPresent_(); - resolve(); - } else { - if (screen.orientation && screen.orientation.unlock) { - screen.orientation.unlock(); - } - self.removeFullscreenWrapper(); - self.disableWakeLock(); - self.endPresent_(); - self.removeFullscreenListeners_(); - } - self.fireVRDisplayPresentChange_(); - }; - var onFullscreenError = function onFullscreenError() { - if (!self.waitingForPresent_) { - return; - } - self.removeFullscreenWrapper(); - self.removeFullscreenListeners_(); - self.disableWakeLock(); - self.waitingForPresent_ = false; - self.isPresenting = false; - reject(new Error('Unable to present.')); - }; - self.addFullscreenListeners_(fullscreenElement, onFullscreenChange, onFullscreenError); - if (requestFullscreen(fullscreenElement)) { - self.enableWakeLock(); - self.waitingForPresent_ = true; - } else if (isIOS() || isWebViewAndroid()) { - self.enableWakeLock(); - self.isPresenting = true; - self.beginPresent_(); - self.fireVRDisplayPresentChange_(); - resolve(); - } - } - if (!self.waitingForPresent_ && !isIOS()) { - exitFullscreen(); - reject(new Error('Unable to present.')); - } - }); -}; -VRDisplay.prototype.exitPresent = function () { - var wasPresenting = this.isPresenting; - var self = this; - this.isPresenting = false; - this.layer_ = null; - this.disableWakeLock(); - return new Promise(function (resolve, reject) { - if (wasPresenting) { - if (!exitFullscreen() && isIOS()) { - self.endPresent_(); - self.fireVRDisplayPresentChange_(); - } - if (isWebViewAndroid()) { - self.removeFullscreenWrapper(); - self.removeFullscreenListeners_(); - self.endPresent_(); - self.fireVRDisplayPresentChange_(); - } - resolve(); - } else { - reject(new Error('Was not presenting to VRDisplay.')); - } - }); -}; -VRDisplay.prototype.getLayers = function () { - if (this.layer_) { - return [this.layer_]; - } - return []; -}; -VRDisplay.prototype.fireVRDisplayPresentChange_ = function () { - var event = new CustomEvent('vrdisplaypresentchange', { detail: { display: this } }); - window.dispatchEvent(event); -}; -VRDisplay.prototype.fireVRDisplayConnect_ = function () { - var event = new CustomEvent('vrdisplayconnect', { detail: { display: this } }); - window.dispatchEvent(event); -}; -VRDisplay.prototype.addFullscreenListeners_ = function (element, changeHandler, errorHandler) { - this.removeFullscreenListeners_(); - this.fullscreenEventTarget_ = element; - this.fullscreenChangeHandler_ = changeHandler; - this.fullscreenErrorHandler_ = errorHandler; - if (changeHandler) { - if (document.fullscreenEnabled) { - element.addEventListener('fullscreenchange', changeHandler, false); - } else if (document.webkitFullscreenEnabled) { - element.addEventListener('webkitfullscreenchange', changeHandler, false); - } else if (document.mozFullScreenEnabled) { - document.addEventListener('mozfullscreenchange', changeHandler, false); - } else if (document.msFullscreenEnabled) { - element.addEventListener('msfullscreenchange', changeHandler, false); - } - } - if (errorHandler) { - if (document.fullscreenEnabled) { - element.addEventListener('fullscreenerror', errorHandler, false); - } else if (document.webkitFullscreenEnabled) { - element.addEventListener('webkitfullscreenerror', errorHandler, false); - } else if (document.mozFullScreenEnabled) { - document.addEventListener('mozfullscreenerror', errorHandler, false); - } else if (document.msFullscreenEnabled) { - element.addEventListener('msfullscreenerror', errorHandler, false); - } - } -}; -VRDisplay.prototype.removeFullscreenListeners_ = function () { - if (!this.fullscreenEventTarget_) return; - var element = this.fullscreenEventTarget_; - if (this.fullscreenChangeHandler_) { - var changeHandler = this.fullscreenChangeHandler_; - element.removeEventListener('fullscreenchange', changeHandler, false); - element.removeEventListener('webkitfullscreenchange', changeHandler, false); - document.removeEventListener('mozfullscreenchange', changeHandler, false); - element.removeEventListener('msfullscreenchange', changeHandler, false); - } - if (this.fullscreenErrorHandler_) { - var errorHandler = this.fullscreenErrorHandler_; - element.removeEventListener('fullscreenerror', errorHandler, false); - element.removeEventListener('webkitfullscreenerror', errorHandler, false); - document.removeEventListener('mozfullscreenerror', errorHandler, false); - element.removeEventListener('msfullscreenerror', errorHandler, false); - } - this.fullscreenEventTarget_ = null; - this.fullscreenChangeHandler_ = null; - this.fullscreenErrorHandler_ = null; -}; -VRDisplay.prototype.enableWakeLock = function () { - if (this.wakelock_) { - this.wakelock_.enable(); - } -}; -VRDisplay.prototype.disableWakeLock = function () { - if (this.wakelock_) { - this.wakelock_.disable(); - } -}; -VRDisplay.prototype.beginPresent_ = function () { -}; -VRDisplay.prototype.endPresent_ = function () { -}; -VRDisplay.prototype.submitFrame = function (pose) { -}; -VRDisplay.prototype.getEyeParameters = function (whichEye) { - return null; -}; -var config = { - ADDITIONAL_VIEWERS: [], - DEFAULT_VIEWER: '', - MOBILE_WAKE_LOCK: true, - DEBUG: false, - DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json', - K_FILTER: 0.98, - PREDICTION_TIME_S: 0.040, - CARDBOARD_UI_DISABLED: false, - ROTATE_INSTRUCTIONS_DISABLED: false, - YAW_ONLY: false, - BUFFER_SCALE: 0.5, - DIRTY_SUBMIT_FRAME_BINDINGS: false -}; -var Eye = { - LEFT: 'left', - RIGHT: 'right' -}; -function CardboardVRDisplay(config$$1) { - var defaults = extend({}, config); - config$$1 = extend(defaults, config$$1 || {}); - VRDisplay.call(this, { - wakelock: config$$1.MOBILE_WAKE_LOCK - }); - this.config = config$$1; - this.displayName = 'Cardboard VRDisplay'; - this.capabilities = new VRDisplayCapabilities({ - hasPosition: false, - hasOrientation: true, - hasExternalDisplay: false, - canPresent: true, - maxLayers: 1 - }); - this.stageParameters = null; - this.bufferScale_ = this.config.BUFFER_SCALE; - this.poseSensor_ = new PoseSensor(this.config); - this.distorter_ = null; - this.cardboardUI_ = null; - this.dpdb_ = new Dpdb(this.config.DPDB_URL, this.onDeviceParamsUpdated_.bind(this)); - this.deviceInfo_ = new DeviceInfo(this.dpdb_.getDeviceParams(), config$$1.ADDITIONAL_VIEWERS); - this.viewerSelector_ = new ViewerSelector(config$$1.DEFAULT_VIEWER); - this.viewerSelector_.onChange(this.onViewerChanged_.bind(this)); - this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer()); - if (!this.config.ROTATE_INSTRUCTIONS_DISABLED) { - this.rotateInstructions_ = new RotateInstructions(); - } - if (isIOS()) { - window.addEventListener('resize', this.onResize_.bind(this)); - } -} -CardboardVRDisplay.prototype = Object.create(VRDisplay.prototype); -CardboardVRDisplay.prototype._getPose = function () { - return { - position: null, - orientation: this.poseSensor_.getOrientation(), - linearVelocity: null, - linearAcceleration: null, - angularVelocity: null, - angularAcceleration: null - }; -}; -CardboardVRDisplay.prototype._resetPose = function () { - if (this.poseSensor_.resetPose) { - this.poseSensor_.resetPose(); - } -}; -CardboardVRDisplay.prototype._getFieldOfView = function (whichEye) { - var fieldOfView; - if (whichEye == Eye.LEFT) { - fieldOfView = this.deviceInfo_.getFieldOfViewLeftEye(); - } else if (whichEye == Eye.RIGHT) { - fieldOfView = this.deviceInfo_.getFieldOfViewRightEye(); - } else { - console.error('Invalid eye provided: %s', whichEye); - return null; - } - return fieldOfView; -}; -CardboardVRDisplay.prototype._getEyeOffset = function (whichEye) { - var offset; - if (whichEye == Eye.LEFT) { - offset = [-this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0]; - } else if (whichEye == Eye.RIGHT) { - offset = [this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0]; - } else { - console.error('Invalid eye provided: %s', whichEye); - return null; - } - return offset; -}; -CardboardVRDisplay.prototype.getEyeParameters = function (whichEye) { - var offset = this._getEyeOffset(whichEye); - var fieldOfView = this._getFieldOfView(whichEye); - var eyeParams = { - offset: offset, - renderWidth: this.deviceInfo_.device.width * 0.5 * this.bufferScale_, - renderHeight: this.deviceInfo_.device.height * this.bufferScale_ - }; - Object.defineProperty(eyeParams, 'fieldOfView', { - enumerable: true, - get: function get() { - deprecateWarning('VRFieldOfView', 'VRFrameData\'s projection matrices'); - return fieldOfView; - } - }); - return eyeParams; -}; -CardboardVRDisplay.prototype.onDeviceParamsUpdated_ = function (newParams) { - if (this.config.DEBUG) { - console.log('DPDB reported that device params were updated.'); - } - this.deviceInfo_.updateDeviceParams(newParams); - if (this.distorter_) { - this.distorter_.updateDeviceInfo(this.deviceInfo_); - } -}; -CardboardVRDisplay.prototype.updateBounds_ = function () { - if (this.layer_ && this.distorter_ && (this.layer_.leftBounds || this.layer_.rightBounds)) { - this.distorter_.setTextureBounds(this.layer_.leftBounds, this.layer_.rightBounds); - } -}; -CardboardVRDisplay.prototype.beginPresent_ = function () { - var gl = this.layer_.source.getContext('webgl'); - if (!gl) gl = this.layer_.source.getContext('experimental-webgl'); - if (!gl) gl = this.layer_.source.getContext('webgl2'); - if (!gl) return; - if (this.layer_.predistorted) { - if (!this.config.CARDBOARD_UI_DISABLED) { - gl.canvas.width = getScreenWidth() * this.bufferScale_; - gl.canvas.height = getScreenHeight() * this.bufferScale_; - this.cardboardUI_ = new CardboardUI(gl); - } - } else { - if (!this.config.CARDBOARD_UI_DISABLED) { - this.cardboardUI_ = new CardboardUI(gl); - } - this.distorter_ = new CardboardDistorter(gl, this.cardboardUI_, this.config.BUFFER_SCALE, this.config.DIRTY_SUBMIT_FRAME_BINDINGS); - this.distorter_.updateDeviceInfo(this.deviceInfo_); - } - if (this.cardboardUI_) { - this.cardboardUI_.listen(function (e) { - this.viewerSelector_.show(this.layer_.source.parentElement); - e.stopPropagation(); - e.preventDefault(); - }.bind(this), function (e) { - this.exitPresent(); - e.stopPropagation(); - e.preventDefault(); - }.bind(this)); - } - if (this.rotateInstructions_) { - if (isLandscapeMode() && isMobile()) { - this.rotateInstructions_.showTemporarily(3000, this.layer_.source.parentElement); - } else { - this.rotateInstructions_.update(); - } - } - this.orientationHandler = this.onOrientationChange_.bind(this); - window.addEventListener('orientationchange', this.orientationHandler); - this.vrdisplaypresentchangeHandler = this.updateBounds_.bind(this); - window.addEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler); - this.fireVRDisplayDeviceParamsChange_(); -}; -CardboardVRDisplay.prototype.endPresent_ = function () { - if (this.distorter_) { - this.distorter_.destroy(); - this.distorter_ = null; - } - if (this.cardboardUI_) { - this.cardboardUI_.destroy(); - this.cardboardUI_ = null; - } - if (this.rotateInstructions_) { - this.rotateInstructions_.hide(); - } - this.viewerSelector_.hide(); - window.removeEventListener('orientationchange', this.orientationHandler); - window.removeEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler); -}; -CardboardVRDisplay.prototype.updatePresent_ = function () { - this.endPresent_(); - this.beginPresent_(); -}; -CardboardVRDisplay.prototype.submitFrame = function (pose) { - if (this.distorter_) { - this.updateBounds_(); - this.distorter_.submitFrame(); - } else if (this.cardboardUI_ && this.layer_) { - var gl = this.layer_.source.getContext('webgl'); - if (!gl) gl = this.layer_.source.getContext('experimental-webgl'); - if (!gl) gl = this.layer_.source.getContext('webgl2'); - var canvas = gl.canvas; - if (canvas.width != this.lastWidth || canvas.height != this.lastHeight) { - this.cardboardUI_.onResize(); - } - this.lastWidth = canvas.width; - this.lastHeight = canvas.height; - this.cardboardUI_.render(); - } -}; -CardboardVRDisplay.prototype.onOrientationChange_ = function (e) { - this.viewerSelector_.hide(); - if (this.rotateInstructions_) { - this.rotateInstructions_.update(); - } - this.onResize_(); -}; -CardboardVRDisplay.prototype.onResize_ = function (e) { - if (this.layer_) { - var gl = this.layer_.source.getContext('webgl'); - if (!gl) gl = this.layer_.source.getContext('experimental-webgl'); - if (!gl) gl = this.layer_.source.getContext('webgl2'); - var cssProperties = ['position: absolute', 'top: 0', 'left: 0', - 'width: 100vw', 'height: 100vh', 'border: 0', 'margin: 0', - 'padding: 0px', 'box-sizing: content-box']; - gl.canvas.setAttribute('style', cssProperties.join('; ') + ';'); - safariCssSizeWorkaround(gl.canvas); - } -}; -CardboardVRDisplay.prototype.onViewerChanged_ = function (viewer) { - this.deviceInfo_.setViewer(viewer); - if (this.distorter_) { - this.distorter_.updateDeviceInfo(this.deviceInfo_); - } - this.fireVRDisplayDeviceParamsChange_(); -}; -CardboardVRDisplay.prototype.fireVRDisplayDeviceParamsChange_ = function () { - var event = new CustomEvent('vrdisplaydeviceparamschange', { - detail: { - vrdisplay: this, - deviceInfo: this.deviceInfo_ - } - }); - window.dispatchEvent(event); -}; -CardboardVRDisplay.VRFrameData = VRFrameData; -CardboardVRDisplay.VRDisplay = VRDisplay; -return CardboardVRDisplay; -}))); -}); -var CardboardVRDisplay = unwrapExports(cardboardVrDisplay); - -class XRDevice extends EventTarget { - constructor(global) { - super(); - this.global = global; - this.onWindowResize = this.onWindowResize.bind(this); - this.global.window.addEventListener('resize', this.onWindowResize); - this.environmentBlendMode = 'opaque'; - } - onBaseLayerSet(sessionId, layer) { throw new Error('Not implemented'); } - isSessionSupported(mode) { throw new Error('Not implemented'); } - isFeatureSupported(featureDescriptor) { throw new Error('Not implemented'); } - async requestSession(mode, enabledFeatures) { throw new Error('Not implemented'); } - requestAnimationFrame(callback) { throw new Error('Not implemented'); } - onFrameStart(sessionId) { throw new Error('Not implemented'); } - onFrameEnd(sessionId) { throw new Error('Not implemented'); } - doesSessionSupportReferenceSpace(sessionId, type) { throw new Error('Not implemented'); } - requestStageBounds() { throw new Error('Not implemented'); } - async requestFrameOfReferenceTransform(type, options) { - return undefined; - } - cancelAnimationFrame(handle) { throw new Error('Not implemented'); } - endSession(sessionId) { throw new Error('Not implemented'); } - getViewport(sessionId, eye, layer, target) { throw new Error('Not implemented'); } - getProjectionMatrix(eye) { throw new Error('Not implemented'); } - getBasePoseMatrix() { throw new Error('Not implemented'); } - getBaseViewMatrix(eye) { throw new Error('Not implemented'); } - getInputSources() { throw new Error('Not implemented'); } - getInputPose(inputSource, coordinateSystem, poseType) { throw new Error('Not implemented'); } - onWindowResize() { - this.onWindowResize(); - } -} - -let daydream = { - mapping: '', - profiles: ['google-daydream', 'generic-trigger-touchpad'], - buttons: { - length: 3, - 0: null, - 1: null, - 2: 0 - }, -}; -let viveFocus = { - mapping: 'xr-standard', - profiles: ['htc-vive-focus', 'generic-trigger-touchpad'], - buttons: { - length: 3, - 0: 1, - 1: null, - 2: 0 - }, -}; -let oculusGo = { - mapping: 'xr-standard', - profiles: ['oculus-go', 'generic-trigger-touchpad'], - buttons: { - length: 3, - 0: 1, - 1: null, - 2: 0 - }, - gripTransform: { - orientation: [Math.PI * 0.11, 0, 0, 1] - } -}; -let oculusTouch = { - mapping: 'xr-standard', - displayProfiles: { - 'Oculus Quest': ['oculus-touch-v2', 'oculus-touch', 'generic-trigger-squeeze-thumbstick'] - }, - profiles: ['oculus-touch', 'generic-trigger-squeeze-thumbstick'], - axes: { - length: 4, - 0: null, - 1: null, - 2: 0, - 3: 1 - }, - buttons: { - length: 7, - 0: 1, - 1: 2, - 2: null, - 3: 0, - 4: 3, - 5: 4, - 6: null - }, - gripTransform: { - position: [0, -0.02, 0.04, 1], - orientation: [Math.PI * 0.11, 0, 0, 1] - } -}; -let openVr = { - mapping: 'xr-standard', - profiles: ['htc-vive', 'generic-trigger-squeeze-touchpad'], - displayProfiles: { - 'HTC Vive': ['htc-vive', 'generic-trigger-squeeze-touchpad'], - 'HTC Vive DVT': ['htc-vive', 'generic-trigger-squeeze-touchpad'], - 'Valve Index': ['valve-index', 'generic-trigger-squeeze-touchpad-thumbstick'] - }, - buttons: { - length: 3, - 0: 1, - 1: 2, - 2: 0 - }, - gripTransform: { - position: [0, 0, 0.05, 1], - }, - targetRayTransform: { - orientation: [Math.PI * -0.08, 0, 0, 1] - }, - userAgentOverrides: { - "Firefox": { - axes: { - invert: [1, 3] - } - } - } -}; -let samsungGearVR = { - mapping: 'xr-standard', - profiles: ['samsung-gearvr', 'generic-trigger-touchpad'], - buttons: { - length: 3, - 0: 1, - 1: null, - 2: 0 - }, - gripTransform: { - orientation: [Math.PI * 0.11, 0, 0, 1] - } -}; -let samsungOdyssey = { - mapping: 'xr-standard', - profiles: ['samsung-odyssey', 'microsoft-mixed-reality', 'generic-trigger-squeeze-touchpad-thumbstick'], - buttons: { - length: 4, - 0: 1, - 1: 0, - 2: 2, - 3: 4, - }, - gripTransform: { - position: [0, -0.02, 0.04, 1], - orientation: [Math.PI * 0.11, 0, 0, 1] - } -}; -let windowsMixedReality = { - mapping: 'xr-standard', - profiles: ['microsoft-mixed-reality', 'generic-trigger-squeeze-touchpad-thumbstick'], - buttons: { - length: 4, - 0: 1, - 1: 0, - 2: 2, - 3: 4, - }, - gripTransform: { - position: [0, -0.02, 0.04, 1], - orientation: [Math.PI * 0.11, 0, 0, 1] - } -}; -let GamepadMappings = { - 'Daydream Controller': daydream, - 'Gear VR Controller': samsungGearVR, - 'HTC Vive Focus Controller': viveFocus, - 'Oculus Go Controller': oculusGo, - 'Oculus Touch (Right)': oculusTouch, - 'Oculus Touch (Left)': oculusTouch, - 'OpenVR Gamepad': openVr, - 'Spatial Controller (Spatial Interaction Source) 045E-065A': windowsMixedReality, - 'Spatial Controller (Spatial Interaction Source) 045E-065D': samsungOdyssey, - 'Windows Mixed Reality (Right)': windowsMixedReality, - 'Windows Mixed Reality (Left)': windowsMixedReality, -}; - -const HEAD_ELBOW_OFFSET_RIGHTHANDED = fromValues$1(0.155, -0.465, -0.15); -const HEAD_ELBOW_OFFSET_LEFTHANDED = fromValues$1(-0.155, -0.465, -0.15); -const ELBOW_WRIST_OFFSET = fromValues$1(0, 0, -0.25); -const WRIST_CONTROLLER_OFFSET = fromValues$1(0, 0, 0.05); -const ARM_EXTENSION_OFFSET = fromValues$1(-0.08, 0.14, 0.08); -const ELBOW_BEND_RATIO = 0.4; -const EXTENSION_RATIO_WEIGHT = 0.4; -const MIN_ANGULAR_SPEED = 0.61; -const MIN_ANGLE_DELTA = 0.175; -const MIN_EXTENSION_COS = 0.12; -const MAX_EXTENSION_COS = 0.87; -const RAD_TO_DEG = 180 / Math.PI; -function eulerFromQuaternion(out, q, order) { - function clamp(value, min$$1, max$$1) { - return (value < min$$1 ? min$$1 : (value > max$$1 ? max$$1 : value)); - } - var sqx = q[0] * q[0]; - var sqy = q[1] * q[1]; - var sqz = q[2] * q[2]; - var sqw = q[3] * q[3]; - if ( order === 'XYZ' ) { - out[0] = Math.atan2( 2 * ( q[0] * q[3] - q[1] * q[2] ), ( sqw - sqx - sqy + sqz ) ); - out[1] = Math.asin( clamp( 2 * ( q[0] * q[2] + q[1] * q[3] ), -1, 1 ) ); - out[2] = Math.atan2( 2 * ( q[2] * q[3] - q[0] * q[1] ), ( sqw + sqx - sqy - sqz ) ); - } else if ( order === 'YXZ' ) { - out[0] = Math.asin( clamp( 2 * ( q[0] * q[3] - q[1] * q[2] ), -1, 1 ) ); - out[1] = Math.atan2( 2 * ( q[0] * q[2] + q[1] * q[3] ), ( sqw - sqx - sqy + sqz ) ); - out[2] = Math.atan2( 2 * ( q[0] * q[1] + q[2] * q[3] ), ( sqw - sqx + sqy - sqz ) ); - } else if ( order === 'ZXY' ) { - out[0] = Math.asin( clamp( 2 * ( q[0] * q[3] + q[1] * q[2] ), -1, 1 ) ); - out[1] = Math.atan2( 2 * ( q[1] * q[3] - q[2] * q[0] ), ( sqw - sqx - sqy + sqz ) ); - out[2] = Math.atan2( 2 * ( q[2] * q[3] - q[0] * q[1] ), ( sqw - sqx + sqy - sqz ) ); - } else if ( order === 'ZYX' ) { - out[0] = Math.atan2( 2 * ( q[0] * q[3] + q[2] * q[1] ), ( sqw - sqx - sqy + sqz ) ); - out[1] = Math.asin( clamp( 2 * ( q[1] * q[3] - q[0] * q[2] ), -1, 1 ) ); - out[2] = Math.atan2( 2 * ( q[0] * q[1] + q[2] * q[3] ), ( sqw + sqx - sqy - sqz ) ); - } else if ( order === 'YZX' ) { - out[0] = Math.atan2( 2 * ( q[0] * q[3] - q[2] * q[1] ), ( sqw - sqx + sqy - sqz ) ); - out[1] = Math.atan2( 2 * ( q[1] * q[3] - q[0] * q[2] ), ( sqw + sqx - sqy - sqz ) ); - out[2] = Math.asin( clamp( 2 * ( q[0] * q[1] + q[2] * q[3] ), -1, 1 ) ); - } else if ( order === 'XZY' ) { - out[0] = Math.atan2( 2 * ( q[0] * q[3] + q[1] * q[2] ), ( sqw - sqx + sqy - sqz ) ); - out[1] = Math.atan2( 2 * ( q[0] * q[2] + q[1] * q[3] ), ( sqw + sqx - sqy - sqz ) ); - out[2] = Math.asin( clamp( 2 * ( q[2] * q[3] - q[0] * q[1] ), -1, 1 ) ); - } else { - console.log('No order given for quaternion to euler conversion.'); - return; - } -} -class OrientationArmModel { - constructor() { - this.hand = 'right'; - this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED; - this.controllerQ = create$4(); - this.lastControllerQ = create$4(); - this.headQ = create$4(); - this.headPos = create$1(); - this.elbowPos = create$1(); - this.wristPos = create$1(); - this.time = null; - this.lastTime = null; - this.rootQ = create$4(); - this.position = create$1(); - } - setHandedness(hand) { - if (this.hand != hand) { - this.hand = hand; - if (this.hand == 'left') { - this.headElbowOffset = HEAD_ELBOW_OFFSET_LEFTHANDED; - } else { - this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED; - } - } - } - update(controllerOrientation, headPoseMatrix) { - this.time = now$1(); - if (controllerOrientation) { - copy$4(this.lastControllerQ, this.controllerQ); - copy$4(this.controllerQ, controllerOrientation); - } - if (headPoseMatrix) { - getTranslation(this.headPos, headPoseMatrix); - getRotation(this.headQ, headPoseMatrix); - } - let headYawQ = this.getHeadYawOrientation_(); - let angleDelta = this.quatAngle_(this.lastControllerQ, this.controllerQ); - let timeDelta = (this.time - this.lastTime) / 1000; - let controllerAngularSpeed = angleDelta / timeDelta; - if (controllerAngularSpeed > MIN_ANGULAR_SPEED) { - slerp(this.rootQ, this.rootQ, headYawQ, - Math.min(angleDelta / MIN_ANGLE_DELTA, 1.0)); - } else { - copy$4(this.rootQ, headYawQ); - } - let controllerForward = fromValues$1(0, 0, -1.0); - transformQuat(controllerForward, controllerForward, this.controllerQ); - let controllerDotY = dot(controllerForward, [0, 1, 0]); - let extensionRatio = this.clamp_( - (controllerDotY - MIN_EXTENSION_COS) / MAX_EXTENSION_COS, 0.0, 1.0); - let controllerCameraQ = clone$4(this.rootQ); - invert$2(controllerCameraQ, controllerCameraQ); - multiply$4(controllerCameraQ, controllerCameraQ, this.controllerQ); - let elbowPos = this.elbowPos; - copy$1(elbowPos, this.headPos); - add$1(elbowPos, elbowPos, this.headElbowOffset); - let elbowOffset = clone$1(ARM_EXTENSION_OFFSET); - scale$1(elbowOffset, elbowOffset, extensionRatio); - add$1(elbowPos, elbowPos, elbowOffset); - let totalAngle = this.quatAngle_(controllerCameraQ, create$4()); - let totalAngleDeg = totalAngle * RAD_TO_DEG; - let lerpSuppression = 1 - Math.pow(totalAngleDeg / 180, 4);let elbowRatio = ELBOW_BEND_RATIO; - let wristRatio = 1 - ELBOW_BEND_RATIO; - let lerpValue = lerpSuppression * - (elbowRatio + wristRatio * extensionRatio * EXTENSION_RATIO_WEIGHT); - let wristQ = create$4(); - slerp(wristQ, wristQ, controllerCameraQ, lerpValue); - let invWristQ = invert$2(create$4(), wristQ); - let elbowQ = clone$4(controllerCameraQ); - multiply$4(elbowQ, elbowQ, invWristQ); - let wristPos = this.wristPos; - copy$1(wristPos, WRIST_CONTROLLER_OFFSET); - transformQuat(wristPos, wristPos, wristQ); - add$1(wristPos, wristPos, ELBOW_WRIST_OFFSET); - transformQuat(wristPos, wristPos, elbowQ); - add$1(wristPos, wristPos, elbowPos); - let offset = clone$1(ARM_EXTENSION_OFFSET); - scale$1(offset, offset, extensionRatio); - add$1(this.position, this.wristPos, offset); - transformQuat(this.position, this.position, this.rootQ); - this.lastTime = this.time; - } - getPosition() { - return this.position; - } - getHeadYawOrientation_() { - let headEuler = create$1(); - eulerFromQuaternion(headEuler, this.headQ, 'YXZ'); - let destinationQ = fromEuler(create$4(), 0, headEuler[1] * RAD_TO_DEG, 0); - return destinationQ; - } - clamp_(value, min$$1, max$$1) { - return Math.min(Math.max(value, min$$1), max$$1); - } - quatAngle_(q1, q2) { - let vec1 = [0, 0, -1]; - let vec2 = [0, 0, -1]; - transformQuat(vec1, vec1, q1); - transformQuat(vec2, vec2, q2); - return angle(vec1, vec2); - } -} - -const PRIVATE$18 = Symbol('@@webxr-polyfill/XRRemappedGamepad'); -const PLACEHOLDER_BUTTON = { pressed: false, touched: false, value: 0.0 }; -Object.freeze(PLACEHOLDER_BUTTON); -class XRRemappedGamepad { - constructor(gamepad, display, map) { - if (!map) { - map = {}; - } - if (map.userAgentOverrides) { - for (let agent in map.userAgentOverrides) { - if (navigator.userAgent.includes(agent)) { - let override = map.userAgentOverrides[agent]; - for (let key in override) { - if (key in map) { - Object.assign(map[key], override[key]); - } else { - map[key] = override[key]; - } - } - break; - } - } - } - let axes = new Array(map.axes && map.axes.length ? map.axes.length : gamepad.axes.length); - let buttons = new Array(map.buttons && map.buttons.length ? map.buttons.length : gamepad.buttons.length); - let gripTransform = null; - if (map.gripTransform) { - let orientation = map.gripTransform.orientation || [0, 0, 0, 1]; - gripTransform = create(); - fromRotationTranslation( - gripTransform, - normalize$2(orientation, orientation), - map.gripTransform.position || [0, 0, 0] - ); - } - let targetRayTransform = null; - if (map.targetRayTransform) { - let orientation = map.targetRayTransform.orientation || [0, 0, 0, 1]; - targetRayTransform = create(); - fromRotationTranslation( - targetRayTransform, - normalize$2(orientation, orientation), - map.targetRayTransform.position || [0, 0, 0] - ); - } - let profiles = map.profiles; - if (map.displayProfiles) { - if (display.displayName in map.displayProfiles) { - profiles = map.displayProfiles[display.displayName]; - } - } - this[PRIVATE$18] = { - gamepad, - map, - profiles: profiles || [gamepad.id], - mapping: map.mapping || gamepad.mapping, - axes, - buttons, - gripTransform, - targetRayTransform, - }; - this._update(); - } - _update() { - let gamepad = this[PRIVATE$18].gamepad; - let map = this[PRIVATE$18].map; - let axes = this[PRIVATE$18].axes; - for (let i = 0; i < axes.length; ++i) { - if (map.axes && i in map.axes) { - if (map.axes[i] === null) { - axes[i] = 0; - } else { - axes[i] = gamepad.axes[map.axes[i]]; - } - } else { - axes[i] = gamepad.axes[i]; - } - } - if (map.axes && map.axes.invert) { - for (let axis of map.axes.invert) { - if (axis < axes.length) { - axes[axis] *= -1; - } - } - } - let buttons = this[PRIVATE$18].buttons; - for (let i = 0; i < buttons.length; ++i) { - if (map.buttons && i in map.buttons) { - if (map.buttons[i] === null) { - buttons[i] = PLACEHOLDER_BUTTON; - } else { - buttons[i] = gamepad.buttons[map.buttons[i]]; - } - } else { - buttons[i] = gamepad.buttons[i]; - } - } - } - get id() { - return ''; - } - get _profiles() { - return this[PRIVATE$18].profiles; - } - get index() { - return -1; - } - get connected() { - return this[PRIVATE$18].gamepad.connected; - } - get timestamp() { - return this[PRIVATE$18].gamepad.timestamp; - } - get mapping() { - return this[PRIVATE$18].mapping; - } - get axes() { - return this[PRIVATE$18].axes; - } - get buttons() { - return this[PRIVATE$18].buttons; - } - get hapticActuators() { - return this[PRIVATE$18].gamepad.hapticActuators; - } -} -class GamepadXRInputSource { - constructor(polyfill, display, primaryButtonIndex = 0, primarySqueezeButtonIndex = -1) { - this.polyfill = polyfill; - this.display = display; - this.nativeGamepad = null; - this.gamepad = null; - this.inputSource = new XRInputSource(this); - this.lastPosition = create$1(); - this.emulatedPosition = false; - this.basePoseMatrix = create(); - this.outputMatrix = create(); - this.primaryButtonIndex = primaryButtonIndex; - this.primaryActionPressed = false; - this.primarySqueezeButtonIndex = primarySqueezeButtonIndex; - this.primarySqueezeActionPressed = false; - this.handedness = ''; - this.targetRayMode = 'gaze'; - this.armModel = null; - } - get profiles() { - return this.gamepad ? this.gamepad._profiles : []; - } - updateFromGamepad(gamepad) { - if (this.nativeGamepad !== gamepad) { - this.nativeGamepad = gamepad; - if (gamepad) { - this.gamepad = new XRRemappedGamepad(gamepad, this.display, GamepadMappings[gamepad.id]); - } else { - this.gamepad = null; - } - } - this.handedness = gamepad.hand === '' ? 'none' : gamepad.hand; - if (this.gamepad) { - this.gamepad._update(); - } - if (gamepad.pose) { - this.targetRayMode = 'tracked-pointer'; - this.emulatedPosition = !gamepad.pose.hasPosition; - } else if (gamepad.hand === '') { - this.targetRayMode = 'gaze'; - this.emulatedPosition = false; - } - } - updateBasePoseMatrix() { - if (this.nativeGamepad && this.nativeGamepad.pose) { - let pose = this.nativeGamepad.pose; - let position = pose.position; - let orientation = pose.orientation; - if (!position && !orientation) { - return; - } - if (!position) { - if (!pose.hasPosition) { - if (!this.armModel) { - this.armModel = new OrientationArmModel(); - } - this.armModel.setHandedness(this.nativeGamepad.hand); - this.armModel.update(orientation, this.polyfill.getBasePoseMatrix()); - position = this.armModel.getPosition(); - } else { - position = this.lastPosition; - } - } else { - this.lastPosition[0] = position[0]; - this.lastPosition[1] = position[1]; - this.lastPosition[2] = position[2]; - } - fromRotationTranslation(this.basePoseMatrix, orientation, position); - } else { - copy(this.basePoseMatrix, this.polyfill.getBasePoseMatrix()); - } - return this.basePoseMatrix; - } - getXRPose(coordinateSystem, poseType) { - this.updateBasePoseMatrix(); - switch(poseType) { - case "target-ray": - coordinateSystem._transformBasePoseMatrix(this.outputMatrix, this.basePoseMatrix); - if (this.gamepad && this.gamepad[PRIVATE$18].targetRayTransform) { - multiply(this.outputMatrix, this.outputMatrix, this.gamepad[PRIVATE$18].targetRayTransform); - } - break; - case "grip": - if (!this.nativeGamepad || !this.nativeGamepad.pose) { - return null; - } - coordinateSystem._transformBasePoseMatrix(this.outputMatrix, this.basePoseMatrix); - if (this.gamepad && this.gamepad[PRIVATE$18].gripTransform) { - multiply(this.outputMatrix, this.outputMatrix, this.gamepad[PRIVATE$18].gripTransform); - } - break; - default: - return null; - } - coordinateSystem._adjustForOriginOffset(this.outputMatrix); - return new XRPose(new XRRigidTransform(this.outputMatrix), this.emulatedPosition); - } -} - -const TEST_ENV = "production" === 'test'; -const EXTRA_PRESENTATION_ATTRIBUTES = { - highRefreshRate: true, -}; -const PRIMARY_BUTTON_MAP = { - oculus: 1, - openvr: 1, - 'spatial controller (spatial interaction source)': 1 -}; -let SESSION_ID = 0; -class Session { - constructor(mode, enabledFeatures, polyfillOptions={}) { - this.mode = mode; - this.enabledFeatures = enabledFeatures; - this.outputContext = null; - this.immersive = mode == 'immersive-vr' || mode == 'immersive-ar'; - this.ended = null; - this.baseLayer = null; - this.id = ++SESSION_ID; - this.modifiedCanvasLayer = false; - if (this.outputContext && !TEST_ENV) { - const renderContextType = polyfillOptions.renderContextType || '2d'; - this.renderContext = this.outputContext.canvas.getContext(renderContextType); - } - } -} -class WebVRDevice extends XRDevice { - constructor(global, display) { - const { canPresent } = display.capabilities; - super(global); - this.display = display; - this.frame = new global.VRFrameData(); - this.sessions = new Map(); - this.immersiveSession = null; - this.canPresent = canPresent; - this.baseModelMatrix = create(); - this.gamepadInputSources = {}; - this.tempVec3 = new Float32Array(3); - this.onVRDisplayPresentChange = this.onVRDisplayPresentChange.bind(this); - global.window.addEventListener('vrdisplaypresentchange', this.onVRDisplayPresentChange); - this.CAN_USE_GAMEPAD = global.navigator && ('getGamepads' in global.navigator); - this.HAS_BITMAP_SUPPORT = isImageBitmapSupported(global); - } - get depthNear() { return this.display.depthNear; } - set depthNear(val) { this.display.depthNear = val; } - get depthFar() { return this.display.depthFar; } - set depthFar(val) { this.display.depthFar = val; } - onBaseLayerSet(sessionId, layer) { - const session = this.sessions.get(sessionId); - const canvas = layer.context.canvas; - if (session.immersive) { - const left = this.display.getEyeParameters('left'); - const right = this.display.getEyeParameters('right'); - canvas.width = Math.max(left.renderWidth, right.renderWidth) * 2; - canvas.height = Math.max(left.renderHeight, right.renderHeight); - this.display.requestPresent([{ - source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES - }]).then(() => { - if (!TEST_ENV && !this.global.document.body.contains(canvas)) { - session.modifiedCanvasLayer = true; - this.global.document.body.appendChild(canvas); - applyCanvasStylesForMinimalRendering(canvas); - } - session.baseLayer = layer; - }); - } - else { - session.baseLayer = layer; - } - } - isSessionSupported(mode) { - if (mode == 'immersive-ar') { - return false; - } - if (mode == 'immersive-vr' && this.canPresent === false) { - return false; - } - return true; - } - isFeatureSupported(featureDescriptor) { - switch(featureDescriptor) { - case 'viewer': return true; - case 'local': return true; - case 'local-floor': return true; - case 'bounded': return false; - case 'unbounded': return false; - default: return false; - } - } - async requestSession(mode, enabledFeatures) { - if (!this.isSessionSupported(mode)) { - return Promise.reject(); - } - let immersive = mode == 'immersive-vr'; - if (immersive) { - const canvas = this.global.document.createElement('canvas'); - if (!TEST_ENV) { - const ctx = canvas.getContext('webgl'); - } - await this.display.requestPresent([{ - source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES }]); - } - const session = new Session(mode, enabledFeatures, { - renderContextType: this.HAS_BITMAP_SUPPORT ? 'bitmaprenderer' : '2d' - }); - this.sessions.set(session.id, session); - if (immersive) { - this.immersiveSession = session; - this.dispatchEvent('@@webxr-polyfill/vr-present-start', session.id); - } - return Promise.resolve(session.id); - } - requestAnimationFrame(callback) { - return this.display.requestAnimationFrame(callback); - } - getPrimaryButtonIndex(gamepad) { - let primaryButton = 0; - let name = gamepad.id.toLowerCase(); - for (let key in PRIMARY_BUTTON_MAP) { - if (name.includes(key)) { - primaryButton = PRIMARY_BUTTON_MAP[key]; - break; - } - } - return Math.min(primaryButton, gamepad.buttons.length - 1); - } - onFrameStart(sessionId, renderState) { - this.display.depthNear = renderState.depthNear; - this.display.depthFar = renderState.depthFar; - this.display.getFrameData(this.frame); - const session = this.sessions.get(sessionId); - if (session.immersive && this.CAN_USE_GAMEPAD) { - let prevInputSources = this.gamepadInputSources; - this.gamepadInputSources = {}; - let gamepads = this.global.navigator.getGamepads(); - for (let i = 0; i < gamepads.length; ++i) { - let gamepad = gamepads[i]; - if (gamepad && gamepad.displayId > 0) { - let inputSourceImpl = prevInputSources[i]; - if (!inputSourceImpl) { - inputSourceImpl = new GamepadXRInputSource(this, this.display, this.getPrimaryButtonIndex(gamepad)); - } - inputSourceImpl.updateFromGamepad(gamepad); - this.gamepadInputSources[i] = inputSourceImpl; - if (inputSourceImpl.primaryButtonIndex != -1) { - let primaryActionPressed = gamepad.buttons[inputSourceImpl.primaryButtonIndex].pressed; - if (primaryActionPressed && !inputSourceImpl.primaryActionPressed) { - this.dispatchEvent('@@webxr-polyfill/input-select-start', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); - } else if (!primaryActionPressed && inputSourceImpl.primaryActionPressed) { - this.dispatchEvent('@@webxr-polyfill/input-select-end', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); - } - inputSourceImpl.primaryActionPressed = primaryActionPressed; - } - if (inputSourceImpl.primarySqueezeButtonIndex != -1) { - let primarySqueezeActionPressed = gamepad.buttons[inputSourceImpl.primarySqueezeButtonIndex].pressed; - if (primarySqueezeActionPressed && !inputSourceImpl.primarySqueezeActionPressed) { - this.dispatchEvent('@@webxr-polyfill/input-squeeze-start', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); - } else if (!primarySqueezeActionPressed && inputSourceImpl.primarySqueezeActionPressed) { - this.dispatchEvent('@@webxr-polyfill/input-squeeze-end', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); - } - inputSourceImpl.primarySqueezeActionPressed = primarySqueezeActionPressed; - } - } - } - } - if (TEST_ENV) { - return; - } - if (!session.immersive && session.baseLayer) { - const canvas = session.baseLayer.context.canvas; - perspective(this.frame.leftProjectionMatrix, renderState.inlineVerticalFieldOfView, - canvas.width/canvas.height, renderState.depthNear, renderState.depthFar); - } - } - onFrameEnd(sessionId) { - const session = this.sessions.get(sessionId); - if (session.ended || !session.baseLayer) { - return; - } - if (session.outputContext && - !(session.immersive && !this.display.capabilities.hasExternalDisplay)) { - const mirroring = - session.immersive && this.display.capabilities.hasExternalDisplay; - const iCanvas = session.baseLayer.context.canvas; - const iWidth = mirroring ? iCanvas.width / 2 : iCanvas.width; - const iHeight = iCanvas.height; - if (!TEST_ENV) { - const oCanvas = session.outputContext.canvas; - const oWidth = oCanvas.width; - const oHeight = oCanvas.height; - const renderContext = session.renderContext; - if (this.HAS_BITMAP_SUPPORT) { - if (iCanvas.transferToImageBitmap) { - renderContext.transferFromImageBitmap(iCanvas.transferToImageBitmap()); - } - else { - this.global.createImageBitmap(iCanvas, 0, 0, iWidth, iHeight, { - resizeWidth: oWidth, - resizeHeight: oHeight, - }).then(bitmap => renderContext.transferFromImageBitmap(bitmap)); - } - } else { - renderContext.drawImage(iCanvas, 0, 0, iWidth, iHeight, - 0, 0, oWidth, oHeight); - } - } - } - if (session.immersive && session.baseLayer) { - this.display.submitFrame(); - } - } - cancelAnimationFrame(handle) { - this.display.cancelAnimationFrame(handle); - } - async endSession(sessionId) { - const session = this.sessions.get(sessionId); - if (session.ended) { - return; - } - if (session.immersive) { - return this.display.exitPresent(); - } else { - session.ended = true; - } - } - doesSessionSupportReferenceSpace(sessionId, type) { - const session = this.sessions.get(sessionId); - if (session.ended) { - return false; - } - return session.enabledFeatures.has(type); - } - requestStageBounds() { - if (this.display.stageParameters) { - const width = this.display.stageParameters.sizeX; - const depth = this.display.stageParameters.sizeZ; - const data = []; - data.push(-width / 2); - data.push(-depth / 2); - data.push(width / 2); - data.push(-depth / 2); - data.push(width / 2); - data.push(depth / 2); - data.push(-width / 2); - data.push(depth / 2); - return data; - } - return null; - } - async requestFrameOfReferenceTransform(type, options) { - if ((type === 'local-floor' || type === 'bounded-floor') && - this.display.stageParameters && - this.display.stageParameters.sittingToStandingTransform) { - return this.display.stageParameters.sittingToStandingTransform; - } - return null; - } - getProjectionMatrix(eye) { - if (eye === 'left') { - return this.frame.leftProjectionMatrix; - } else if (eye === 'right') { - return this.frame.rightProjectionMatrix; - } else if (eye === 'none') { - return this.frame.leftProjectionMatrix; - } else { - throw new Error(`eye must be of type 'left' or 'right'`); - } - } - getViewport(sessionId, eye, layer, target) { - const session = this.sessions.get(sessionId); - const { width, height } = layer.context.canvas; - if (!session.immersive) { - target.x = target.y = 0; - target.width = width; - target.height = height; - return true; - } - if (eye === 'left' || eye === 'none') { - target.x = 0; - } else if (eye === 'right') { - target.x = width / 2; - } else { - return false; - } - target.y = 0; - target.width = width / 2; - target.height = height; - return true; - } - getBasePoseMatrix() { - let { position, orientation } = this.frame.pose; - if (!position && !orientation) { - return this.baseModelMatrix; - } - if (!position) { - position = this.tempVec3; - position[0] = position[1] = position[2] = 0; - } - fromRotationTranslation(this.baseModelMatrix, orientation, position); - return this.baseModelMatrix; - } - getBaseViewMatrix(eye) { - if (eye === 'left' || eye === 'none') { - return this.frame.leftViewMatrix; - } else if (eye === 'right') { - return this.frame.rightViewMatrix; - } else { - throw new Error(`eye must be of type 'left' or 'right'`); - } - } - getInputSources() { - let inputSources = []; - for (let i in this.gamepadInputSources) { - inputSources.push(this.gamepadInputSources[i].inputSource); - } - return inputSources; - } - getInputPose(inputSource, coordinateSystem, poseType) { - if (!coordinateSystem) { - return null; - } - for (let i in this.gamepadInputSources) { - let inputSourceImpl = this.gamepadInputSources[i]; - if (inputSourceImpl.inputSource === inputSource) { - return inputSourceImpl.getXRPose(coordinateSystem, poseType); - } - } - return null; - } - onWindowResize() { - } - onVRDisplayPresentChange(e) { - if (!this.display.isPresenting) { - this.sessions.forEach(session => { - if (session.immersive && !session.ended) { - if (session.modifiedCanvasLayer) { - const canvas = session.baseLayer.context.canvas; - document.body.removeChild(canvas); - canvas.setAttribute('style', ''); - } - if (this.immersiveSession === session) { - this.immersiveSession = null; - } - this.dispatchEvent('@@webxr-polyfill/vr-present-end', session.id); - } - }); - } - } -} - -class CardboardXRDevice extends WebVRDevice { - constructor(global, cardboardConfig) { - const display = new CardboardVRDisplay(cardboardConfig || {}); - super(global, display); - this.display = display; - this.frame = { - rightViewMatrix: new Float32Array(16), - leftViewMatrix: new Float32Array(16), - rightProjectionMatrix: new Float32Array(16), - leftProjectionMatrix: new Float32Array(16), - pose: null, - timestamp: null, - }; - } -} - -const TEST_ENV$1 = "production" === 'test'; -let SESSION_ID$1 = 0; -class Session$1 { - constructor(mode, enabledFeatures) { - this.mode = mode; - this.enabledFeatures = enabledFeatures; - this.ended = null; - this.baseLayer = null; - this.id = ++SESSION_ID$1; - } -} -class InlineDevice extends XRDevice { - constructor(global) { - super(global); - this.sessions = new Map(); - this.projectionMatrix = create(); - this.identityMatrix = create(); - } - onBaseLayerSet(sessionId, layer) { - const session = this.sessions.get(sessionId); - session.baseLayer = layer; - } - isSessionSupported(mode) { - return mode == 'inline'; - } - isFeatureSupported(featureDescriptor) { - switch(featureDescriptor) { - case 'viewer': return true; - default: return false; - } - } - async requestSession(mode, enabledFeatures) { - if (!this.isSessionSupported(mode)) { - return Promise.reject(); - } - const session = new Session$1(mode, enabledFeatures); - this.sessions.set(session.id, session); - return Promise.resolve(session.id); - } - requestAnimationFrame(callback) { - return window.requestAnimationFrame(callback); - } - cancelAnimationFrame(handle) { - window.cancelAnimationFrame(handle); - } - onFrameStart(sessionId, renderState) { - if (TEST_ENV$1) { - return; - } - const session = this.sessions.get(sessionId); - if (session.baseLayer) { - const canvas = session.baseLayer.context.canvas; - perspective(this.projectionMatrix, renderState.inlineVerticalFieldOfView, - canvas.width/canvas.height, renderState.depthNear, renderState.depthFar); - } - } - onFrameEnd(sessionId) { - } - async endSession(sessionId) { - const session = this.sessions.get(sessionId); - session.ended = true; - } - doesSessionSupportReferenceSpace(sessionId, type) { - const session = this.sessions.get(sessionId); - if (session.ended) { - return false; - } - return session.enabledFeatures.has(type); - } - requestStageBounds() { - return null; - } - async requestFrameOfReferenceTransform(type, options) { - return null; - } - getProjectionMatrix(eye) { - return this.projectionMatrix; - } - getViewport(sessionId, eye, layer, target) { - const session = this.sessions.get(sessionId); - const { width, height } = layer.context.canvas; - target.x = target.y = 0; - target.width = width; - target.height = height; - return true; - } - getBasePoseMatrix() { - return this.identityMatrix; - } - getBaseViewMatrix(eye) { - return this.identityMatrix; - } - getInputSources() { - return []; - } - getInputPose(inputSource, coordinateSystem, poseType) { - return null; - } - onWindowResize() { - } -} - -const getWebVRDevice = async function (global) { - let device = null; - if ('getVRDisplays' in global.navigator) { - try { - const displays = await global.navigator.getVRDisplays(); - if (displays && displays.length) { - device = new WebVRDevice(global, displays[0]); - } - } catch (e) {} - } - return device; -}; -const requestXRDevice = async function (global, config) { - if (config.webvr) { - let xr = await getWebVRDevice(global); - if (xr) { - return xr; - } - } - let mobile = isMobile(global); - if ((mobile && config.cardboard) || - (!mobile && config.allowCardboardOnDesktop)) { - if (!global.VRFrameData) { - global.VRFrameData = function () { - this.rightViewMatrix = new Float32Array(16); - this.leftViewMatrix = new Float32Array(16); - this.rightProjectionMatrix = new Float32Array(16); - this.leftProjectionMatrix = new Float32Array(16); - this.pose = null; - }; - } - return new CardboardXRDevice(global, config.cardboardConfig); - } - return new InlineDevice(global); -}; - -const CONFIG_DEFAULTS = { - global: _global, - webvr: true, - cardboard: true, - cardboardConfig: null, - allowCardboardOnDesktop: false, -}; -const partials = ['navigator', 'HTMLCanvasElement', 'WebGLRenderingContext']; -class WebXRPolyfill { - constructor(config={}) { - this.config = Object.freeze(Object.assign({}, CONFIG_DEFAULTS, config)); - this.global = this.config.global; - this.nativeWebXR = 'xr' in this.global.navigator; - this.injected = false; - if (!this.nativeWebXR) { - this._injectPolyfill(this.global); - } else { - this._injectCompatibilityShims(this.global); - } - } - _injectPolyfill(global) { - if (!partials.every(iface => !!global[iface])) { - throw new Error(`Global must have the following attributes : ${partials}`); - } - for (const className of Object.keys(API)) { - if (global[className] !== undefined) { - console.warn(`${className} already defined on global.`); - } else { - global[className] = API[className]; - } - } - { - const polyfilledCtx = polyfillMakeXRCompatible(global.WebGLRenderingContext); - if (polyfilledCtx) { - polyfillGetContext(global.HTMLCanvasElement); - if (global.OffscreenCanvas) { - polyfillGetContext(global.OffscreenCanvas); - } - if (global.WebGL2RenderingContext){ - polyfillMakeXRCompatible(global.WebGL2RenderingContext); - } - } - } - this.injected = true; - this._patchNavigatorXR(); - } - _patchNavigatorXR() { - let devicePromise = requestXRDevice(this.global, this.config); - this.xr = new API.XR(devicePromise); - Object.defineProperty(this.global.navigator, 'xr', { - value: this.xr, - configurable: true, - }); - } - _injectCompatibilityShims(global) { - if (!partials.every(iface => !!global[iface])) { - throw new Error(`Global must have the following attributes : ${partials}`); - } - if (global.navigator.xr && - 'supportsSession' in global.navigator.xr && - !('isSessionSupported' in global.navigator.xr)) { - let originalSupportsSession = global.navigator.xr.supportsSession; - global.navigator.xr.isSessionSupported = function(mode) { - return originalSupportsSession.call(this, mode).then(() => { - return true; - }).catch(() => { - return false; - }); - }; - global.navigator.xr.supportsSession = function(mode) { - console.warn("navigator.xr.supportsSession() is deprecated. Please " + - "call navigator.xr.isSessionSupported() instead and check the boolean " + - "value returned when the promise resolves."); - return originalSupportsSession.call(this, mode); - }; - } - } -} - -export default WebXRPolyfill; From 63c113200b8a1147ed2a13f44f77a4a499ad5495 Mon Sep 17 00:00:00 2001 From: Blair MacIntyre Date: Wed, 1 Jan 2020 20:00:25 -0500 Subject: [PATCH 3/7] added back builds --- build/webxr-polyfill.js | 6117 ++++++++++++++++++++++++++++++++ build/webxr-polyfill.min.js | 95 + build/webxr-polyfill.module.js | 6109 +++++++++++++++++++++++++++++++ 3 files changed, 12321 insertions(+) create mode 100644 build/webxr-polyfill.js create mode 100644 build/webxr-polyfill.min.js create mode 100644 build/webxr-polyfill.module.js diff --git a/build/webxr-polyfill.js b/build/webxr-polyfill.js new file mode 100644 index 0000000..af60dbb --- /dev/null +++ b/build/webxr-polyfill.js @@ -0,0 +1,6117 @@ +/** + * @license + * webxr-polyfill + * Copyright (c) 2017 Google + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @license + * cardboard-vr-display + * Copyright (c) 2015-2017 Google + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @license + * webvr-polyfill-dpdb + * Copyright (c) 2017 Google + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @license + * wglu-preserve-state + * Copyright (c) 2016, Brandon Jones. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * @license + * nosleep.js + * Copyright (c) 2017, Rich Tibbett + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.WebXRPolyfill = factory()); +}(this, (function () { 'use strict'; + +const _global = typeof global !== 'undefined' ? global : + typeof self !== 'undefined' ? self : + typeof window !== 'undefined' ? window : {}; + +const PRIVATE = Symbol('@@webxr-polyfill/EventTarget'); +class EventTarget { + constructor() { + this[PRIVATE] = { + listeners: new Map(), + }; + } + addEventListener(type, listener) { + if (typeof type !== 'string') { throw new Error('`type` must be a string'); } + if (typeof listener !== 'function') { throw new Error('`listener` must be a function'); } + const typedListeners = this[PRIVATE].listeners.get(type) || []; + typedListeners.push(listener); + this[PRIVATE].listeners.set(type, typedListeners); + } + removeEventListener(type, listener) { + if (typeof type !== 'string') { throw new Error('`type` must be a string'); } + if (typeof listener !== 'function') { throw new Error('`listener` must be a function'); } + const typedListeners = this[PRIVATE].listeners.get(type) || []; + for (let i = typedListeners.length; i >= 0; i--) { + if (typedListeners[i] === listener) { + typedListeners.pop(); + } + } + } + dispatchEvent(type, event) { + const typedListeners = this[PRIVATE].listeners.get(type) || []; + const queue = []; + for (let i = 0; i < typedListeners.length; i++) { + queue[i] = typedListeners[i]; + } + for (let listener of queue) { + listener(event); + } + if (typeof this[`on${type}`] === 'function') { + this[`on${type}`](event); + } + } +} + +const EPSILON = 0.000001; +let ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; + + +const degree = Math.PI / 180; + +function create() { + let out = new ARRAY_TYPE(16); + if(ARRAY_TYPE != Float32Array) { + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + } + out[0] = 1; + out[5] = 1; + out[10] = 1; + out[15] = 1; + return out; +} + +function copy(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +} + + +function identity(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +} + +function invert(out, a) { + let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; + let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; + let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; + let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + let b00 = a00 * a11 - a01 * a10; + let b01 = a00 * a12 - a02 * a10; + let b02 = a00 * a13 - a03 * a10; + let b03 = a01 * a12 - a02 * a11; + let b04 = a01 * a13 - a03 * a11; + let b05 = a02 * a13 - a03 * a12; + let b06 = a20 * a31 - a21 * a30; + let b07 = a20 * a32 - a22 * a30; + let b08 = a20 * a33 - a23 * a30; + let b09 = a21 * a32 - a22 * a31; + let b10 = a21 * a33 - a23 * a31; + let b11 = a22 * a33 - a23 * a32; + let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + if (!det) { + return null; + } + det = 1.0 / det; + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; + out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; + out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; + out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; + out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; + out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; + out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; + return out; +} + + +function multiply(out, a, b) { + let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; + let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; + let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; + let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; + out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; + out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; + out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + return out; +} + + + + + + + + + + + + +function fromRotationTranslation(out, q, v) { + let x = q[0], y = q[1], z = q[2], w = q[3]; + let x2 = x + x; + let y2 = y + y; + let z2 = z + z; + let xx = x * x2; + let xy = x * y2; + let xz = x * z2; + let yy = y * y2; + let yz = y * z2; + let zz = z * z2; + let wx = w * x2; + let wy = w * y2; + let wz = w * z2; + out[0] = 1 - (yy + zz); + out[1] = xy + wz; + out[2] = xz - wy; + out[3] = 0; + out[4] = xy - wz; + out[5] = 1 - (xx + zz); + out[6] = yz + wx; + out[7] = 0; + out[8] = xz + wy; + out[9] = yz - wx; + out[10] = 1 - (xx + yy); + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + return out; +} + +function getTranslation(out, mat) { + out[0] = mat[12]; + out[1] = mat[13]; + out[2] = mat[14]; + return out; +} + +function getRotation(out, mat) { + let trace = mat[0] + mat[5] + mat[10]; + let S = 0; + if (trace > 0) { + S = Math.sqrt(trace + 1.0) * 2; + out[3] = 0.25 * S; + out[0] = (mat[6] - mat[9]) / S; + out[1] = (mat[8] - mat[2]) / S; + out[2] = (mat[1] - mat[4]) / S; + } else if ((mat[0] > mat[5]) && (mat[0] > mat[10])) { + S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2; + out[3] = (mat[6] - mat[9]) / S; + out[0] = 0.25 * S; + out[1] = (mat[1] + mat[4]) / S; + out[2] = (mat[8] + mat[2]) / S; + } else if (mat[5] > mat[10]) { + S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2; + out[3] = (mat[8] - mat[2]) / S; + out[0] = (mat[1] + mat[4]) / S; + out[1] = 0.25 * S; + out[2] = (mat[6] + mat[9]) / S; + } else { + S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2; + out[3] = (mat[1] - mat[4]) / S; + out[0] = (mat[8] + mat[2]) / S; + out[1] = (mat[6] + mat[9]) / S; + out[2] = 0.25 * S; + } + return out; +} + + + + +function perspective(out, fovy, aspect, near, far) { + let f = 1.0 / Math.tan(fovy / 2), nf; + out[0] = f / aspect; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = f; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[15] = 0; + if (far != null && far !== Infinity) { + nf = 1 / (near - far); + out[10] = (far + near) * nf; + out[14] = (2 * far * near) * nf; + } else { + out[10] = -1; + out[14] = -2 * near; + } + return out; +} + +function create$1() { + let out = new ARRAY_TYPE(3); + if(ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + } + return out; +} +function clone$1(a) { + var out = new ARRAY_TYPE(3); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +} +function length(a) { + let x = a[0]; + let y = a[1]; + let z = a[2]; + return Math.sqrt(x*x + y*y + z*z); +} +function fromValues$1(x, y, z) { + let out = new ARRAY_TYPE(3); + out[0] = x; + out[1] = y; + out[2] = z; + return out; +} +function copy$1(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +} + +function add$1(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + return out; +} + + + + + + + + +function scale$1(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + return out; +} + + + + + + +function normalize(out, a) { + let x = a[0]; + let y = a[1]; + let z = a[2]; + let len = x*x + y*y + z*z; + if (len > 0) { + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + out[2] = a[2] * len; + } + return out; +} +function dot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} +function cross(out, a, b) { + let ax = a[0], ay = a[1], az = a[2]; + let bx = b[0], by = b[1], bz = b[2]; + out[0] = ay * bz - az * by; + out[1] = az * bx - ax * bz; + out[2] = ax * by - ay * bx; + return out; +} + + + + + + +function transformQuat(out, a, q) { + let qx = q[0], qy = q[1], qz = q[2], qw = q[3]; + let x = a[0], y = a[1], z = a[2]; + let uvx = qy * z - qz * y, + uvy = qz * x - qx * z, + uvz = qx * y - qy * x; + let uuvx = qy * uvz - qz * uvy, + uuvy = qz * uvx - qx * uvz, + uuvz = qx * uvy - qy * uvx; + let w2 = qw * 2; + uvx *= w2; + uvy *= w2; + uvz *= w2; + uuvx *= 2; + uuvy *= 2; + uuvz *= 2; + out[0] = x + uvx + uuvx; + out[1] = y + uvy + uuvy; + out[2] = z + uvz + uuvz; + return out; +} + + + +function angle(a, b) { + let tempA = fromValues$1(a[0], a[1], a[2]); + let tempB = fromValues$1(b[0], b[1], b[2]); + normalize(tempA, tempA); + normalize(tempB, tempB); + let cosine = dot(tempA, tempB); + if(cosine > 1.0) { + return 0; + } + else if(cosine < -1.0) { + return Math.PI; + } else { + return Math.acos(cosine); + } +} + + + + + + + + +const len = length; + +const forEach = (function() { + let vec = create$1(); + return function(a, stride, offset, count, fn, arg) { + let i, l; + if(!stride) { + stride = 3; + } + if(!offset) { + offset = 0; + } + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; + } + return a; + }; +})(); + +function create$2() { + let out = new ARRAY_TYPE(9); + if(ARRAY_TYPE != Float32Array) { + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[5] = 0; + out[6] = 0; + out[7] = 0; + } + out[0] = 1; + out[4] = 1; + out[8] = 1; + return out; +} + +function create$3() { + let out = new ARRAY_TYPE(4); + if(ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 0; + } + return out; +} +function clone$3(a) { + let out = new ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +} +function fromValues$3(x, y, z, w) { + let out = new ARRAY_TYPE(4); + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; +} +function copy$3(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +} + + + + + + + + + + + + + + + + + + +function normalize$1(out, a) { + let x = a[0]; + let y = a[1]; + let z = a[2]; + let w = a[3]; + let len = x*x + y*y + z*z + w*w; + if (len > 0) { + len = 1 / Math.sqrt(len); + out[0] = x * len; + out[1] = y * len; + out[2] = z * len; + out[3] = w * len; + } + return out; +} + + + + + + + + + + + + + + + +const forEach$1 = (function() { + let vec = create$3(); + return function(a, stride, offset, count, fn, arg) { + let i, l; + if(!stride) { + stride = 4; + } + if(!offset) { + offset = 0; + } + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3]; + } + return a; + }; +})(); + +function create$4() { + let out = new ARRAY_TYPE(4); + if(ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + } + out[3] = 1; + return out; +} + +function setAxisAngle(out, axis, rad) { + rad = rad * 0.5; + let s = Math.sin(rad); + out[0] = s * axis[0]; + out[1] = s * axis[1]; + out[2] = s * axis[2]; + out[3] = Math.cos(rad); + return out; +} + +function multiply$4(out, a, b) { + let ax = a[0], ay = a[1], az = a[2], aw = a[3]; + let bx = b[0], by = b[1], bz = b[2], bw = b[3]; + out[0] = ax * bw + aw * bx + ay * bz - az * by; + out[1] = ay * bw + aw * by + az * bx - ax * bz; + out[2] = az * bw + aw * bz + ax * by - ay * bx; + out[3] = aw * bw - ax * bx - ay * by - az * bz; + return out; +} + + + + +function slerp(out, a, b, t) { + let ax = a[0], ay = a[1], az = a[2], aw = a[3]; + let bx = b[0], by = b[1], bz = b[2], bw = b[3]; + let omega, cosom, sinom, scale0, scale1; + cosom = ax * bx + ay * by + az * bz + aw * bw; + if ( cosom < 0.0 ) { + cosom = -cosom; + bx = - bx; + by = - by; + bz = - bz; + bw = - bw; + } + if ( (1.0 - cosom) > EPSILON ) { + omega = Math.acos(cosom); + sinom = Math.sin(omega); + scale0 = Math.sin((1.0 - t) * omega) / sinom; + scale1 = Math.sin(t * omega) / sinom; + } else { + scale0 = 1.0 - t; + scale1 = t; + } + out[0] = scale0 * ax + scale1 * bx; + out[1] = scale0 * ay + scale1 * by; + out[2] = scale0 * az + scale1 * bz; + out[3] = scale0 * aw + scale1 * bw; + return out; +} + +function invert$2(out, a) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + let dot$$1 = a0*a0 + a1*a1 + a2*a2 + a3*a3; + let invDot = dot$$1 ? 1.0/dot$$1 : 0; + out[0] = -a0*invDot; + out[1] = -a1*invDot; + out[2] = -a2*invDot; + out[3] = a3*invDot; + return out; +} + +function fromMat3(out, m) { + let fTrace = m[0] + m[4] + m[8]; + let fRoot; + if ( fTrace > 0.0 ) { + fRoot = Math.sqrt(fTrace + 1.0); + out[3] = 0.5 * fRoot; + fRoot = 0.5/fRoot; + out[0] = (m[5]-m[7])*fRoot; + out[1] = (m[6]-m[2])*fRoot; + out[2] = (m[1]-m[3])*fRoot; + } else { + let i = 0; + if ( m[4] > m[0] ) + i = 1; + if ( m[8] > m[i*3+i] ) + i = 2; + let j = (i+1)%3; + let k = (i+2)%3; + fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); + out[i] = 0.5 * fRoot; + fRoot = 0.5 / fRoot; + out[3] = (m[j*3+k] - m[k*3+j]) * fRoot; + out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; + out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; + } + return out; +} +function fromEuler(out, x, y, z) { + let halfToRad = 0.5 * Math.PI / 180.0; + x *= halfToRad; + y *= halfToRad; + z *= halfToRad; + let sx = Math.sin(x); + let cx = Math.cos(x); + let sy = Math.sin(y); + let cy = Math.cos(y); + let sz = Math.sin(z); + let cz = Math.cos(z); + out[0] = sx * cy * cz - cx * sy * sz; + out[1] = cx * sy * cz + sx * cy * sz; + out[2] = cx * cy * sz - sx * sy * cz; + out[3] = cx * cy * cz + sx * sy * sz; + return out; +} + +const clone$4 = clone$3; +const fromValues$4 = fromValues$3; +const copy$4 = copy$3; + + + + + + + + + + +const normalize$2 = normalize$1; + + +const rotationTo = (function() { + let tmpvec3 = create$1(); + let xUnitVec3 = fromValues$1(1,0,0); + let yUnitVec3 = fromValues$1(0,1,0); + return function(out, a, b) { + let dot$$1 = dot(a, b); + if (dot$$1 < -0.999999) { + cross(tmpvec3, xUnitVec3, a); + if (len(tmpvec3) < 0.000001) + cross(tmpvec3, yUnitVec3, a); + normalize(tmpvec3, tmpvec3); + setAxisAngle(out, tmpvec3, Math.PI); + return out; + } else if (dot$$1 > 0.999999) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } else { + cross(tmpvec3, a, b); + out[0] = tmpvec3[0]; + out[1] = tmpvec3[1]; + out[2] = tmpvec3[2]; + out[3] = 1 + dot$$1; + return normalize$2(out, out); + } + }; +})(); +const sqlerp = (function () { + let temp1 = create$4(); + let temp2 = create$4(); + return function (out, a, b, c, d, t) { + slerp(temp1, a, d, t); + slerp(temp2, b, c, t); + slerp(out, temp1, temp2, 2 * t * (1 - t)); + return out; + }; +}()); +const setAxes = (function() { + let matr = create$2(); + return function(out, view, right, up) { + matr[0] = right[0]; + matr[3] = right[1]; + matr[6] = right[2]; + matr[1] = up[0]; + matr[4] = up[1]; + matr[7] = up[2]; + matr[2] = -view[0]; + matr[5] = -view[1]; + matr[8] = -view[2]; + return normalize$2(out, fromMat3(out, matr)); + }; +})(); + +const PRIVATE$1 = Symbol('@@webxr-polyfill/XRRigidTransform'); +class XRRigidTransform$1 { + constructor() { + this[PRIVATE$1] = { + matrix: null, + position: null, + orientation: null, + inverse: null, + }; + if (arguments.length === 0) { + this[PRIVATE$1].matrix = identity(new Float32Array(16)); + } else if (arguments.length === 1) { + if (arguments[0] instanceof Float32Array) { + this[PRIVATE$1].matrix = arguments[0]; + } else { + this[PRIVATE$1].position = this._getPoint(arguments[0]); + this[PRIVATE$1].orientation = DOMPointReadOnly.fromPoint({ + x: 0, y: 0, z: 0, w: 1 + }); + } + } else if (arguments.length === 2) { + this[PRIVATE$1].position = this._getPoint(arguments[0]); + this[PRIVATE$1].orientation = this._getPoint(arguments[1]); + } else { + throw new Error("Too many arguments!"); + } + if (this[PRIVATE$1].matrix) { + let position = create$1(); + getTranslation(position, this[PRIVATE$1].matrix); + this[PRIVATE$1].position = DOMPointReadOnly.fromPoint({ + x: position[0], + y: position[1], + z: position[2] + }); + let orientation = create$4(); + getRotation(orientation, this[PRIVATE$1].matrix); + this[PRIVATE$1].orientation = DOMPointReadOnly.fromPoint({ + x: orientation[0], + y: orientation[1], + z: orientation[2], + w: orientation[3] + }); + } else { + this[PRIVATE$1].matrix = identity(new Float32Array(16)); + fromRotationTranslation( + this[PRIVATE$1].matrix, + fromValues$4( + this[PRIVATE$1].orientation.x, + this[PRIVATE$1].orientation.y, + this[PRIVATE$1].orientation.z, + this[PRIVATE$1].orientation.w), + fromValues$1( + this[PRIVATE$1].position.x, + this[PRIVATE$1].position.y, + this[PRIVATE$1].position.z) + ); + } + } + _getPoint(arg) { + if (arg instanceof DOMPointReadOnly) { + return arg; + } + return DOMPointReadOnly.fromPoint(arg); + } + get matrix() { return this[PRIVATE$1].matrix; } + get position() { return this[PRIVATE$1].position; } + get orientation() { return this[PRIVATE$1].orientation; } + get inverse() { + if (this[PRIVATE$1].inverse === null) { + let invMatrix = identity(new Float32Array(16)); + invert(invMatrix, this[PRIVATE$1].matrix); + this[PRIVATE$1].inverse = new XRRigidTransform$1(invMatrix); + this[PRIVATE$1].inverse[PRIVATE$1].inverse = this; + } + return this[PRIVATE$1].inverse; + } +} + +const PRIVATE$2 = Symbol('@@webxr-polyfill/XRSpace'); + +class XRSpace { + constructor(specialType = null, inputSource = null) { + this[PRIVATE$2] = { + specialType, + inputSource, + baseMatrix: null, + inverseBaseMatrix: null, + lastFrameId: -1 + }; + } + get _specialType() { + return this[PRIVATE$2].specialType; + } + get _inputSource() { + return this[PRIVATE$2].inputSource; + } + _ensurePoseUpdated(device, frameId) { + if (frameId == this[PRIVATE$2].lastFrameId) return; + this[PRIVATE$2].lastFrameId = frameId; + this._onPoseUpdate(device); + } + _onPoseUpdate(device) { + if (this[PRIVATE$2].specialType == 'viewer') { + this._baseMatrix = device.getBasePoseMatrix(); + } + } + set _baseMatrix(matrix) { + this[PRIVATE$2].baseMatrix = matrix; + this[PRIVATE$2].inverseBaseMatrix = null; + } + get _baseMatrix() { + if (!this[PRIVATE$2].baseMatrix) { + if (this[PRIVATE$2].inverseBaseMatrix) { + this[PRIVATE$2].baseMatrix = new Float32Array(16); + invert(this[PRIVATE$2].baseMatrix, this[PRIVATE$2].inverseBaseMatrix); + } + } + return this[PRIVATE$2].baseMatrix; + } + set _inverseBaseMatrix(matrix) { + this[PRIVATE$2].inverseBaseMatrix = matrix; + this[PRIVATE$2].baseMatrix = null; + } + get _inverseBaseMatrix() { + if (!this[PRIVATE$2].inverseBaseMatrix) { + if (this[PRIVATE$2].baseMatrix) { + this[PRIVATE$2].inverseBaseMatrix = new Float32Array(16); + invert(this[PRIVATE$2].inverseBaseMatrix, this[PRIVATE$2].baseMatrix); + } + } + return this[PRIVATE$2].inverseBaseMatrix; + } + _getSpaceRelativeTransform(space) { + if (!this._inverseBaseMatrix || !space._baseMatrix) { + return null; + } + let out = new Float32Array(16); + multiply(out, this._inverseBaseMatrix, space._baseMatrix); + return new XRRigidTransform$1(out); + } +} + +const DEFAULT_EMULATION_HEIGHT = 1.6; +const PRIVATE$3 = Symbol('@@webxr-polyfill/XRReferenceSpace'); +const XRReferenceSpaceTypes = [ + 'viewer', + 'local', + 'local-floor', + 'bounded-floor', + 'unbounded' +]; +function isFloor(type) { + return type === 'bounded-floor' || type === 'local-floor'; +} +class XRReferenceSpace extends XRSpace { + constructor(type, transform = null) { + if (!XRReferenceSpaceTypes.includes(type)) { + throw new Error(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`); + } + super(type); + if (type === 'bounded-floor' && !transform) { + throw new Error(`XRReferenceSpace cannot use 'bounded-floor' type if the platform does not provide the floor level`); + } + if (isFloor(type) && !transform) { + transform = identity(new Float32Array(16)); + transform[13] = DEFAULT_EMULATION_HEIGHT; + } + this._inverseBaseMatrix = transform || identity(new Float32Array(16)); + this[PRIVATE$3] = { + type, + transform, + originOffset : identity(new Float32Array(16)), + }; + } + _transformBasePoseMatrix(out, pose) { + multiply(out, this._inverseBaseMatrix, pose); + } + _originOffsetMatrix() { + return this[PRIVATE$3].originOffset; + } + _adjustForOriginOffset(transformMatrix) { + let inverseOriginOffsetMatrix = new Float32Array(16); + invert(inverseOriginOffsetMatrix, this[PRIVATE$3].originOffset); + multiply(transformMatrix, inverseOriginOffsetMatrix, transformMatrix); + } + _getSpaceRelativeTransform(space) { + let transform = super._getSpaceRelativeTransform(space); + this._adjustForOriginOffset(transform.matrix); + return new XRRigidTransform(transform.matrix); + } + getOffsetReferenceSpace(additionalOffset) { + let newSpace = new XRReferenceSpace( + this[PRIVATE$3].type, + this[PRIVATE$3].transform, + this[PRIVATE$3].bounds); + multiply(newSpace[PRIVATE$3].originOffset, this[PRIVATE$3].originOffset, additionalOffset.matrix); + return newSpace; + } +} + +const PRIVATE$4 = Symbol('@@webxr-polyfill/XR'); +const XRSessionModes = ['inline', 'immersive-vr', 'immersive-ar']; +const DEFAULT_SESSION_OPTIONS = { + 'inline': { + requiredFeatures: ['viewer'], + optionalFeatures: [], + }, + 'immersive-vr': { + requiredFeatures: ['viewer', 'local'], + optionalFeatures: [], + }, + 'immersive-ar': { + requiredFeatures: ['viewer', 'local'], + optionalFeatures: [], + } +}; +const POLYFILL_REQUEST_SESSION_ERROR = +`Polyfill Error: Must call navigator.xr.isSessionSupported() with any XRSessionMode +or navigator.xr.requestSession('inline') prior to requesting an immersive +session. This is a limitation specific to the WebXR Polyfill and does not apply +to native implementations of the API.`; +class XR extends EventTarget { + constructor(devicePromise) { + super(); + this[PRIVATE$4] = { + device: null, + devicePromise, + immersiveSession: null, + inlineSessions: new Set(), + }; + devicePromise.then((device) => { this[PRIVATE$4].device = device; }); + } + async isSessionSupported(mode) { + if (!this[PRIVATE$4].device) { + await this[PRIVATE$4].devicePromise; + } + if (mode != 'inline') { + return Promise.resolve(this[PRIVATE$4].device.isSessionSupported(mode)); + } + return Promise.resolve(true); + } + async requestSession(mode, options) { + if (!this[PRIVATE$4].device) { + if (mode != 'inline') { + throw new Error(POLYFILL_REQUEST_SESSION_ERROR); + } else { + await this[PRIVATE$4].devicePromise; + } + } + if (!XRSessionModes.includes(mode)) { + throw new TypeError( + `The provided value '${mode}' is not a valid enum value of type XRSessionMode`); + } + const defaultOptions = DEFAULT_SESSION_OPTIONS[mode]; + const requiredFeatures = defaultOptions.requiredFeatures.concat( + options && options.requiredFeatures ? options.requiredFeatures : []); + const optionalFeatures = defaultOptions.optionalFeatures.concat( + options && options.optionalFeatures ? options.optionalFeatures : []); + const enabledFeatures = new Set(); + let requirementsFailed = false; + for (let feature of requiredFeatures) { + if (!this[PRIVATE$4].device.isFeatureSupported(feature)) { + console.error(`The required feature '${feature}' is not supported`); + requirementsFailed = true; + } else { + enabledFeatures.add(feature); + } + } + if (requirementsFailed) { + throw new DOMException('Session does not support some required features', 'NotSupportedError'); + } + for (let feature of optionalFeatures) { + if (!this[PRIVATE$4].device.isFeatureSupported(feature)) { + console.log(`The optional feature '${feature}' is not supported`); + } else { + enabledFeatures.add(feature); + } + } + const sessionId = await this[PRIVATE$4].device.requestSession(mode, enabledFeatures); + const session = new XRSession(this[PRIVATE$4].device, mode, sessionId); + if (mode == 'inline') { + this[PRIVATE$4].inlineSessions.add(session); + } else { + this[PRIVATE$4].immersiveSession = session; + } + const onSessionEnd = () => { + if (mode == 'inline') { + this[PRIVATE$4].inlineSessions.delete(session); + } else { + this[PRIVATE$4].immersiveSession = null; + } + session.removeEventListener('end', onSessionEnd); + }; + session.addEventListener('end', onSessionEnd); + return session; + } +} + +let now; +if ('performance' in _global === false) { + let startTime = Date.now(); + now = () => Date.now() - startTime; +} else { + now = () => performance.now(); +} +var now$1 = now; + +const PRIVATE$5 = Symbol('@@webxr-polyfill/XRPose'); +class XRPose$1 { + constructor(transform, emulatedPosition) { + this[PRIVATE$5] = { + transform, + emulatedPosition, + }; + } + get transform() { return this[PRIVATE$5].transform; } + get emulatedPosition() { return this[PRIVATE$5].emulatedPosition; } +} + +const PRIVATE$6 = Symbol('@@webxr-polyfill/XRViewerPose'); +class XRViewerPose extends XRPose$1 { + constructor(transform, views, emulatedPosition = false) { + super(transform, emulatedPosition); + this[PRIVATE$6] = { + views + }; + } + get views() { + return this[PRIVATE$6].views; + } +} + +const PRIVATE$7 = Symbol('@@webxr-polyfill/XRViewport'); +class XRViewport { + constructor(target) { + this[PRIVATE$7] = { target }; + } + get x() { return this[PRIVATE$7].target.x; } + get y() { return this[PRIVATE$7].target.y; } + get width() { return this[PRIVATE$7].target.width; } + get height() { return this[PRIVATE$7].target.height; } +} + +const XREyes = ['left', 'right', 'none']; +const PRIVATE$8 = Symbol('@@webxr-polyfill/XRView'); +class XRView { + constructor(device, transform, eye, sessionId) { + if (!XREyes.includes(eye)) { + throw new Error(`XREye must be one of: ${XREyes}`); + } + const temp = Object.create(null); + const viewport = new XRViewport(temp); + this[PRIVATE$8] = { + device, + eye, + viewport, + temp, + sessionId, + transform, + }; + } + get eye() { return this[PRIVATE$8].eye; } + get projectionMatrix() { return this[PRIVATE$8].device.getProjectionMatrix(this.eye); } + get transform() { return this[PRIVATE$8].transform; } + _getViewport(layer) { + if (this[PRIVATE$8].device.getViewport(this[PRIVATE$8].sessionId, + this.eye, + layer, + this[PRIVATE$8].temp)) { + return this[PRIVATE$8].viewport; + } + return undefined; + } +} + +const PRIVATE$9 = Symbol('@@webxr-polyfill/XRFrame'); +const NON_ACTIVE_MSG = "XRFrame access outside the callback that produced it is invalid."; +const NON_ANIMFRAME_MSG = "getViewerPose can only be called on XRFrame objects passed to XRSession.requestAnimationFrame callbacks."; +let NEXT_FRAME_ID = 0; +class XRFrame { + constructor(device, session, sessionId) { + this[PRIVATE$9] = { + id: ++NEXT_FRAME_ID, + active: false, + animationFrame: false, + device, + session, + sessionId + }; + } + get session() { return this[PRIVATE$9].session; } + getViewerPose(referenceSpace) { + if (!this[PRIVATE$9].animationFrame) { + throw new DOMException(NON_ANIMFRAME_MSG, 'InvalidStateError'); + } + if (!this[PRIVATE$9].active) { + throw new DOMException(NON_ACTIVE_MSG, 'InvalidStateError'); + } + const device = this[PRIVATE$9].device; + const session = this[PRIVATE$9].session; + session[PRIVATE$15].viewerSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); + referenceSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); + let viewerTransform = referenceSpace._getSpaceRelativeTransform(session[PRIVATE$15].viewerSpace); + const views = []; + for (let viewSpace of session[PRIVATE$15].viewSpaces) { + viewSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); + let viewTransform = referenceSpace._getSpaceRelativeTransform(viewSpace); + let view = new XRView(device, viewTransform, viewSpace.eye, this[PRIVATE$9].sessionId); + views.push(view); + } + let viewerPose = new XRViewerPose(viewerTransform, views, false ); + return viewerPose; + } + getPose(space, baseSpace) { + if (!this[PRIVATE$9].active) { + throw new DOMException(NON_ACTIVE_MSG, 'InvalidStateError'); + } + const device = this[PRIVATE$9].device; + if (space._specialType === "target-ray" || space._specialType === "grip") { + return device.getInputPose( + space._inputSource, baseSpace, space._specialType); + } else { + space._ensurePoseUpdated(device, this[PRIVATE$9].id); + baseSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); + let transform = baseSpace._getSpaceRelativeTransform(space); + if (!transform) { return null; } + return new XRPose(transform, false ); + } + return null; + } +} + +const PRIVATE$10 = Symbol('@@webxr-polyfill/XRRenderState'); +const XRRenderStateInit = Object.freeze({ + depthNear: 0.1, + depthFar: 1000.0, + inlineVerticalFieldOfView: null, + baseLayer: null +}); +class XRRenderState { + constructor(stateInit = {}) { + const config = Object.assign({}, XRRenderStateInit, stateInit); + this[PRIVATE$10] = { config }; + } + get depthNear() { return this[PRIVATE$10].config.depthNear; } + get depthFar() { return this[PRIVATE$10].config.depthFar; } + get inlineVerticalFieldOfView() { return this[PRIVATE$10].config.inlineVerticalFieldOfView; } + get baseLayer() { return this[PRIVATE$10].config.baseLayer; } +} + +const POLYFILLED_XR_COMPATIBLE = Symbol('@@webxr-polyfill/polyfilled-xr-compatible'); +const XR_COMPATIBLE = Symbol('@@webxr-polyfill/xr-compatible'); + +const PRIVATE$11 = Symbol('@@webxr-polyfill/XRWebGLLayer'); +const XRWebGLLayerInit = Object.freeze({ + antialias: true, + depth: false, + stencil: false, + alpha: true, + multiview: false, + ignoreDepthValues: false, + framebufferScaleFactor: 1.0, +}); +class XRWebGLLayer { + constructor(session, context, layerInit={}) { + const config = Object.assign({}, XRWebGLLayerInit, layerInit); + if (!(session instanceof XRSession$1)) { + throw new Error('session must be a XRSession'); + } + if (session.ended) { + throw new Error(`InvalidStateError`); + } + if (context[POLYFILLED_XR_COMPATIBLE]) { + if (context[XR_COMPATIBLE] !== true) { + throw new Error(`InvalidStateError`); + } + } + const framebuffer = context.getParameter(context.FRAMEBUFFER_BINDING); + this[PRIVATE$11] = { + context, + config, + framebuffer, + session, + }; + } + get context() { return this[PRIVATE$11].context; } + get antialias() { return this[PRIVATE$11].config.antialias; } + get ignoreDepthValues() { return true; } + get framebuffer() { return this[PRIVATE$11].framebuffer; } + get framebufferWidth() { return this[PRIVATE$11].context.drawingBufferWidth; } + get framebufferHeight() { return this[PRIVATE$11].context.drawingBufferHeight; } + get _session() { return this[PRIVATE$11].session; } + getViewport(view) { + return view._getViewport(this); + } + static getNativeFramebufferScaleFactor(session) { + if (!session) { + throw new TypeError('getNativeFramebufferScaleFactor must be passed a session.') + } + if (session[PRIVATE$15].ended) { return 0.0; } + return 1.0; + } +} + +const PRIVATE$12 = Symbol('@@webxr-polyfill/XRInputSourceEvent'); +class XRInputSourceEvent extends Event { + constructor(type, eventInitDict) { + super(type, eventInitDict); + this[PRIVATE$12] = { + frame: eventInitDict.frame, + inputSource: eventInitDict.inputSource + }; + } + get frame() { return this[PRIVATE$12].frame; } + get inputSource() { return this[PRIVATE$12].inputSource; } +} + +const PRIVATE$13 = Symbol('@@webxr-polyfill/XRSessionEvent'); +class XRSessionEvent extends Event { + constructor(type, eventInitDict) { + super(type, eventInitDict); + this[PRIVATE$13] = { + session: eventInitDict.session + }; + } + get session() { return this[PRIVATE$13].session; } +} + +const PRIVATE$14 = Symbol('@@webxr-polyfill/XRInputSourcesChangeEvent'); +class XRInputSourcesChangeEvent extends Event { + constructor(type, eventInitDict) { + super(type, eventInitDict); + this[PRIVATE$14] = { + session: eventInitDict.session, + added: eventInitDict.added, + removed: eventInitDict.removed + }; + } + get session() { return this[PRIVATE$14].session; } + get added() { return this[PRIVATE$14].added; } + get removed() { return this[PRIVATE$14].removed; } +} + +const PRIVATE$15 = Symbol('@@webxr-polyfill/XRSession'); +class XRViewSpace extends XRSpace { + constructor(eye) { + super(eye); + } + get eye() { + return this._specialType; + } + _onPoseUpdate(device) { + this._inverseBaseMatrix = device.getBaseViewMatrix(this._specialType); + } +} +class XRSession$1 extends EventTarget { + constructor(device, mode, id) { + super(); + let immersive = mode != 'inline'; + let initialRenderState = new XRRenderState({ + inlineVerticalFieldOfView: immersive ? null : Math.PI * 0.5 + }); + this[PRIVATE$15] = { + device, + mode, + immersive, + ended: false, + suspended: false, + frameCallbacks: [], + currentFrameCallbacks: null, + frameHandle: 0, + deviceFrameHandle: null, + id, + activeRenderState: initialRenderState, + pendingRenderState: null, + viewerSpace: new XRReferenceSpace("viewer"), + viewSpaces: [], + currentInputSources: [] + }; + if (immersive) { + this[PRIVATE$15].viewSpaces.push(new XRViewSpace('left'), + new XRViewSpace('right')); + } else { + this[PRIVATE$15].viewSpaces.push(new XRViewSpace('none')); + } + this[PRIVATE$15].onDeviceFrame = () => { + if (this[PRIVATE$15].ended || this[PRIVATE$15].suspended) { + return; + } + this[PRIVATE$15].deviceFrameHandle = null; + this[PRIVATE$15].startDeviceFrameLoop(); + if (this[PRIVATE$15].pendingRenderState !== null) { + this[PRIVATE$15].activeRenderState = new XRRenderState(this[PRIVATE$15].pendingRenderState); + this[PRIVATE$15].pendingRenderState = null; + if (this[PRIVATE$15].activeRenderState.baseLayer) { + this[PRIVATE$15].device.onBaseLayerSet( + this[PRIVATE$15].id, + this[PRIVATE$15].activeRenderState.baseLayer); + } + } + if (this[PRIVATE$15].activeRenderState.baseLayer === null) { + return; + } + const frame = new XRFrame(device, this, this[PRIVATE$15].id); + const callbacks = this[PRIVATE$15].currentFrameCallbacks = this[PRIVATE$15].frameCallbacks; + this[PRIVATE$15].frameCallbacks = []; + frame[PRIVATE$9].active = true; + frame[PRIVATE$9].animationFrame = true; + this[PRIVATE$15].device.onFrameStart(this[PRIVATE$15].id, this[PRIVATE$15].activeRenderState); + this._checkInputSourcesChange(); + const rightNow = now$1(); + for (let i = 0; i < callbacks.length; i++) { + try { + if (!callbacks[i].cancelled && typeof callbacks[i].callback === 'function') { + callbacks[i].callback(rightNow, frame); + } + } catch(err) { + console.error(err); + } + } + this[PRIVATE$15].currentFrameCallbacks = null; + frame[PRIVATE$9].active = false; + this[PRIVATE$15].device.onFrameEnd(this[PRIVATE$15].id); + }; + this[PRIVATE$15].startDeviceFrameLoop = () => { + if (this[PRIVATE$15].deviceFrameHandle === null) { + this[PRIVATE$15].deviceFrameHandle = this[PRIVATE$15].device.requestAnimationFrame( + this[PRIVATE$15].onDeviceFrame + ); + } + }; + this[PRIVATE$15].stopDeviceFrameLoop = () => { + const handle = this[PRIVATE$15].deviceFrameHandle; + if (handle !== null) { + this[PRIVATE$15].device.cancelAnimationFrame(handle); + this[PRIVATE$15].deviceFrameHandle = null; + } + }; + this[PRIVATE$15].onPresentationEnd = sessionId => { + if (sessionId !== this[PRIVATE$15].id) { + this[PRIVATE$15].suspended = false; + this[PRIVATE$15].startDeviceFrameLoop(); + this.dispatchEvent('focus', { session: this }); + return; + } + this[PRIVATE$15].ended = true; + this[PRIVATE$15].stopDeviceFrameLoop(); + device.removeEventListener('@webvr-polyfill/vr-present-end', this[PRIVATE$15].onPresentationEnd); + device.removeEventListener('@webvr-polyfill/vr-present-start', this[PRIVATE$15].onPresentationStart); + device.removeEventListener('@@webvr-polyfill/input-select-start', this[PRIVATE$15].onSelectStart); + device.removeEventListener('@@webvr-polyfill/input-select-end', this[PRIVATE$15].onSelectEnd); + this.dispatchEvent('end', new XRSessionEvent('end', { session: this })); + }; + device.addEventListener('@@webxr-polyfill/vr-present-end', this[PRIVATE$15].onPresentationEnd); + this[PRIVATE$15].onPresentationStart = sessionId => { + if (sessionId === this[PRIVATE$15].id) { + return; + } + this[PRIVATE$15].suspended = true; + this[PRIVATE$15].stopDeviceFrameLoop(); + this.dispatchEvent('blur', { session: this }); + }; + device.addEventListener('@@webxr-polyfill/vr-present-start', this[PRIVATE$15].onPresentationStart); + this[PRIVATE$15].onSelectStart = evt => { + if (evt.sessionId !== this[PRIVATE$15].id) { + return; + } + this[PRIVATE$15].dispatchInputSourceEvent('selectstart', evt.inputSource); + }; + device.addEventListener('@@webxr-polyfill/input-select-start', this[PRIVATE$15].onSelectStart); + this[PRIVATE$15].onSelectEnd = evt => { + if (evt.sessionId !== this[PRIVATE$15].id) { + return; + } + this[PRIVATE$15].dispatchInputSourceEvent('selectend', evt.inputSource); + this[PRIVATE$15].dispatchInputSourceEvent('select', evt.inputSource); + }; + device.addEventListener('@@webxr-polyfill/input-select-end', this[PRIVATE$15].onSelectEnd); + this[PRIVATE$15].onSqueezeStart = evt => { + if (evt.sessionId !== this[PRIVATE$15].id) { + return; + } + this[PRIVATE$15].dispatchInputSourceEvent('squeezestart', evt.inputSource); + }; + device.addEventListener('@@webxr-polyfill/input-squeeze-start', this[PRIVATE$15].onSqueezeStart); + this[PRIVATE$15].onSqueezeEnd = evt => { + if (evt.sessionId !== this[PRIVATE$15].id) { + return; + } + this[PRIVATE$15].dispatchInputSourceEvent('squeezeend', evt.inputSource); + this[PRIVATE$15].dispatchInputSourceEvent('squeeze', evt.inputSource); + }; + device.addEventListener('@@webxr-polyfill/input-squeeze-end', this[PRIVATE$15].onSqueezeEnd); + this[PRIVATE$15].dispatchInputSourceEvent = (type, inputSource) => { + const frame = new XRFrame(device, this, this[PRIVATE$15].id); + const event = new XRInputSourceEvent(type, { frame, inputSource }); + frame[PRIVATE$9].active = true; + this.dispatchEvent(type, event); + frame[PRIVATE$9].active = false; + }; + this[PRIVATE$15].startDeviceFrameLoop(); + this.onblur = undefined; + this.onfocus = undefined; + this.onresetpose = undefined; + this.onend = undefined; + this.onselect = undefined; + this.onselectstart = undefined; + this.onselectend = undefined; + } + get renderState() { return this[PRIVATE$15].activeRenderState; } + get environmentBlendMode() { + return this[PRIVATE$15].device.environmentBlendMode || 'opaque'; + } + async requestReferenceSpace(type) { + if (this[PRIVATE$15].ended) { + return; + } + if (!XRReferenceSpaceTypes.includes(type)) { + throw new TypeError(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`); + } + if (!this[PRIVATE$15].device.doesSessionSupportReferenceSpace(this[PRIVATE$15].id, type)) { + throw new DOMException(`The ${type} reference space is not supported by this session.`, 'NotSupportedError'); + } + if (type === 'viewer') { + return this[PRIVATE$15].viewerSpace; + } + let transform = await this[PRIVATE$15].device.requestFrameOfReferenceTransform(type); + if (type === 'bounded-floor') { + if (!transform) { + throw new DOMException(`${type} XRReferenceSpace not supported by this device.`, 'NotSupportedError'); + } + let bounds = this[PRIVATE$15].device.requestStageBounds(); + if (!bounds) { + throw new DOMException(`${type} XRReferenceSpace not supported by this device.`, 'NotSupportedError'); + } + throw new DOMException(`The WebXR polyfill does not support the ${type} reference space yet.`, 'NotSupportedError'); + } + return new XRReferenceSpace(type, transform); + } + requestAnimationFrame(callback) { + if (this[PRIVATE$15].ended) { + return; + } + const handle = ++this[PRIVATE$15].frameHandle; + this[PRIVATE$15].frameCallbacks.push({ + handle, + callback, + cancelled: false + }); + return handle; + } + cancelAnimationFrame(handle) { + let callbacks = this[PRIVATE$15].frameCallbacks; + let index = callbacks.findIndex(d => d && d.handle === handle); + if (index > -1) { + callbacks[index].cancelled = true; + callbacks.splice(index, 1); + } + callbacks = this[PRIVATE$15].currentFrameCallbacks; + if (callbacks) { + index = callbacks.findIndex(d => d && d.handle === handle); + if (index > -1) { + callbacks[index].cancelled = true; + } + } + } + get inputSources() { + return this[PRIVATE$15].device.getInputSources(); + } + async end() { + if (this[PRIVATE$15].ended) { + return; + } + if (this.immersive) { + this[PRIVATE$15].ended = true; + this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/vr-present-start', + this[PRIVATE$15].onPresentationStart); + this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/vr-present-end', + this[PRIVATE$15].onPresentationEnd); + this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/input-select-start', + this[PRIVATE$15].onSelectStart); + this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/input-select-end', + this[PRIVATE$15].onSelectEnd); + this.dispatchEvent('end', new XRSessionEvent('end', { session: this })); + } + this[PRIVATE$15].stopDeviceFrameLoop(); + return this[PRIVATE$15].device.endSession(this[PRIVATE$15].id); + } + updateRenderState(newState) { + if (this[PRIVATE$15].ended) { + const message = "Can't call updateRenderState on an XRSession " + + "that has already ended."; + throw new Error(message); + } + if (newState.baseLayer && (newState.baseLayer._session !== this)) { + const message = "Called updateRenderState with a base layer that was " + + "created by a different session."; + throw new Error(message); + } + const fovSet = (newState.inlineVerticalFieldOfView !== null) && + (newState.inlineVerticalFieldOfView !== undefined); + if (fovSet) { + if (this[PRIVATE$15].immersive) { + const message = "inlineVerticalFieldOfView must not be set for an " + + "XRRenderState passed to updateRenderState for an " + + "immersive session."; + throw new Error(message); + } else { + newState.inlineVerticalFieldOfView = Math.min( + 3.13, Math.max(0.01, newState.inlineVerticalFieldOfView)); + } + } + if (this[PRIVATE$15].pendingRenderState === null) { + const activeRenderState = this[PRIVATE$15].activeRenderState; + this[PRIVATE$15].pendingRenderState = { + depthNear: activeRenderState.depthNear, + depthFar: activeRenderState.depthFar, + inlineVerticalFieldOfView: activeRenderState.inlineVerticalFieldOfView, + baseLayer: activeRenderState.baseLayer + }; + } + Object.assign(this[PRIVATE$15].pendingRenderState, newState); + } + _checkInputSourcesChange() { + const added = []; + const removed = []; + const newInputSources = this.inputSources; + const oldInputSources = this[PRIVATE$15].currentInputSources; + for (const newInputSource of newInputSources) { + if (!oldInputSources.includes(newInputSource)) { + added.push(newInputSource); + } + } + for (const oldInputSource of oldInputSources) { + if (!newInputSources.includes(oldInputSource)) { + removed.push(oldInputSource); + } + } + if (added.length > 0 || removed.length > 0) { + this.dispatchEvent('inputsourceschange', new XRInputSourcesChangeEvent('inputsourceschange', { + session: this, + added: added, + removed: removed + })); + } + this[PRIVATE$15].currentInputSources.length = 0; + for (const newInputSource of newInputSources) { + this[PRIVATE$15].currentInputSources.push(newInputSource); + } + } +} + +const PRIVATE$16 = Symbol('@@webxr-polyfill/XRInputSource'); +class XRInputSource { + constructor(impl) { + this[PRIVATE$16] = { + impl, + gripSpace: new XRSpace("grip", this), + targetRaySpace: new XRSpace("target-ray", this) + }; + } + get handedness() { return this[PRIVATE$16].impl.handedness; } + get targetRayMode() { return this[PRIVATE$16].impl.targetRayMode; } + get gripSpace() { + let mode = this[PRIVATE$16].impl.targetRayMode; + if (mode === "gaze" || mode === "screen") { + return null; + } + return this[PRIVATE$16].gripSpace; + } + get targetRaySpace() { return this[PRIVATE$16].targetRaySpace; } + get profiles() { return this[PRIVATE$16].impl.profiles; } + get gamepad() { return this[PRIVATE$16].impl.gamepad; } +} + +const PRIVATE$17 = Symbol('@@webxr-polyfill/XRReferenceSpaceEvent'); +class XRReferenceSpaceEvent extends Event { + constructor(type, eventInitDict) { + super(type, eventInitDict); + this[PRIVATE$17] = { + referenceSpace: eventInitDict.referenceSpace, + transform: eventInitDict.transform || null + }; + } + get referenceSpace() { return this[PRIVATE$17].referenceSpace; } + get transform() { return this[PRIVATE$17].transform; } +} + +var API = { + XR, + XRSession: XRSession$1, + XRSessionEvent, + XRFrame, + XRView, + XRViewport, + XRViewerPose, + XRWebGLLayer, + XRSpace, + XRReferenceSpace, + XRReferenceSpaceEvent, + XRInputSource, + XRInputSourceEvent, + XRInputSourcesChangeEvent, + XRRenderState, + XRRigidTransform: XRRigidTransform$1, + XRPose: XRPose$1, +}; + +const polyfillMakeXRCompatible = Context => { + if (typeof Context.prototype.makeXRCompatible === 'function') { + return false; + } + Context.prototype.makeXRCompatible = function () { + this[XR_COMPATIBLE] = true; + return Promise.resolve(); + }; + return true; +}; +const polyfillGetContext = (Canvas) => { + const getContext = Canvas.prototype.getContext; + Canvas.prototype.getContext = function (contextType, glAttribs) { + const ctx = getContext.call(this, contextType, glAttribs); + if (ctx) { + ctx[POLYFILLED_XR_COMPATIBLE] = true; + if (glAttribs && ('xrCompatible' in glAttribs)) { + ctx[XR_COMPATIBLE] = glAttribs.xrCompatible; + } + } + return ctx; + }; +}; + +const isImageBitmapSupported = global => + !!(global.ImageBitmapRenderingContext && + global.createImageBitmap); +const isMobile = global => { + var check = false; + (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true;})(global.navigator.userAgent||global.navigator.vendor||global.opera); + return check; +}; +const applyCanvasStylesForMinimalRendering = canvas => { + canvas.style.display = 'block'; + canvas.style.position = 'absolute'; + canvas.style.width = canvas.style.height = '1px'; + canvas.style.top = canvas.style.left = '0px'; +}; + +var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + + +function unwrapExports (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; +} + +function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; +} + +var cardboardVrDisplay = createCommonjsModule(function (module, exports) { +(function (global, factory) { + module.exports = factory(); +}(commonjsGlobal, (function () { var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +}; +var createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; +}(); +var slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + return _arr; + } + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; +}(); +var MIN_TIMESTEP = 0.001; +var MAX_TIMESTEP = 1; +var dataUri = function dataUri(mimeType, svg) { + return 'data:' + mimeType + ',' + encodeURIComponent(svg); +}; +var lerp = function lerp(a, b, t) { + return a + (b - a) * t; +}; +var isIOS = function () { + var isIOS = /iPad|iPhone|iPod/.test(navigator.platform); + return function () { + return isIOS; + }; +}(); +var isWebViewAndroid = function () { + var isWebViewAndroid = navigator.userAgent.indexOf('Version') !== -1 && navigator.userAgent.indexOf('Android') !== -1 && navigator.userAgent.indexOf('Chrome') !== -1; + return function () { + return isWebViewAndroid; + }; +}(); +var isSafari = function () { + var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); + return function () { + return isSafari; + }; +}(); +var isFirefoxAndroid = function () { + var isFirefoxAndroid = navigator.userAgent.indexOf('Firefox') !== -1 && navigator.userAgent.indexOf('Android') !== -1; + return function () { + return isFirefoxAndroid; + }; +}(); +var getChromeVersion = function () { + var match = navigator.userAgent.match(/.*Chrome\/([0-9]+)/); + var value = match ? parseInt(match[1], 10) : null; + return function () { + return value; + }; +}(); +var isChromeWithoutDeviceMotion = function () { + var value = false; + if (getChromeVersion() === 65) { + var match = navigator.userAgent.match(/.*Chrome\/([0-9\.]*)/); + if (match) { + var _match$1$split = match[1].split('.'), + _match$1$split2 = slicedToArray(_match$1$split, 4), + major = _match$1$split2[0], + minor = _match$1$split2[1], + branch = _match$1$split2[2], + build = _match$1$split2[3]; + value = parseInt(branch, 10) === 3325 && parseInt(build, 10) < 148; + } + } + return function () { + return value; + }; +}(); +var isR7 = function () { + var isR7 = navigator.userAgent.indexOf('R7 Build') !== -1; + return function () { + return isR7; + }; +}(); +var isLandscapeMode = function isLandscapeMode() { + var rtn = window.orientation == 90 || window.orientation == -90; + return isR7() ? !rtn : rtn; +}; +var isTimestampDeltaValid = function isTimestampDeltaValid(timestampDeltaS) { + if (isNaN(timestampDeltaS)) { + return false; + } + if (timestampDeltaS <= MIN_TIMESTEP) { + return false; + } + if (timestampDeltaS > MAX_TIMESTEP) { + return false; + } + return true; +}; +var getScreenWidth = function getScreenWidth() { + return Math.max(window.screen.width, window.screen.height) * window.devicePixelRatio; +}; +var getScreenHeight = function getScreenHeight() { + return Math.min(window.screen.width, window.screen.height) * window.devicePixelRatio; +}; +var requestFullscreen = function requestFullscreen(element) { + if (isWebViewAndroid()) { + return false; + } + if (element.requestFullscreen) { + element.requestFullscreen(); + } else if (element.webkitRequestFullscreen) { + element.webkitRequestFullscreen(); + } else if (element.mozRequestFullScreen) { + element.mozRequestFullScreen(); + } else if (element.msRequestFullscreen) { + element.msRequestFullscreen(); + } else { + return false; + } + return true; +}; +var exitFullscreen = function exitFullscreen() { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); + } else { + return false; + } + return true; +}; +var getFullscreenElement = function getFullscreenElement() { + return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement; +}; +var linkProgram = function linkProgram(gl, vertexSource, fragmentSource, attribLocationMap) { + var vertexShader = gl.createShader(gl.VERTEX_SHADER); + gl.shaderSource(vertexShader, vertexSource); + gl.compileShader(vertexShader); + var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); + gl.shaderSource(fragmentShader, fragmentSource); + gl.compileShader(fragmentShader); + var program = gl.createProgram(); + gl.attachShader(program, vertexShader); + gl.attachShader(program, fragmentShader); + for (var attribName in attribLocationMap) { + gl.bindAttribLocation(program, attribLocationMap[attribName], attribName); + }gl.linkProgram(program); + gl.deleteShader(vertexShader); + gl.deleteShader(fragmentShader); + return program; +}; +var getProgramUniforms = function getProgramUniforms(gl, program) { + var uniforms = {}; + var uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); + var uniformName = ''; + for (var i = 0; i < uniformCount; i++) { + var uniformInfo = gl.getActiveUniform(program, i); + uniformName = uniformInfo.name.replace('[0]', ''); + uniforms[uniformName] = gl.getUniformLocation(program, uniformName); + } + return uniforms; +}; +var orthoMatrix = function orthoMatrix(out, left, right, bottom, top, near, far) { + var lr = 1 / (left - right), + bt = 1 / (bottom - top), + nf = 1 / (near - far); + out[0] = -2 * lr; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = -2 * bt; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 2 * nf; + out[11] = 0; + out[12] = (left + right) * lr; + out[13] = (top + bottom) * bt; + out[14] = (far + near) * nf; + out[15] = 1; + return out; +}; +var isMobile = function isMobile() { + var check = false; + (function (a) { + if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true; + })(navigator.userAgent || navigator.vendor || window.opera); + return check; +}; +var extend = function extend(dest, src) { + for (var key in src) { + if (src.hasOwnProperty(key)) { + dest[key] = src[key]; + } + } + return dest; +}; +var safariCssSizeWorkaround = function safariCssSizeWorkaround(canvas) { + if (isIOS()) { + var width = canvas.style.width; + var height = canvas.style.height; + canvas.style.width = parseInt(width) + 1 + 'px'; + canvas.style.height = parseInt(height) + 'px'; + setTimeout(function () { + canvas.style.width = width; + canvas.style.height = height; + }, 100); + } + window.canvas = canvas; +}; +var frameDataFromPose = function () { + var piOver180 = Math.PI / 180.0; + var rad45 = Math.PI * 0.25; + function mat4_perspectiveFromFieldOfView(out, fov, near, far) { + var upTan = Math.tan(fov ? fov.upDegrees * piOver180 : rad45), + downTan = Math.tan(fov ? fov.downDegrees * piOver180 : rad45), + leftTan = Math.tan(fov ? fov.leftDegrees * piOver180 : rad45), + rightTan = Math.tan(fov ? fov.rightDegrees * piOver180 : rad45), + xScale = 2.0 / (leftTan + rightTan), + yScale = 2.0 / (upTan + downTan); + out[0] = xScale; + out[1] = 0.0; + out[2] = 0.0; + out[3] = 0.0; + out[4] = 0.0; + out[5] = yScale; + out[6] = 0.0; + out[7] = 0.0; + out[8] = -((leftTan - rightTan) * xScale * 0.5); + out[9] = (upTan - downTan) * yScale * 0.5; + out[10] = far / (near - far); + out[11] = -1.0; + out[12] = 0.0; + out[13] = 0.0; + out[14] = far * near / (near - far); + out[15] = 0.0; + return out; + } + function mat4_fromRotationTranslation(out, q, v) { + var x = q[0], + y = q[1], + z = q[2], + w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + out[0] = 1 - (yy + zz); + out[1] = xy + wz; + out[2] = xz - wy; + out[3] = 0; + out[4] = xy - wz; + out[5] = 1 - (xx + zz); + out[6] = yz + wx; + out[7] = 0; + out[8] = xz + wy; + out[9] = yz - wx; + out[10] = 1 - (xx + yy); + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + return out; + } + function mat4_translate(out, a, v) { + var x = v[0], + y = v[1], + z = v[2], + a00, + a01, + a02, + a03, + a10, + a11, + a12, + a13, + a20, + a21, + a22, + a23; + if (a === out) { + out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; + out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; + out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; + out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; + } else { + a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3]; + a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7]; + a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11]; + out[0] = a00;out[1] = a01;out[2] = a02;out[3] = a03; + out[4] = a10;out[5] = a11;out[6] = a12;out[7] = a13; + out[8] = a20;out[9] = a21;out[10] = a22;out[11] = a23; + out[12] = a00 * x + a10 * y + a20 * z + a[12]; + out[13] = a01 * x + a11 * y + a21 * z + a[13]; + out[14] = a02 * x + a12 * y + a22 * z + a[14]; + out[15] = a03 * x + a13 * y + a23 * z + a[15]; + } + return out; + } + function mat4_invert(out, a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3], + a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7], + a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11], + a30 = a[12], + a31 = a[13], + a32 = a[14], + a33 = a[15], + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + if (!det) { + return null; + } + det = 1.0 / det; + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; + out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; + out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; + out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; + out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; + out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; + out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; + return out; + } + var defaultOrientation = new Float32Array([0, 0, 0, 1]); + var defaultPosition = new Float32Array([0, 0, 0]); + function updateEyeMatrices(projection, view, pose, fov, offset, vrDisplay) { + mat4_perspectiveFromFieldOfView(projection, fov || null, vrDisplay.depthNear, vrDisplay.depthFar); + var orientation = pose.orientation || defaultOrientation; + var position = pose.position || defaultPosition; + mat4_fromRotationTranslation(view, orientation, position); + if (offset) mat4_translate(view, view, offset); + mat4_invert(view, view); + } + return function (frameData, pose, vrDisplay) { + if (!frameData || !pose) return false; + frameData.pose = pose; + frameData.timestamp = pose.timestamp; + updateEyeMatrices(frameData.leftProjectionMatrix, frameData.leftViewMatrix, pose, vrDisplay._getFieldOfView("left"), vrDisplay._getEyeOffset("left"), vrDisplay); + updateEyeMatrices(frameData.rightProjectionMatrix, frameData.rightViewMatrix, pose, vrDisplay._getFieldOfView("right"), vrDisplay._getEyeOffset("right"), vrDisplay); + return true; + }; +}(); +var isInsideCrossOriginIFrame = function isInsideCrossOriginIFrame() { + var isFramed = window.self !== window.top; + var refOrigin = getOriginFromUrl(document.referrer); + var thisOrigin = getOriginFromUrl(window.location.href); + return isFramed && refOrigin !== thisOrigin; +}; +var getOriginFromUrl = function getOriginFromUrl(url) { + var domainIdx; + var protoSepIdx = url.indexOf("://"); + if (protoSepIdx !== -1) { + domainIdx = protoSepIdx + 3; + } else { + domainIdx = 0; + } + var domainEndIdx = url.indexOf('/', domainIdx); + if (domainEndIdx === -1) { + domainEndIdx = url.length; + } + return url.substring(0, domainEndIdx); +}; +var getQuaternionAngle = function getQuaternionAngle(quat) { + if (quat.w > 1) { + console.warn('getQuaternionAngle: w > 1'); + return 0; + } + var angle = 2 * Math.acos(quat.w); + return angle; +}; +var warnOnce = function () { + var observedWarnings = {}; + return function (key, message) { + if (observedWarnings[key] === undefined) { + console.warn('webvr-polyfill: ' + message); + observedWarnings[key] = true; + } + }; +}(); +var deprecateWarning = function deprecateWarning(deprecated, suggested) { + var alternative = suggested ? 'Please use ' + suggested + ' instead.' : ''; + warnOnce(deprecated, deprecated + ' has been deprecated. ' + 'This may not work on native WebVR displays. ' + alternative); +}; +function WGLUPreserveGLState(gl, bindings, callback) { + if (!bindings) { + callback(gl); + return; + } + var boundValues = []; + var activeTexture = null; + for (var i = 0; i < bindings.length; ++i) { + var binding = bindings[i]; + switch (binding) { + case gl.TEXTURE_BINDING_2D: + case gl.TEXTURE_BINDING_CUBE_MAP: + var textureUnit = bindings[++i]; + if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) { + console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit"); + boundValues.push(null, null); + break; + } + if (!activeTexture) { + activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE); + } + gl.activeTexture(textureUnit); + boundValues.push(gl.getParameter(binding), null); + break; + case gl.ACTIVE_TEXTURE: + activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE); + boundValues.push(null); + break; + default: + boundValues.push(gl.getParameter(binding)); + break; + } + } + callback(gl); + for (var i = 0; i < bindings.length; ++i) { + var binding = bindings[i]; + var boundValue = boundValues[i]; + switch (binding) { + case gl.ACTIVE_TEXTURE: + break; + case gl.ARRAY_BUFFER_BINDING: + gl.bindBuffer(gl.ARRAY_BUFFER, boundValue); + break; + case gl.COLOR_CLEAR_VALUE: + gl.clearColor(boundValue[0], boundValue[1], boundValue[2], boundValue[3]); + break; + case gl.COLOR_WRITEMASK: + gl.colorMask(boundValue[0], boundValue[1], boundValue[2], boundValue[3]); + break; + case gl.CURRENT_PROGRAM: + gl.useProgram(boundValue); + break; + case gl.ELEMENT_ARRAY_BUFFER_BINDING: + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boundValue); + break; + case gl.FRAMEBUFFER_BINDING: + gl.bindFramebuffer(gl.FRAMEBUFFER, boundValue); + break; + case gl.RENDERBUFFER_BINDING: + gl.bindRenderbuffer(gl.RENDERBUFFER, boundValue); + break; + case gl.TEXTURE_BINDING_2D: + var textureUnit = bindings[++i]; + if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) + break; + gl.activeTexture(textureUnit); + gl.bindTexture(gl.TEXTURE_2D, boundValue); + break; + case gl.TEXTURE_BINDING_CUBE_MAP: + var textureUnit = bindings[++i]; + if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) + break; + gl.activeTexture(textureUnit); + gl.bindTexture(gl.TEXTURE_CUBE_MAP, boundValue); + break; + case gl.VIEWPORT: + gl.viewport(boundValue[0], boundValue[1], boundValue[2], boundValue[3]); + break; + case gl.BLEND: + case gl.CULL_FACE: + case gl.DEPTH_TEST: + case gl.SCISSOR_TEST: + case gl.STENCIL_TEST: + if (boundValue) { + gl.enable(binding); + } else { + gl.disable(binding); + } + break; + default: + console.log("No GL restore behavior for 0x" + binding.toString(16)); + break; + } + if (activeTexture) { + gl.activeTexture(activeTexture); + } + } +} +var glPreserveState = WGLUPreserveGLState; +var distortionVS = ['attribute vec2 position;', 'attribute vec3 texCoord;', 'varying vec2 vTexCoord;', 'uniform vec4 viewportOffsetScale[2];', 'void main() {', ' vec4 viewport = viewportOffsetScale[int(texCoord.z)];', ' vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;', ' gl_Position = vec4( position, 1.0, 1.0 );', '}'].join('\n'); +var distortionFS = ['precision mediump float;', 'uniform sampler2D diffuse;', 'varying vec2 vTexCoord;', 'void main() {', ' gl_FragColor = texture2D(diffuse, vTexCoord);', '}'].join('\n'); +function CardboardDistorter(gl, cardboardUI, bufferScale, dirtySubmitFrameBindings) { + this.gl = gl; + this.cardboardUI = cardboardUI; + this.bufferScale = bufferScale; + this.dirtySubmitFrameBindings = dirtySubmitFrameBindings; + this.ctxAttribs = gl.getContextAttributes(); + this.meshWidth = 20; + this.meshHeight = 20; + this.bufferWidth = gl.drawingBufferWidth; + this.bufferHeight = gl.drawingBufferHeight; + this.realBindFramebuffer = gl.bindFramebuffer; + this.realEnable = gl.enable; + this.realDisable = gl.disable; + this.realColorMask = gl.colorMask; + this.realClearColor = gl.clearColor; + this.realViewport = gl.viewport; + if (!isIOS()) { + this.realCanvasWidth = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'width'); + this.realCanvasHeight = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'height'); + } + this.isPatched = false; + this.lastBoundFramebuffer = null; + this.cullFace = false; + this.depthTest = false; + this.blend = false; + this.scissorTest = false; + this.stencilTest = false; + this.viewport = [0, 0, 0, 0]; + this.colorMask = [true, true, true, true]; + this.clearColor = [0, 0, 0, 0]; + this.attribs = { + position: 0, + texCoord: 1 + }; + this.program = linkProgram(gl, distortionVS, distortionFS, this.attribs); + this.uniforms = getProgramUniforms(gl, this.program); + this.viewportOffsetScale = new Float32Array(8); + this.setTextureBounds(); + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + this.indexCount = 0; + this.renderTarget = gl.createTexture(); + this.framebuffer = gl.createFramebuffer(); + this.depthStencilBuffer = null; + this.depthBuffer = null; + this.stencilBuffer = null; + if (this.ctxAttribs.depth && this.ctxAttribs.stencil) { + this.depthStencilBuffer = gl.createRenderbuffer(); + } else if (this.ctxAttribs.depth) { + this.depthBuffer = gl.createRenderbuffer(); + } else if (this.ctxAttribs.stencil) { + this.stencilBuffer = gl.createRenderbuffer(); + } + this.patch(); + this.onResize(); +} +CardboardDistorter.prototype.destroy = function () { + var gl = this.gl; + this.unpatch(); + gl.deleteProgram(this.program); + gl.deleteBuffer(this.vertexBuffer); + gl.deleteBuffer(this.indexBuffer); + gl.deleteTexture(this.renderTarget); + gl.deleteFramebuffer(this.framebuffer); + if (this.depthStencilBuffer) { + gl.deleteRenderbuffer(this.depthStencilBuffer); + } + if (this.depthBuffer) { + gl.deleteRenderbuffer(this.depthBuffer); + } + if (this.stencilBuffer) { + gl.deleteRenderbuffer(this.stencilBuffer); + } + if (this.cardboardUI) { + this.cardboardUI.destroy(); + } +}; +CardboardDistorter.prototype.onResize = function () { + var gl = this.gl; + var self = this; + var glState = [gl.RENDERBUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0]; + glPreserveState(gl, glState, function (gl) { + self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null); + if (self.scissorTest) { + self.realDisable.call(gl, gl.SCISSOR_TEST); + } + self.realColorMask.call(gl, true, true, true, true); + self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + self.realClearColor.call(gl, 0, 0, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.framebuffer); + gl.bindTexture(gl.TEXTURE_2D, self.renderTarget); + gl.texImage2D(gl.TEXTURE_2D, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, self.bufferWidth, self.bufferHeight, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, self.renderTarget, 0); + if (self.ctxAttribs.depth && self.ctxAttribs.stencil) { + gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthStencilBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, self.bufferWidth, self.bufferHeight); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.depthStencilBuffer); + } else if (self.ctxAttribs.depth) { + gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, self.bufferWidth, self.bufferHeight); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, self.depthBuffer); + } else if (self.ctxAttribs.stencil) { + gl.bindRenderbuffer(gl.RENDERBUFFER, self.stencilBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, self.bufferWidth, self.bufferHeight); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.stencilBuffer); + } + if (!gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) { + console.error('Framebuffer incomplete!'); + } + self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer); + if (self.scissorTest) { + self.realEnable.call(gl, gl.SCISSOR_TEST); + } + self.realColorMask.apply(gl, self.colorMask); + self.realViewport.apply(gl, self.viewport); + self.realClearColor.apply(gl, self.clearColor); + }); + if (this.cardboardUI) { + this.cardboardUI.onResize(); + } +}; +CardboardDistorter.prototype.patch = function () { + if (this.isPatched) { + return; + } + var self = this; + var canvas = this.gl.canvas; + var gl = this.gl; + if (!isIOS()) { + canvas.width = getScreenWidth() * this.bufferScale; + canvas.height = getScreenHeight() * this.bufferScale; + Object.defineProperty(canvas, 'width', { + configurable: true, + enumerable: true, + get: function get() { + return self.bufferWidth; + }, + set: function set(value) { + self.bufferWidth = value; + self.realCanvasWidth.set.call(canvas, value); + self.onResize(); + } + }); + Object.defineProperty(canvas, 'height', { + configurable: true, + enumerable: true, + get: function get() { + return self.bufferHeight; + }, + set: function set(value) { + self.bufferHeight = value; + self.realCanvasHeight.set.call(canvas, value); + self.onResize(); + } + }); + } + this.lastBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING); + if (this.lastBoundFramebuffer == null) { + this.lastBoundFramebuffer = this.framebuffer; + this.gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer); + } + this.gl.bindFramebuffer = function (target, framebuffer) { + self.lastBoundFramebuffer = framebuffer ? framebuffer : self.framebuffer; + self.realBindFramebuffer.call(gl, target, self.lastBoundFramebuffer); + }; + this.cullFace = gl.getParameter(gl.CULL_FACE); + this.depthTest = gl.getParameter(gl.DEPTH_TEST); + this.blend = gl.getParameter(gl.BLEND); + this.scissorTest = gl.getParameter(gl.SCISSOR_TEST); + this.stencilTest = gl.getParameter(gl.STENCIL_TEST); + gl.enable = function (pname) { + switch (pname) { + case gl.CULL_FACE: + self.cullFace = true;break; + case gl.DEPTH_TEST: + self.depthTest = true;break; + case gl.BLEND: + self.blend = true;break; + case gl.SCISSOR_TEST: + self.scissorTest = true;break; + case gl.STENCIL_TEST: + self.stencilTest = true;break; + } + self.realEnable.call(gl, pname); + }; + gl.disable = function (pname) { + switch (pname) { + case gl.CULL_FACE: + self.cullFace = false;break; + case gl.DEPTH_TEST: + self.depthTest = false;break; + case gl.BLEND: + self.blend = false;break; + case gl.SCISSOR_TEST: + self.scissorTest = false;break; + case gl.STENCIL_TEST: + self.stencilTest = false;break; + } + self.realDisable.call(gl, pname); + }; + this.colorMask = gl.getParameter(gl.COLOR_WRITEMASK); + gl.colorMask = function (r, g, b, a) { + self.colorMask[0] = r; + self.colorMask[1] = g; + self.colorMask[2] = b; + self.colorMask[3] = a; + self.realColorMask.call(gl, r, g, b, a); + }; + this.clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE); + gl.clearColor = function (r, g, b, a) { + self.clearColor[0] = r; + self.clearColor[1] = g; + self.clearColor[2] = b; + self.clearColor[3] = a; + self.realClearColor.call(gl, r, g, b, a); + }; + this.viewport = gl.getParameter(gl.VIEWPORT); + gl.viewport = function (x, y, w, h) { + self.viewport[0] = x; + self.viewport[1] = y; + self.viewport[2] = w; + self.viewport[3] = h; + self.realViewport.call(gl, x, y, w, h); + }; + this.isPatched = true; + safariCssSizeWorkaround(canvas); +}; +CardboardDistorter.prototype.unpatch = function () { + if (!this.isPatched) { + return; + } + var gl = this.gl; + var canvas = this.gl.canvas; + if (!isIOS()) { + Object.defineProperty(canvas, 'width', this.realCanvasWidth); + Object.defineProperty(canvas, 'height', this.realCanvasHeight); + } + canvas.width = this.bufferWidth; + canvas.height = this.bufferHeight; + gl.bindFramebuffer = this.realBindFramebuffer; + gl.enable = this.realEnable; + gl.disable = this.realDisable; + gl.colorMask = this.realColorMask; + gl.clearColor = this.realClearColor; + gl.viewport = this.realViewport; + if (this.lastBoundFramebuffer == this.framebuffer) { + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + } + this.isPatched = false; + setTimeout(function () { + safariCssSizeWorkaround(canvas); + }, 1); +}; +CardboardDistorter.prototype.setTextureBounds = function (leftBounds, rightBounds) { + if (!leftBounds) { + leftBounds = [0, 0, 0.5, 1]; + } + if (!rightBounds) { + rightBounds = [0.5, 0, 0.5, 1]; + } + this.viewportOffsetScale[0] = leftBounds[0]; + this.viewportOffsetScale[1] = leftBounds[1]; + this.viewportOffsetScale[2] = leftBounds[2]; + this.viewportOffsetScale[3] = leftBounds[3]; + this.viewportOffsetScale[4] = rightBounds[0]; + this.viewportOffsetScale[5] = rightBounds[1]; + this.viewportOffsetScale[6] = rightBounds[2]; + this.viewportOffsetScale[7] = rightBounds[3]; +}; +CardboardDistorter.prototype.submitFrame = function () { + var gl = this.gl; + var self = this; + var glState = []; + if (!this.dirtySubmitFrameBindings) { + glState.push(gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0); + } + glPreserveState(gl, glState, function (gl) { + self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null); + if (self.cullFace) { + self.realDisable.call(gl, gl.CULL_FACE); + } + if (self.depthTest) { + self.realDisable.call(gl, gl.DEPTH_TEST); + } + if (self.blend) { + self.realDisable.call(gl, gl.BLEND); + } + if (self.scissorTest) { + self.realDisable.call(gl, gl.SCISSOR_TEST); + } + if (self.stencilTest) { + self.realDisable.call(gl, gl.STENCIL_TEST); + } + self.realColorMask.call(gl, true, true, true, true); + self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + if (self.ctxAttribs.alpha || isIOS()) { + self.realClearColor.call(gl, 0, 0, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + } + gl.useProgram(self.program); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer); + gl.enableVertexAttribArray(self.attribs.position); + gl.enableVertexAttribArray(self.attribs.texCoord); + gl.vertexAttribPointer(self.attribs.position, 2, gl.FLOAT, false, 20, 0); + gl.vertexAttribPointer(self.attribs.texCoord, 3, gl.FLOAT, false, 20, 8); + gl.activeTexture(gl.TEXTURE0); + gl.uniform1i(self.uniforms.diffuse, 0); + gl.bindTexture(gl.TEXTURE_2D, self.renderTarget); + gl.uniform4fv(self.uniforms.viewportOffsetScale, self.viewportOffsetScale); + gl.drawElements(gl.TRIANGLES, self.indexCount, gl.UNSIGNED_SHORT, 0); + if (self.cardboardUI) { + self.cardboardUI.renderNoState(); + } + self.realBindFramebuffer.call(self.gl, gl.FRAMEBUFFER, self.framebuffer); + if (!self.ctxAttribs.preserveDrawingBuffer) { + self.realClearColor.call(gl, 0, 0, 0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + } + if (!self.dirtySubmitFrameBindings) { + self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer); + } + if (self.cullFace) { + self.realEnable.call(gl, gl.CULL_FACE); + } + if (self.depthTest) { + self.realEnable.call(gl, gl.DEPTH_TEST); + } + if (self.blend) { + self.realEnable.call(gl, gl.BLEND); + } + if (self.scissorTest) { + self.realEnable.call(gl, gl.SCISSOR_TEST); + } + if (self.stencilTest) { + self.realEnable.call(gl, gl.STENCIL_TEST); + } + self.realColorMask.apply(gl, self.colorMask); + self.realViewport.apply(gl, self.viewport); + if (self.ctxAttribs.alpha || !self.ctxAttribs.preserveDrawingBuffer) { + self.realClearColor.apply(gl, self.clearColor); + } + }); + if (isIOS()) { + var canvas = gl.canvas; + if (canvas.width != self.bufferWidth || canvas.height != self.bufferHeight) { + self.bufferWidth = canvas.width; + self.bufferHeight = canvas.height; + self.onResize(); + } + } +}; +CardboardDistorter.prototype.updateDeviceInfo = function (deviceInfo) { + var gl = this.gl; + var self = this; + var glState = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING]; + glPreserveState(gl, glState, function (gl) { + var vertices = self.computeMeshVertices_(self.meshWidth, self.meshHeight, deviceInfo); + gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); + if (!self.indexCount) { + var indices = self.computeMeshIndices_(self.meshWidth, self.meshHeight); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); + self.indexCount = indices.length; + } + }); +}; +CardboardDistorter.prototype.computeMeshVertices_ = function (width, height, deviceInfo) { + var vertices = new Float32Array(2 * width * height * 5); + var lensFrustum = deviceInfo.getLeftEyeVisibleTanAngles(); + var noLensFrustum = deviceInfo.getLeftEyeNoLensTanAngles(); + var viewport = deviceInfo.getLeftEyeVisibleScreenRect(noLensFrustum); + var vidx = 0; + for (var e = 0; e < 2; e++) { + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++, vidx++) { + var u = i / (width - 1); + var v = j / (height - 1); + var s = u; + var t = v; + var x = lerp(lensFrustum[0], lensFrustum[2], u); + var y = lerp(lensFrustum[3], lensFrustum[1], v); + var d = Math.sqrt(x * x + y * y); + var r = deviceInfo.distortion.distortInverse(d); + var p = x * r / d; + var q = y * r / d; + u = (p - noLensFrustum[0]) / (noLensFrustum[2] - noLensFrustum[0]); + v = (q - noLensFrustum[3]) / (noLensFrustum[1] - noLensFrustum[3]); + u = (viewport.x + u * viewport.width - 0.5) * 2.0; + v = (viewport.y + v * viewport.height - 0.5) * 2.0; + vertices[vidx * 5 + 0] = u; + vertices[vidx * 5 + 1] = v; + vertices[vidx * 5 + 2] = s; + vertices[vidx * 5 + 3] = t; + vertices[vidx * 5 + 4] = e; + } + } + var w = lensFrustum[2] - lensFrustum[0]; + lensFrustum[0] = -(w + lensFrustum[0]); + lensFrustum[2] = w - lensFrustum[2]; + w = noLensFrustum[2] - noLensFrustum[0]; + noLensFrustum[0] = -(w + noLensFrustum[0]); + noLensFrustum[2] = w - noLensFrustum[2]; + viewport.x = 1 - (viewport.x + viewport.width); + } + return vertices; +}; +CardboardDistorter.prototype.computeMeshIndices_ = function (width, height) { + var indices = new Uint16Array(2 * (width - 1) * (height - 1) * 6); + var halfwidth = width / 2; + var halfheight = height / 2; + var vidx = 0; + var iidx = 0; + for (var e = 0; e < 2; e++) { + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++, vidx++) { + if (i == 0 || j == 0) continue; + if (i <= halfwidth == j <= halfheight) { + indices[iidx++] = vidx; + indices[iidx++] = vidx - width - 1; + indices[iidx++] = vidx - width; + indices[iidx++] = vidx - width - 1; + indices[iidx++] = vidx; + indices[iidx++] = vidx - 1; + } else { + indices[iidx++] = vidx - 1; + indices[iidx++] = vidx - width; + indices[iidx++] = vidx; + indices[iidx++] = vidx - width; + indices[iidx++] = vidx - 1; + indices[iidx++] = vidx - width - 1; + } + } + } + } + return indices; +}; +CardboardDistorter.prototype.getOwnPropertyDescriptor_ = function (proto, attrName) { + var descriptor = Object.getOwnPropertyDescriptor(proto, attrName); + if (descriptor.get === undefined || descriptor.set === undefined) { + descriptor.configurable = true; + descriptor.enumerable = true; + descriptor.get = function () { + return this.getAttribute(attrName); + }; + descriptor.set = function (val) { + this.setAttribute(attrName, val); + }; + } + return descriptor; +}; +var uiVS = ['attribute vec2 position;', 'uniform mat4 projectionMat;', 'void main() {', ' gl_Position = projectionMat * vec4( position, -1.0, 1.0 );', '}'].join('\n'); +var uiFS = ['precision mediump float;', 'uniform vec4 color;', 'void main() {', ' gl_FragColor = color;', '}'].join('\n'); +var DEG2RAD = Math.PI / 180.0; +var kAnglePerGearSection = 60; +var kOuterRimEndAngle = 12; +var kInnerRimBeginAngle = 20; +var kOuterRadius = 1; +var kMiddleRadius = 0.75; +var kInnerRadius = 0.3125; +var kCenterLineThicknessDp = 4; +var kButtonWidthDp = 28; +var kTouchSlopFactor = 1.5; +function CardboardUI(gl) { + this.gl = gl; + this.attribs = { + position: 0 + }; + this.program = linkProgram(gl, uiVS, uiFS, this.attribs); + this.uniforms = getProgramUniforms(gl, this.program); + this.vertexBuffer = gl.createBuffer(); + this.gearOffset = 0; + this.gearVertexCount = 0; + this.arrowOffset = 0; + this.arrowVertexCount = 0; + this.projMat = new Float32Array(16); + this.listener = null; + this.onResize(); +} +CardboardUI.prototype.destroy = function () { + var gl = this.gl; + if (this.listener) { + gl.canvas.removeEventListener('click', this.listener, false); + } + gl.deleteProgram(this.program); + gl.deleteBuffer(this.vertexBuffer); +}; +CardboardUI.prototype.listen = function (optionsCallback, backCallback) { + var canvas = this.gl.canvas; + this.listener = function (event) { + var midline = canvas.clientWidth / 2; + var buttonSize = kButtonWidthDp * kTouchSlopFactor; + if (event.clientX > midline - buttonSize && event.clientX < midline + buttonSize && event.clientY > canvas.clientHeight - buttonSize) { + optionsCallback(event); + } + else if (event.clientX < buttonSize && event.clientY < buttonSize) { + backCallback(event); + } + }; + canvas.addEventListener('click', this.listener, false); +}; +CardboardUI.prototype.onResize = function () { + var gl = this.gl; + var self = this; + var glState = [gl.ARRAY_BUFFER_BINDING]; + glPreserveState(gl, glState, function (gl) { + var vertices = []; + var midline = gl.drawingBufferWidth / 2; + var physicalPixels = Math.max(screen.width, screen.height) * window.devicePixelRatio; + var scalingRatio = gl.drawingBufferWidth / physicalPixels; + var dps = scalingRatio * window.devicePixelRatio; + var lineWidth = kCenterLineThicknessDp * dps / 2; + var buttonSize = kButtonWidthDp * kTouchSlopFactor * dps; + var buttonScale = kButtonWidthDp * dps / 2; + var buttonBorder = (kButtonWidthDp * kTouchSlopFactor - kButtonWidthDp) * dps; + vertices.push(midline - lineWidth, buttonSize); + vertices.push(midline - lineWidth, gl.drawingBufferHeight); + vertices.push(midline + lineWidth, buttonSize); + vertices.push(midline + lineWidth, gl.drawingBufferHeight); + self.gearOffset = vertices.length / 2; + function addGearSegment(theta, r) { + var angle = (90 - theta) * DEG2RAD; + var x = Math.cos(angle); + var y = Math.sin(angle); + vertices.push(kInnerRadius * x * buttonScale + midline, kInnerRadius * y * buttonScale + buttonScale); + vertices.push(r * x * buttonScale + midline, r * y * buttonScale + buttonScale); + } + for (var i = 0; i <= 6; i++) { + var segmentTheta = i * kAnglePerGearSection; + addGearSegment(segmentTheta, kOuterRadius); + addGearSegment(segmentTheta + kOuterRimEndAngle, kOuterRadius); + addGearSegment(segmentTheta + kInnerRimBeginAngle, kMiddleRadius); + addGearSegment(segmentTheta + (kAnglePerGearSection - kInnerRimBeginAngle), kMiddleRadius); + addGearSegment(segmentTheta + (kAnglePerGearSection - kOuterRimEndAngle), kOuterRadius); + } + self.gearVertexCount = vertices.length / 2 - self.gearOffset; + self.arrowOffset = vertices.length / 2; + function addArrowVertex(x, y) { + vertices.push(buttonBorder + x, gl.drawingBufferHeight - buttonBorder - y); + } + var angledLineWidth = lineWidth / Math.sin(45 * DEG2RAD); + addArrowVertex(0, buttonScale); + addArrowVertex(buttonScale, 0); + addArrowVertex(buttonScale + angledLineWidth, angledLineWidth); + addArrowVertex(angledLineWidth, buttonScale + angledLineWidth); + addArrowVertex(angledLineWidth, buttonScale - angledLineWidth); + addArrowVertex(0, buttonScale); + addArrowVertex(buttonScale, buttonScale * 2); + addArrowVertex(buttonScale + angledLineWidth, buttonScale * 2 - angledLineWidth); + addArrowVertex(angledLineWidth, buttonScale - angledLineWidth); + addArrowVertex(0, buttonScale); + addArrowVertex(angledLineWidth, buttonScale - lineWidth); + addArrowVertex(kButtonWidthDp * dps, buttonScale - lineWidth); + addArrowVertex(angledLineWidth, buttonScale + lineWidth); + addArrowVertex(kButtonWidthDp * dps, buttonScale + lineWidth); + self.arrowVertexCount = vertices.length / 2 - self.arrowOffset; + gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); + }); +}; +CardboardUI.prototype.render = function () { + var gl = this.gl; + var self = this; + var glState = [gl.CULL_FACE, gl.DEPTH_TEST, gl.BLEND, gl.SCISSOR_TEST, gl.STENCIL_TEST, gl.COLOR_WRITEMASK, gl.VIEWPORT, gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING]; + glPreserveState(gl, glState, function (gl) { + gl.disable(gl.CULL_FACE); + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.BLEND); + gl.disable(gl.SCISSOR_TEST); + gl.disable(gl.STENCIL_TEST); + gl.colorMask(true, true, true, true); + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + self.renderNoState(); + }); +}; +CardboardUI.prototype.renderNoState = function () { + var gl = this.gl; + gl.useProgram(this.program); + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.enableVertexAttribArray(this.attribs.position); + gl.vertexAttribPointer(this.attribs.position, 2, gl.FLOAT, false, 8, 0); + gl.uniform4f(this.uniforms.color, 1.0, 1.0, 1.0, 1.0); + orthoMatrix(this.projMat, 0, gl.drawingBufferWidth, 0, gl.drawingBufferHeight, 0.1, 1024.0); + gl.uniformMatrix4fv(this.uniforms.projectionMat, false, this.projMat); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + gl.drawArrays(gl.TRIANGLE_STRIP, this.gearOffset, this.gearVertexCount); + gl.drawArrays(gl.TRIANGLE_STRIP, this.arrowOffset, this.arrowVertexCount); +}; +function Distortion(coefficients) { + this.coefficients = coefficients; +} +Distortion.prototype.distortInverse = function (radius) { + var r0 = 0; + var r1 = 1; + var dr0 = radius - this.distort(r0); + while (Math.abs(r1 - r0) > 0.0001 ) { + var dr1 = radius - this.distort(r1); + var r2 = r1 - dr1 * ((r1 - r0) / (dr1 - dr0)); + r0 = r1; + r1 = r2; + dr0 = dr1; + } + return r1; +}; +Distortion.prototype.distort = function (radius) { + var r2 = radius * radius; + var ret = 0; + for (var i = 0; i < this.coefficients.length; i++) { + ret = r2 * (ret + this.coefficients[i]); + } + return (ret + 1) * radius; +}; +var degToRad = Math.PI / 180; +var radToDeg = 180 / Math.PI; +var Vector3 = function Vector3(x, y, z) { + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; +}; +Vector3.prototype = { + constructor: Vector3, + set: function set(x, y, z) { + this.x = x; + this.y = y; + this.z = z; + return this; + }, + copy: function copy(v) { + this.x = v.x; + this.y = v.y; + this.z = v.z; + return this; + }, + length: function length() { + return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); + }, + normalize: function normalize() { + var scalar = this.length(); + if (scalar !== 0) { + var invScalar = 1 / scalar; + this.multiplyScalar(invScalar); + } else { + this.x = 0; + this.y = 0; + this.z = 0; + } + return this; + }, + multiplyScalar: function multiplyScalar(scalar) { + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + }, + applyQuaternion: function applyQuaternion(q) { + var x = this.x; + var y = this.y; + var z = this.z; + var qx = q.x; + var qy = q.y; + var qz = q.z; + var qw = q.w; + var ix = qw * x + qy * z - qz * y; + var iy = qw * y + qz * x - qx * z; + var iz = qw * z + qx * y - qy * x; + var iw = -qx * x - qy * y - qz * z; + this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + return this; + }, + dot: function dot(v) { + return this.x * v.x + this.y * v.y + this.z * v.z; + }, + crossVectors: function crossVectors(a, b) { + var ax = a.x, + ay = a.y, + az = a.z; + var bx = b.x, + by = b.y, + bz = b.z; + this.x = ay * bz - az * by; + this.y = az * bx - ax * bz; + this.z = ax * by - ay * bx; + return this; + } +}; +var Quaternion = function Quaternion(x, y, z, w) { + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + this.w = w !== undefined ? w : 1; +}; +Quaternion.prototype = { + constructor: Quaternion, + set: function set(x, y, z, w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + return this; + }, + copy: function copy(quaternion) { + this.x = quaternion.x; + this.y = quaternion.y; + this.z = quaternion.z; + this.w = quaternion.w; + return this; + }, + setFromEulerXYZ: function setFromEulerXYZ(x, y, z) { + var c1 = Math.cos(x / 2); + var c2 = Math.cos(y / 2); + var c3 = Math.cos(z / 2); + var s1 = Math.sin(x / 2); + var s2 = Math.sin(y / 2); + var s3 = Math.sin(z / 2); + this.x = s1 * c2 * c3 + c1 * s2 * s3; + this.y = c1 * s2 * c3 - s1 * c2 * s3; + this.z = c1 * c2 * s3 + s1 * s2 * c3; + this.w = c1 * c2 * c3 - s1 * s2 * s3; + return this; + }, + setFromEulerYXZ: function setFromEulerYXZ(x, y, z) { + var c1 = Math.cos(x / 2); + var c2 = Math.cos(y / 2); + var c3 = Math.cos(z / 2); + var s1 = Math.sin(x / 2); + var s2 = Math.sin(y / 2); + var s3 = Math.sin(z / 2); + this.x = s1 * c2 * c3 + c1 * s2 * s3; + this.y = c1 * s2 * c3 - s1 * c2 * s3; + this.z = c1 * c2 * s3 - s1 * s2 * c3; + this.w = c1 * c2 * c3 + s1 * s2 * s3; + return this; + }, + setFromAxisAngle: function setFromAxisAngle(axis, angle) { + var halfAngle = angle / 2, + s = Math.sin(halfAngle); + this.x = axis.x * s; + this.y = axis.y * s; + this.z = axis.z * s; + this.w = Math.cos(halfAngle); + return this; + }, + multiply: function multiply(q) { + return this.multiplyQuaternions(this, q); + }, + multiplyQuaternions: function multiplyQuaternions(a, b) { + var qax = a.x, + qay = a.y, + qaz = a.z, + qaw = a.w; + var qbx = b.x, + qby = b.y, + qbz = b.z, + qbw = b.w; + this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + return this; + }, + inverse: function inverse() { + this.x *= -1; + this.y *= -1; + this.z *= -1; + this.normalize(); + return this; + }, + normalize: function normalize() { + var l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); + if (l === 0) { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 1; + } else { + l = 1 / l; + this.x = this.x * l; + this.y = this.y * l; + this.z = this.z * l; + this.w = this.w * l; + } + return this; + }, + slerp: function slerp(qb, t) { + if (t === 0) return this; + if (t === 1) return this.copy(qb); + var x = this.x, + y = this.y, + z = this.z, + w = this.w; + var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z; + if (cosHalfTheta < 0) { + this.w = -qb.w; + this.x = -qb.x; + this.y = -qb.y; + this.z = -qb.z; + cosHalfTheta = -cosHalfTheta; + } else { + this.copy(qb); + } + if (cosHalfTheta >= 1.0) { + this.w = w; + this.x = x; + this.y = y; + this.z = z; + return this; + } + var halfTheta = Math.acos(cosHalfTheta); + var sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); + if (Math.abs(sinHalfTheta) < 0.001) { + this.w = 0.5 * (w + this.w); + this.x = 0.5 * (x + this.x); + this.y = 0.5 * (y + this.y); + this.z = 0.5 * (z + this.z); + return this; + } + var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta, + ratioB = Math.sin(t * halfTheta) / sinHalfTheta; + this.w = w * ratioA + this.w * ratioB; + this.x = x * ratioA + this.x * ratioB; + this.y = y * ratioA + this.y * ratioB; + this.z = z * ratioA + this.z * ratioB; + return this; + }, + setFromUnitVectors: function () { + var v1, r; + var EPS = 0.000001; + return function (vFrom, vTo) { + if (v1 === undefined) v1 = new Vector3(); + r = vFrom.dot(vTo) + 1; + if (r < EPS) { + r = 0; + if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) { + v1.set(-vFrom.y, vFrom.x, 0); + } else { + v1.set(0, -vFrom.z, vFrom.y); + } + } else { + v1.crossVectors(vFrom, vTo); + } + this.x = v1.x; + this.y = v1.y; + this.z = v1.z; + this.w = r; + this.normalize(); + return this; + }; + }() +}; +function Device(params) { + this.width = params.width || getScreenWidth(); + this.height = params.height || getScreenHeight(); + this.widthMeters = params.widthMeters; + this.heightMeters = params.heightMeters; + this.bevelMeters = params.bevelMeters; +} +var DEFAULT_ANDROID = new Device({ + widthMeters: 0.110, + heightMeters: 0.062, + bevelMeters: 0.004 +}); +var DEFAULT_IOS = new Device({ + widthMeters: 0.1038, + heightMeters: 0.0584, + bevelMeters: 0.004 +}); +var Viewers = { + CardboardV1: new CardboardViewer({ + id: 'CardboardV1', + label: 'Cardboard I/O 2014', + fov: 40, + interLensDistance: 0.060, + baselineLensDistance: 0.035, + screenLensDistance: 0.042, + distortionCoefficients: [0.441, 0.156], + inverseCoefficients: [-0.4410035, 0.42756155, -0.4804439, 0.5460139, -0.58821183, 0.5733938, -0.48303202, 0.33299083, -0.17573841, 0.0651772, -0.01488963, 0.001559834] + }), + CardboardV2: new CardboardViewer({ + id: 'CardboardV2', + label: 'Cardboard I/O 2015', + fov: 60, + interLensDistance: 0.064, + baselineLensDistance: 0.035, + screenLensDistance: 0.039, + distortionCoefficients: [0.34, 0.55], + inverseCoefficients: [-0.33836704, -0.18162185, 0.862655, -1.2462051, 1.0560602, -0.58208317, 0.21609078, -0.05444823, 0.009177956, -9.904169E-4, 6.183535E-5, -1.6981803E-6] + }) +}; +function DeviceInfo(deviceParams, additionalViewers) { + this.viewer = Viewers.CardboardV2; + this.updateDeviceParams(deviceParams); + this.distortion = new Distortion(this.viewer.distortionCoefficients); + for (var i = 0; i < additionalViewers.length; i++) { + var viewer = additionalViewers[i]; + Viewers[viewer.id] = new CardboardViewer(viewer); + } +} +DeviceInfo.prototype.updateDeviceParams = function (deviceParams) { + this.device = this.determineDevice_(deviceParams) || this.device; +}; +DeviceInfo.prototype.getDevice = function () { + return this.device; +}; +DeviceInfo.prototype.setViewer = function (viewer) { + this.viewer = viewer; + this.distortion = new Distortion(this.viewer.distortionCoefficients); +}; +DeviceInfo.prototype.determineDevice_ = function (deviceParams) { + if (!deviceParams) { + if (isIOS()) { + console.warn('Using fallback iOS device measurements.'); + return DEFAULT_IOS; + } else { + console.warn('Using fallback Android device measurements.'); + return DEFAULT_ANDROID; + } + } + var METERS_PER_INCH = 0.0254; + var metersPerPixelX = METERS_PER_INCH / deviceParams.xdpi; + var metersPerPixelY = METERS_PER_INCH / deviceParams.ydpi; + var width = getScreenWidth(); + var height = getScreenHeight(); + return new Device({ + widthMeters: metersPerPixelX * width, + heightMeters: metersPerPixelY * height, + bevelMeters: deviceParams.bevelMm * 0.001 + }); +}; +DeviceInfo.prototype.getDistortedFieldOfViewLeftEye = function () { + var viewer = this.viewer; + var device = this.device; + var distortion = this.distortion; + var eyeToScreenDistance = viewer.screenLensDistance; + var outerDist = (device.widthMeters - viewer.interLensDistance) / 2; + var innerDist = viewer.interLensDistance / 2; + var bottomDist = viewer.baselineLensDistance - device.bevelMeters; + var topDist = device.heightMeters - bottomDist; + var outerAngle = radToDeg * Math.atan(distortion.distort(outerDist / eyeToScreenDistance)); + var innerAngle = radToDeg * Math.atan(distortion.distort(innerDist / eyeToScreenDistance)); + var bottomAngle = radToDeg * Math.atan(distortion.distort(bottomDist / eyeToScreenDistance)); + var topAngle = radToDeg * Math.atan(distortion.distort(topDist / eyeToScreenDistance)); + return { + leftDegrees: Math.min(outerAngle, viewer.fov), + rightDegrees: Math.min(innerAngle, viewer.fov), + downDegrees: Math.min(bottomAngle, viewer.fov), + upDegrees: Math.min(topAngle, viewer.fov) + }; +}; +DeviceInfo.prototype.getLeftEyeVisibleTanAngles = function () { + var viewer = this.viewer; + var device = this.device; + var distortion = this.distortion; + var fovLeft = Math.tan(-degToRad * viewer.fov); + var fovTop = Math.tan(degToRad * viewer.fov); + var fovRight = Math.tan(degToRad * viewer.fov); + var fovBottom = Math.tan(-degToRad * viewer.fov); + var halfWidth = device.widthMeters / 4; + var halfHeight = device.heightMeters / 2; + var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight; + var centerX = viewer.interLensDistance / 2 - halfWidth; + var centerY = -verticalLensOffset; + var centerZ = viewer.screenLensDistance; + var screenLeft = distortion.distort((centerX - halfWidth) / centerZ); + var screenTop = distortion.distort((centerY + halfHeight) / centerZ); + var screenRight = distortion.distort((centerX + halfWidth) / centerZ); + var screenBottom = distortion.distort((centerY - halfHeight) / centerZ); + var result = new Float32Array(4); + result[0] = Math.max(fovLeft, screenLeft); + result[1] = Math.min(fovTop, screenTop); + result[2] = Math.min(fovRight, screenRight); + result[3] = Math.max(fovBottom, screenBottom); + return result; +}; +DeviceInfo.prototype.getLeftEyeNoLensTanAngles = function () { + var viewer = this.viewer; + var device = this.device; + var distortion = this.distortion; + var result = new Float32Array(4); + var fovLeft = distortion.distortInverse(Math.tan(-degToRad * viewer.fov)); + var fovTop = distortion.distortInverse(Math.tan(degToRad * viewer.fov)); + var fovRight = distortion.distortInverse(Math.tan(degToRad * viewer.fov)); + var fovBottom = distortion.distortInverse(Math.tan(-degToRad * viewer.fov)); + var halfWidth = device.widthMeters / 4; + var halfHeight = device.heightMeters / 2; + var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight; + var centerX = viewer.interLensDistance / 2 - halfWidth; + var centerY = -verticalLensOffset; + var centerZ = viewer.screenLensDistance; + var screenLeft = (centerX - halfWidth) / centerZ; + var screenTop = (centerY + halfHeight) / centerZ; + var screenRight = (centerX + halfWidth) / centerZ; + var screenBottom = (centerY - halfHeight) / centerZ; + result[0] = Math.max(fovLeft, screenLeft); + result[1] = Math.min(fovTop, screenTop); + result[2] = Math.min(fovRight, screenRight); + result[3] = Math.max(fovBottom, screenBottom); + return result; +}; +DeviceInfo.prototype.getLeftEyeVisibleScreenRect = function (undistortedFrustum) { + var viewer = this.viewer; + var device = this.device; + var dist = viewer.screenLensDistance; + var eyeX = (device.widthMeters - viewer.interLensDistance) / 2; + var eyeY = viewer.baselineLensDistance - device.bevelMeters; + var left = (undistortedFrustum[0] * dist + eyeX) / device.widthMeters; + var top = (undistortedFrustum[1] * dist + eyeY) / device.heightMeters; + var right = (undistortedFrustum[2] * dist + eyeX) / device.widthMeters; + var bottom = (undistortedFrustum[3] * dist + eyeY) / device.heightMeters; + return { + x: left, + y: bottom, + width: right - left, + height: top - bottom + }; +}; +DeviceInfo.prototype.getFieldOfViewLeftEye = function (opt_isUndistorted) { + return opt_isUndistorted ? this.getUndistortedFieldOfViewLeftEye() : this.getDistortedFieldOfViewLeftEye(); +}; +DeviceInfo.prototype.getFieldOfViewRightEye = function (opt_isUndistorted) { + var fov = this.getFieldOfViewLeftEye(opt_isUndistorted); + return { + leftDegrees: fov.rightDegrees, + rightDegrees: fov.leftDegrees, + upDegrees: fov.upDegrees, + downDegrees: fov.downDegrees + }; +}; +DeviceInfo.prototype.getUndistortedFieldOfViewLeftEye = function () { + var p = this.getUndistortedParams_(); + return { + leftDegrees: radToDeg * Math.atan(p.outerDist), + rightDegrees: radToDeg * Math.atan(p.innerDist), + downDegrees: radToDeg * Math.atan(p.bottomDist), + upDegrees: radToDeg * Math.atan(p.topDist) + }; +}; +DeviceInfo.prototype.getUndistortedViewportLeftEye = function () { + var p = this.getUndistortedParams_(); + var viewer = this.viewer; + var device = this.device; + var eyeToScreenDistance = viewer.screenLensDistance; + var screenWidth = device.widthMeters / eyeToScreenDistance; + var screenHeight = device.heightMeters / eyeToScreenDistance; + var xPxPerTanAngle = device.width / screenWidth; + var yPxPerTanAngle = device.height / screenHeight; + var x = Math.round((p.eyePosX - p.outerDist) * xPxPerTanAngle); + var y = Math.round((p.eyePosY - p.bottomDist) * yPxPerTanAngle); + return { + x: x, + y: y, + width: Math.round((p.eyePosX + p.innerDist) * xPxPerTanAngle) - x, + height: Math.round((p.eyePosY + p.topDist) * yPxPerTanAngle) - y + }; +}; +DeviceInfo.prototype.getUndistortedParams_ = function () { + var viewer = this.viewer; + var device = this.device; + var distortion = this.distortion; + var eyeToScreenDistance = viewer.screenLensDistance; + var halfLensDistance = viewer.interLensDistance / 2 / eyeToScreenDistance; + var screenWidth = device.widthMeters / eyeToScreenDistance; + var screenHeight = device.heightMeters / eyeToScreenDistance; + var eyePosX = screenWidth / 2 - halfLensDistance; + var eyePosY = (viewer.baselineLensDistance - device.bevelMeters) / eyeToScreenDistance; + var maxFov = viewer.fov; + var viewerMax = distortion.distortInverse(Math.tan(degToRad * maxFov)); + var outerDist = Math.min(eyePosX, viewerMax); + var innerDist = Math.min(halfLensDistance, viewerMax); + var bottomDist = Math.min(eyePosY, viewerMax); + var topDist = Math.min(screenHeight - eyePosY, viewerMax); + return { + outerDist: outerDist, + innerDist: innerDist, + topDist: topDist, + bottomDist: bottomDist, + eyePosX: eyePosX, + eyePosY: eyePosY + }; +}; +function CardboardViewer(params) { + this.id = params.id; + this.label = params.label; + this.fov = params.fov; + this.interLensDistance = params.interLensDistance; + this.baselineLensDistance = params.baselineLensDistance; + this.screenLensDistance = params.screenLensDistance; + this.distortionCoefficients = params.distortionCoefficients; + this.inverseCoefficients = params.inverseCoefficients; +} +DeviceInfo.Viewers = Viewers; +var format = 1; +var last_updated = "2018-12-10T17:01:42Z"; +var devices = [{"type":"android","rules":[{"mdmh":"asus/*/Nexus 7/*"},{"ua":"Nexus 7"}],"dpi":[320.8,323],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_Z00AD/*"},{"ua":"ASUS_Z00AD"}],"dpi":[403,404.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2 XL/*"},{"ua":"Pixel 2 XL"}],"dpi":537.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3 XL/*"},{"ua":"Pixel 3 XL"}],"dpi":[558.5,553.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel XL/*"},{"ua":"Pixel XL"}],"dpi":[537.9,533],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3/*"},{"ua":"Pixel 3"}],"dpi":442.4,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2/*"},{"ua":"Pixel 2"}],"dpi":441,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Google/*/Pixel/*"},{"ua":"Pixel"}],"dpi":[432.6,436.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC6435LVW/*"},{"ua":"HTC6435LVW"}],"dpi":[449.7,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One XL/*"},{"ua":"HTC One XL"}],"dpi":[315.3,314.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"htc/*/Nexus 9/*"},{"ua":"Nexus 9"}],"dpi":289,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One M9/*"},{"ua":"HTC One M9"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One_M8/*"},{"ua":"HTC One_M8"}],"dpi":[449.7,447.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One/*"},{"ua":"HTC One"}],"dpi":472.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/Nexus 6P/*"},{"ua":"Nexus 6P"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/BLN-L24/*"},{"ua":"HONORBLN-L24"}],"dpi":480,"bw":4,"ac":500},{"type":"android","rules":[{"mdmh":"Huawei/*/BKL-L09/*"},{"ua":"BKL-L09"}],"dpi":403,"bw":3.47,"ac":500},{"type":"android","rules":[{"mdmh":"LENOVO/*/Lenovo PB2-690Y/*"},{"ua":"Lenovo PB2-690Y"}],"dpi":[457.2,454.713],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5X/*"},{"ua":"Nexus 5X"}],"dpi":[422,419.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS345/*"},{"ua":"LGMS345"}],"dpi":[221.7,219.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D800/*"},{"ua":"LG-D800"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D850/*"},{"ua":"LG-D850"}],"dpi":[537.9,541.9],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/VS985 4G/*"},{"ua":"VS985 4G"}],"dpi":[537.9,535.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5/*"},{"ua":"Nexus 5 B"}],"dpi":[442.4,444.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 4/*"},{"ua":"Nexus 4"}],"dpi":[319.8,318.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LG-P769/*"},{"ua":"LG-P769"}],"dpi":[240.6,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS323/*"},{"ua":"LGMS323"}],"dpi":[206.6,204.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGLS996/*"},{"ua":"LGLS996"}],"dpi":[403.4,401.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/4560MMX/*"},{"ua":"4560MMX"}],"dpi":[240,219.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/A250/*"},{"ua":"Micromax A250"}],"dpi":[480,446.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/Micromax AQ4501/*"},{"ua":"Micromax AQ4501"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/G5/*"},{"ua":"Moto G (5) Plus"}],"dpi":[403.4,403],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/DROID RAZR/*"},{"ua":"DROID RAZR"}],"dpi":[368.1,256.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT830C/*"},{"ua":"XT830C"}],"dpi":[254,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1021/*"},{"ua":"XT1021"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1023/*"},{"ua":"XT1023"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1028/*"},{"ua":"XT1028"}],"dpi":[326.6,327.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1034/*"},{"ua":"XT1034"}],"dpi":[326.6,328.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1053/*"},{"ua":"XT1053"}],"dpi":[315.3,316.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1562/*"},{"ua":"XT1562"}],"dpi":[403.4,402.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/Nexus 6/*"},{"ua":"Nexus 6 B"}],"dpi":[494.3,489.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1063/*"},{"ua":"XT1063"}],"dpi":[295,296.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1064/*"},{"ua":"XT1064"}],"dpi":[295,295.6],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1092/*"},{"ua":"XT1092"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1095/*"},{"ua":"XT1095"}],"dpi":[422,423.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/G4/*"},{"ua":"Moto G (4)"}],"dpi":401,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/A0001/*"},{"ua":"A0001"}],"dpi":[403.4,401],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1005/*"},{"ua":"ONE E1005"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2005/*"},{"ua":"ONE A2005"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A5000/*"},{"ua":"ONEPLUS A5000 "}],"dpi":[403.411,399.737],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A5010/*"},{"ua":"ONEPLUS A5010"}],"dpi":[403,400],"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"OPPO/*/X909/*"},{"ua":"X909"}],"dpi":[442.4,444.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9082/*"},{"ua":"GT-I9082"}],"dpi":[184.7,185.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G360P/*"},{"ua":"SM-G360P"}],"dpi":[196.7,205.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Nexus S/*"},{"ua":"Nexus S"}],"dpi":[234.5,229.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[304.8,303.9],"bw":5,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T230NU/*"},{"ua":"SM-T230NU"}],"dpi":216,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-T399/*"},{"ua":"SGH-T399"}],"dpi":[217.7,231.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-M919/*"},{"ua":"SGH-M919"}],"dpi":[440.8,437.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N9005/*"},{"ua":"SM-N9005"}],"dpi":[386.4,387],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SM-N900A/*"},{"ua":"SAMSUNG-SM-N900A"}],"dpi":[386.4,387.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9500/*"},{"ua":"GT-I9500"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9505/*"},{"ua":"GT-I9505"}],"dpi":439.4,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900F/*"},{"ua":"SM-G900F"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900M/*"},{"ua":"SM-G900M"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G800F/*"},{"ua":"SM-G800F"}],"dpi":326.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G906S/*"},{"ua":"SM-G906S"}],"dpi":[562.7,572.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[306.7,304.8],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T535/*"},{"ua":"SM-T535"}],"dpi":[142.6,136.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920C/*"},{"ua":"SM-N920C"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920P/*"},{"ua":"SM-N920P"}],"dpi":[386.3655,390.144],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920W8/*"},{"ua":"SM-N920W8"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300I/*"},{"ua":"GT-I9300I"}],"dpi":[304.8,305.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9195/*"},{"ua":"GT-I9195"}],"dpi":[249.4,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-L520/*"},{"ua":"SPH-L520"}],"dpi":[249.4,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SGH-I717/*"},{"ua":"SAMSUNG-SGH-I717"}],"dpi":285.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-D710/*"},{"ua":"SPH-D710"}],"dpi":[217.7,204.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-N7100/*"},{"ua":"GT-N7100"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SCH-I605/*"},{"ua":"SCH-I605"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Galaxy Nexus/*"},{"ua":"Galaxy Nexus"}],"dpi":[315.3,314.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910H/*"},{"ua":"SM-N910H"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910C/*"},{"ua":"SM-N910C"}],"dpi":[515.2,520.2],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G130M/*"},{"ua":"SM-G130M"}],"dpi":[165.9,164.8],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G928I/*"},{"ua":"SM-G928I"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920F/*"},{"ua":"SM-G920F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920P/*"},{"ua":"SM-G920P"}],"dpi":[522.5,577],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925F/*"},{"ua":"SM-G925F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925V/*"},{"ua":"SM-G925V"}],"dpi":[522.5,576.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G930F/*"},{"ua":"SM-G930F"}],"dpi":576.6,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G935F/*"},{"ua":"SM-G935F"}],"dpi":533,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G950F/*"},{"ua":"SM-G950F"}],"dpi":[562.707,565.293],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955U/*"},{"ua":"SM-G955U"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955F/*"},{"ua":"SM-G955F"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/C6903/*"},{"ua":"C6903"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/D6653/*"},{"ua":"D6653"}],"dpi":[428.6,427.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6653/*"},{"ua":"E6653"}],"dpi":[428.6,425.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6853/*"},{"ua":"E6853"}],"dpi":[403.4,401.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/SGP321/*"},{"ua":"SGP321"}],"dpi":[224.7,224.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{"ua":"ALCATEL ONE TOUCH Fierce"}],"dpi":[240,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"THL/*/thl 5000/*"},{"ua":"thl 5000"}],"dpi":[480,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Fly/*/IQ4412/*"},{"ua":"IQ4412"}],"dpi":307.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"ZTE/*/ZTE Blade L2/*"},{"ua":"ZTE Blade L2"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"BENEVE/*/VR518/*"},{"ua":"VR518"}],"dpi":480,"bw":3,"ac":500},{"type":"ios","rules":[{"res":[640,960]}],"dpi":[325.1,328.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[640,1136]}],"dpi":[317.1,320.2],"bw":3,"ac":1000},{"type":"ios","rules":[{"res":[750,1334]}],"dpi":326.4,"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1242,2208]}],"dpi":[453.6,458.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2001]}],"dpi":[410.9,415.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2436]}],"dpi":458,"bw":4,"ac":1000}]; +var DPDB_CACHE = { + format: format, + last_updated: last_updated, + devices: devices +}; +function Dpdb(url, onDeviceParamsUpdated) { + this.dpdb = DPDB_CACHE; + this.recalculateDeviceParams_(); + if (url) { + this.onDeviceParamsUpdated = onDeviceParamsUpdated; + var xhr = new XMLHttpRequest(); + var obj = this; + xhr.open('GET', url, true); + xhr.addEventListener('load', function () { + obj.loading = false; + if (xhr.status >= 200 && xhr.status <= 299) { + obj.dpdb = JSON.parse(xhr.response); + obj.recalculateDeviceParams_(); + } else { + console.error('Error loading online DPDB!'); + } + }); + xhr.send(); + } +} +Dpdb.prototype.getDeviceParams = function () { + return this.deviceParams; +}; +Dpdb.prototype.recalculateDeviceParams_ = function () { + var newDeviceParams = this.calcDeviceParams_(); + if (newDeviceParams) { + this.deviceParams = newDeviceParams; + if (this.onDeviceParamsUpdated) { + this.onDeviceParamsUpdated(this.deviceParams); + } + } else { + console.error('Failed to recalculate device parameters.'); + } +}; +Dpdb.prototype.calcDeviceParams_ = function () { + var db = this.dpdb; + if (!db) { + console.error('DPDB not available.'); + return null; + } + if (db.format != 1) { + console.error('DPDB has unexpected format version.'); + return null; + } + if (!db.devices || !db.devices.length) { + console.error('DPDB does not have a devices section.'); + return null; + } + var userAgent = navigator.userAgent || navigator.vendor || window.opera; + var width = getScreenWidth(); + var height = getScreenHeight(); + if (!db.devices) { + console.error('DPDB has no devices section.'); + return null; + } + for (var i = 0; i < db.devices.length; i++) { + var device = db.devices[i]; + if (!device.rules) { + console.warn('Device[' + i + '] has no rules section.'); + continue; + } + if (device.type != 'ios' && device.type != 'android') { + console.warn('Device[' + i + '] has invalid type.'); + continue; + } + if (isIOS() != (device.type == 'ios')) continue; + var matched = false; + for (var j = 0; j < device.rules.length; j++) { + var rule = device.rules[j]; + if (this.ruleMatches_(rule, userAgent, width, height)) { + matched = true; + break; + } + } + if (!matched) continue; + var xdpi = device.dpi[0] || device.dpi; + var ydpi = device.dpi[1] || device.dpi; + return new DeviceParams({ xdpi: xdpi, ydpi: ydpi, bevelMm: device.bw }); + } + console.warn('No DPDB device match.'); + return null; +}; +Dpdb.prototype.ruleMatches_ = function (rule, ua, screenWidth, screenHeight) { + if (!rule.ua && !rule.res) return false; + if (rule.ua && rule.ua.substring(0, 2) === 'SM') rule.ua = rule.ua.substring(0, 7); + if (rule.ua && ua.indexOf(rule.ua) < 0) return false; + if (rule.res) { + if (!rule.res[0] || !rule.res[1]) return false; + var resX = rule.res[0]; + var resY = rule.res[1]; + if (Math.min(screenWidth, screenHeight) != Math.min(resX, resY) || Math.max(screenWidth, screenHeight) != Math.max(resX, resY)) { + return false; + } + } + return true; +}; +function DeviceParams(params) { + this.xdpi = params.xdpi; + this.ydpi = params.ydpi; + this.bevelMm = params.bevelMm; +} +function SensorSample(sample, timestampS) { + this.set(sample, timestampS); +} +SensorSample.prototype.set = function (sample, timestampS) { + this.sample = sample; + this.timestampS = timestampS; +}; +SensorSample.prototype.copy = function (sensorSample) { + this.set(sensorSample.sample, sensorSample.timestampS); +}; +function ComplementaryFilter(kFilter, isDebug) { + this.kFilter = kFilter; + this.isDebug = isDebug; + this.currentAccelMeasurement = new SensorSample(); + this.currentGyroMeasurement = new SensorSample(); + this.previousGyroMeasurement = new SensorSample(); + if (isIOS()) { + this.filterQ = new Quaternion(-1, 0, 0, 1); + } else { + this.filterQ = new Quaternion(1, 0, 0, 1); + } + this.previousFilterQ = new Quaternion(); + this.previousFilterQ.copy(this.filterQ); + this.accelQ = new Quaternion(); + this.isOrientationInitialized = false; + this.estimatedGravity = new Vector3(); + this.measuredGravity = new Vector3(); + this.gyroIntegralQ = new Quaternion(); +} +ComplementaryFilter.prototype.addAccelMeasurement = function (vector, timestampS) { + this.currentAccelMeasurement.set(vector, timestampS); +}; +ComplementaryFilter.prototype.addGyroMeasurement = function (vector, timestampS) { + this.currentGyroMeasurement.set(vector, timestampS); + var deltaT = timestampS - this.previousGyroMeasurement.timestampS; + if (isTimestampDeltaValid(deltaT)) { + this.run_(); + } + this.previousGyroMeasurement.copy(this.currentGyroMeasurement); +}; +ComplementaryFilter.prototype.run_ = function () { + if (!this.isOrientationInitialized) { + this.accelQ = this.accelToQuaternion_(this.currentAccelMeasurement.sample); + this.previousFilterQ.copy(this.accelQ); + this.isOrientationInitialized = true; + return; + } + var deltaT = this.currentGyroMeasurement.timestampS - this.previousGyroMeasurement.timestampS; + var gyroDeltaQ = this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample, deltaT); + this.gyroIntegralQ.multiply(gyroDeltaQ); + this.filterQ.copy(this.previousFilterQ); + this.filterQ.multiply(gyroDeltaQ); + var invFilterQ = new Quaternion(); + invFilterQ.copy(this.filterQ); + invFilterQ.inverse(); + this.estimatedGravity.set(0, 0, -1); + this.estimatedGravity.applyQuaternion(invFilterQ); + this.estimatedGravity.normalize(); + this.measuredGravity.copy(this.currentAccelMeasurement.sample); + this.measuredGravity.normalize(); + var deltaQ = new Quaternion(); + deltaQ.setFromUnitVectors(this.estimatedGravity, this.measuredGravity); + deltaQ.inverse(); + if (this.isDebug) { + console.log('Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)', radToDeg * getQuaternionAngle(deltaQ), this.estimatedGravity.x.toFixed(1), this.estimatedGravity.y.toFixed(1), this.estimatedGravity.z.toFixed(1), this.measuredGravity.x.toFixed(1), this.measuredGravity.y.toFixed(1), this.measuredGravity.z.toFixed(1)); + } + var targetQ = new Quaternion(); + targetQ.copy(this.filterQ); + targetQ.multiply(deltaQ); + this.filterQ.slerp(targetQ, 1 - this.kFilter); + this.previousFilterQ.copy(this.filterQ); +}; +ComplementaryFilter.prototype.getOrientation = function () { + return this.filterQ; +}; +ComplementaryFilter.prototype.accelToQuaternion_ = function (accel) { + var normAccel = new Vector3(); + normAccel.copy(accel); + normAccel.normalize(); + var quat = new Quaternion(); + quat.setFromUnitVectors(new Vector3(0, 0, -1), normAccel); + quat.inverse(); + return quat; +}; +ComplementaryFilter.prototype.gyroToQuaternionDelta_ = function (gyro, dt) { + var quat = new Quaternion(); + var axis = new Vector3(); + axis.copy(gyro); + axis.normalize(); + quat.setFromAxisAngle(axis, gyro.length() * dt); + return quat; +}; +function PosePredictor(predictionTimeS, isDebug) { + this.predictionTimeS = predictionTimeS; + this.isDebug = isDebug; + this.previousQ = new Quaternion(); + this.previousTimestampS = null; + this.deltaQ = new Quaternion(); + this.outQ = new Quaternion(); +} +PosePredictor.prototype.getPrediction = function (currentQ, gyro, timestampS) { + if (!this.previousTimestampS) { + this.previousQ.copy(currentQ); + this.previousTimestampS = timestampS; + return currentQ; + } + var axis = new Vector3(); + axis.copy(gyro); + axis.normalize(); + var angularSpeed = gyro.length(); + if (angularSpeed < degToRad * 20) { + if (this.isDebug) { + console.log('Moving slowly, at %s deg/s: no prediction', (radToDeg * angularSpeed).toFixed(1)); + } + this.outQ.copy(currentQ); + this.previousQ.copy(currentQ); + return this.outQ; + } + var predictAngle = angularSpeed * this.predictionTimeS; + this.deltaQ.setFromAxisAngle(axis, predictAngle); + this.outQ.copy(this.previousQ); + this.outQ.multiply(this.deltaQ); + this.previousQ.copy(currentQ); + this.previousTimestampS = timestampS; + return this.outQ; +}; +function FusionPoseSensor(kFilter, predictionTime, yawOnly, isDebug) { + this.yawOnly = yawOnly; + this.accelerometer = new Vector3(); + this.gyroscope = new Vector3(); + this.filter = new ComplementaryFilter(kFilter, isDebug); + this.posePredictor = new PosePredictor(predictionTime, isDebug); + this.isFirefoxAndroid = isFirefoxAndroid(); + this.isIOS = isIOS(); + var chromeVersion = getChromeVersion(); + this.isDeviceMotionInRadians = !this.isIOS && chromeVersion && chromeVersion < 66; + this.isWithoutDeviceMotion = isChromeWithoutDeviceMotion(); + this.filterToWorldQ = new Quaternion(); + if (isIOS()) { + this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2); + } else { + this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2); + } + this.inverseWorldToScreenQ = new Quaternion(); + this.worldToScreenQ = new Quaternion(); + this.originalPoseAdjustQ = new Quaternion(); + this.originalPoseAdjustQ.setFromAxisAngle(new Vector3(0, 0, 1), -window.orientation * Math.PI / 180); + this.setScreenTransform_(); + if (isLandscapeMode()) { + this.filterToWorldQ.multiply(this.inverseWorldToScreenQ); + } + this.resetQ = new Quaternion(); + this.orientationOut_ = new Float32Array(4); + this.start(); +} +FusionPoseSensor.prototype.getPosition = function () { + return null; +}; +FusionPoseSensor.prototype.getOrientation = function () { + var orientation = void 0; + if (this.isWithoutDeviceMotion && this._deviceOrientationQ) { + this.deviceOrientationFixQ = this.deviceOrientationFixQ || function () { + var z = new Quaternion().setFromAxisAngle(new Vector3(0, 0, -1), 0); + var y = new Quaternion(); + if (window.orientation === -90) { + y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / -2); + } else { + y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 2); + } + return z.multiply(y); + }(); + this.deviceOrientationFilterToWorldQ = this.deviceOrientationFilterToWorldQ || function () { + var q = new Quaternion(); + q.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2); + return q; + }(); + orientation = this._deviceOrientationQ; + var out = new Quaternion(); + out.copy(orientation); + out.multiply(this.deviceOrientationFilterToWorldQ); + out.multiply(this.resetQ); + out.multiply(this.worldToScreenQ); + out.multiplyQuaternions(this.deviceOrientationFixQ, out); + if (this.yawOnly) { + out.x = 0; + out.z = 0; + out.normalize(); + } + this.orientationOut_[0] = out.x; + this.orientationOut_[1] = out.y; + this.orientationOut_[2] = out.z; + this.orientationOut_[3] = out.w; + return this.orientationOut_; + } else { + var filterOrientation = this.filter.getOrientation(); + orientation = this.posePredictor.getPrediction(filterOrientation, this.gyroscope, this.previousTimestampS); + } + var out = new Quaternion(); + out.copy(this.filterToWorldQ); + out.multiply(this.resetQ); + out.multiply(orientation); + out.multiply(this.worldToScreenQ); + if (this.yawOnly) { + out.x = 0; + out.z = 0; + out.normalize(); + } + this.orientationOut_[0] = out.x; + this.orientationOut_[1] = out.y; + this.orientationOut_[2] = out.z; + this.orientationOut_[3] = out.w; + return this.orientationOut_; +}; +FusionPoseSensor.prototype.resetPose = function () { + this.resetQ.copy(this.filter.getOrientation()); + this.resetQ.x = 0; + this.resetQ.y = 0; + this.resetQ.z *= -1; + this.resetQ.normalize(); + if (isLandscapeMode()) { + this.resetQ.multiply(this.inverseWorldToScreenQ); + } + this.resetQ.multiply(this.originalPoseAdjustQ); +}; +FusionPoseSensor.prototype.onDeviceOrientation_ = function (e) { + this._deviceOrientationQ = this._deviceOrientationQ || new Quaternion(); + var alpha = e.alpha, + beta = e.beta, + gamma = e.gamma; + alpha = (alpha || 0) * Math.PI / 180; + beta = (beta || 0) * Math.PI / 180; + gamma = (gamma || 0) * Math.PI / 180; + this._deviceOrientationQ.setFromEulerYXZ(beta, alpha, -gamma); +}; +FusionPoseSensor.prototype.onDeviceMotion_ = function (deviceMotion) { + this.updateDeviceMotion_(deviceMotion); +}; +FusionPoseSensor.prototype.updateDeviceMotion_ = function (deviceMotion) { + var accGravity = deviceMotion.accelerationIncludingGravity; + var rotRate = deviceMotion.rotationRate; + var timestampS = deviceMotion.timeStamp / 1000; + var deltaS = timestampS - this.previousTimestampS; + if (deltaS < 0) { + warnOnce('fusion-pose-sensor:invalid:non-monotonic', 'Invalid timestamps detected: non-monotonic timestamp from devicemotion'); + this.previousTimestampS = timestampS; + return; + } else if (deltaS <= MIN_TIMESTEP || deltaS > MAX_TIMESTEP) { + warnOnce('fusion-pose-sensor:invalid:outside-threshold', 'Invalid timestamps detected: Timestamp from devicemotion outside expected range.'); + this.previousTimestampS = timestampS; + return; + } + this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z); + if (isR7()) { + this.gyroscope.set(-rotRate.beta, rotRate.alpha, rotRate.gamma); + } else { + this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma); + } + if (!this.isDeviceMotionInRadians) { + this.gyroscope.multiplyScalar(Math.PI / 180); + } + this.filter.addAccelMeasurement(this.accelerometer, timestampS); + this.filter.addGyroMeasurement(this.gyroscope, timestampS); + this.previousTimestampS = timestampS; +}; +FusionPoseSensor.prototype.onOrientationChange_ = function (screenOrientation) { + this.setScreenTransform_(); +}; +FusionPoseSensor.prototype.onMessage_ = function (event) { + var message = event.data; + if (!message || !message.type) { + return; + } + var type = message.type.toLowerCase(); + if (type !== 'devicemotion') { + return; + } + this.updateDeviceMotion_(message.deviceMotionEvent); +}; +FusionPoseSensor.prototype.setScreenTransform_ = function () { + this.worldToScreenQ.set(0, 0, 0, 1); + switch (window.orientation) { + case 0: + break; + case 90: + this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), -Math.PI / 2); + break; + case -90: + this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), Math.PI / 2); + break; + case 180: + break; + } + this.inverseWorldToScreenQ.copy(this.worldToScreenQ); + this.inverseWorldToScreenQ.inverse(); +}; +FusionPoseSensor.prototype.start = function () { + this.onDeviceMotionCallback_ = this.onDeviceMotion_.bind(this); + this.onOrientationChangeCallback_ = this.onOrientationChange_.bind(this); + this.onMessageCallback_ = this.onMessage_.bind(this); + this.onDeviceOrientationCallback_ = this.onDeviceOrientation_.bind(this); + if (isIOS() && isInsideCrossOriginIFrame()) { + window.addEventListener('message', this.onMessageCallback_); + } + window.addEventListener('orientationchange', this.onOrientationChangeCallback_); + if (this.isWithoutDeviceMotion) { + window.addEventListener('deviceorientation', this.onDeviceOrientationCallback_); + } else { + window.addEventListener('devicemotion', this.onDeviceMotionCallback_); + } +}; +FusionPoseSensor.prototype.stop = function () { + window.removeEventListener('devicemotion', this.onDeviceMotionCallback_); + window.removeEventListener('deviceorientation', this.onDeviceOrientationCallback_); + window.removeEventListener('orientationchange', this.onOrientationChangeCallback_); + window.removeEventListener('message', this.onMessageCallback_); +}; +var SENSOR_FREQUENCY = 60; +var X_AXIS = new Vector3(1, 0, 0); +var Z_AXIS = new Vector3(0, 0, 1); +var SENSOR_TO_VR = new Quaternion(); +SENSOR_TO_VR.setFromAxisAngle(X_AXIS, -Math.PI / 2); +SENSOR_TO_VR.multiply(new Quaternion().setFromAxisAngle(Z_AXIS, Math.PI / 2)); +var PoseSensor = function () { + function PoseSensor(config) { + classCallCheck(this, PoseSensor); + this.config = config; + this.sensor = null; + this.fusionSensor = null; + this._out = new Float32Array(4); + this.api = null; + this.errors = []; + this._sensorQ = new Quaternion(); + this._outQ = new Quaternion(); + this._onSensorRead = this._onSensorRead.bind(this); + this._onSensorError = this._onSensorError.bind(this); + this.init(); + } + createClass(PoseSensor, [{ + key: 'init', + value: function init() { + var sensor = null; + try { + sensor = new RelativeOrientationSensor({ + frequency: SENSOR_FREQUENCY, + referenceFrame: 'screen' + }); + sensor.addEventListener('error', this._onSensorError); + } catch (error) { + this.errors.push(error); + if (error.name === 'SecurityError') { + console.error('Cannot construct sensors due to the Feature Policy'); + console.warn('Attempting to fall back using "devicemotion"; however this will ' + 'fail in the future without correct permissions.'); + this.useDeviceMotion(); + } else if (error.name === 'ReferenceError') { + this.useDeviceMotion(); + } else { + console.error(error); + } + } + if (sensor) { + this.api = 'sensor'; + this.sensor = sensor; + this.sensor.addEventListener('reading', this._onSensorRead); + this.sensor.start(); + } + } + }, { + key: 'useDeviceMotion', + value: function useDeviceMotion() { + this.api = 'devicemotion'; + this.fusionSensor = new FusionPoseSensor(this.config.K_FILTER, this.config.PREDICTION_TIME_S, this.config.YAW_ONLY, this.config.DEBUG); + if (this.sensor) { + this.sensor.removeEventListener('reading', this._onSensorRead); + this.sensor.removeEventListener('error', this._onSensorError); + this.sensor = null; + } + } + }, { + key: 'getOrientation', + value: function getOrientation() { + if (this.fusionSensor) { + return this.fusionSensor.getOrientation(); + } + if (!this.sensor || !this.sensor.quaternion) { + this._out[0] = this._out[1] = this._out[2] = 0; + this._out[3] = 1; + return this._out; + } + var q = this.sensor.quaternion; + this._sensorQ.set(q[0], q[1], q[2], q[3]); + var out = this._outQ; + out.copy(SENSOR_TO_VR); + out.multiply(this._sensorQ); + if (this.config.YAW_ONLY) { + out.x = out.z = 0; + out.normalize(); + } + this._out[0] = out.x; + this._out[1] = out.y; + this._out[2] = out.z; + this._out[3] = out.w; + return this._out; + } + }, { + key: '_onSensorError', + value: function _onSensorError(event) { + this.errors.push(event.error); + if (event.error.name === 'NotAllowedError') { + console.error('Permission to access sensor was denied'); + } else if (event.error.name === 'NotReadableError') { + console.error('Sensor could not be read'); + } else { + console.error(event.error); + } + this.useDeviceMotion(); + } + }, { + key: '_onSensorRead', + value: function _onSensorRead() {} + }]); + return PoseSensor; +}(); +var rotateInstructionsAsset = ""; +function RotateInstructions() { + this.loadIcon_(); + var overlay = document.createElement('div'); + var s = overlay.style; + s.position = 'fixed'; + s.top = 0; + s.right = 0; + s.bottom = 0; + s.left = 0; + s.backgroundColor = 'gray'; + s.fontFamily = 'sans-serif'; + s.zIndex = 1000000; + var img = document.createElement('img'); + img.src = this.icon; + var s = img.style; + s.marginLeft = '25%'; + s.marginTop = '25%'; + s.width = '50%'; + overlay.appendChild(img); + var text = document.createElement('div'); + var s = text.style; + s.textAlign = 'center'; + s.fontSize = '16px'; + s.lineHeight = '24px'; + s.margin = '24px 25%'; + s.width = '50%'; + text.innerHTML = 'Place your phone into your Cardboard viewer.'; + overlay.appendChild(text); + var snackbar = document.createElement('div'); + var s = snackbar.style; + s.backgroundColor = '#CFD8DC'; + s.position = 'fixed'; + s.bottom = 0; + s.width = '100%'; + s.height = '48px'; + s.padding = '14px 24px'; + s.boxSizing = 'border-box'; + s.color = '#656A6B'; + overlay.appendChild(snackbar); + var snackbarText = document.createElement('div'); + snackbarText.style.float = 'left'; + snackbarText.innerHTML = 'No Cardboard viewer?'; + var snackbarButton = document.createElement('a'); + snackbarButton.href = 'https://www.google.com/get/cardboard/get-cardboard/'; + snackbarButton.innerHTML = 'get one'; + snackbarButton.target = '_blank'; + var s = snackbarButton.style; + s.float = 'right'; + s.fontWeight = 600; + s.textTransform = 'uppercase'; + s.borderLeft = '1px solid gray'; + s.paddingLeft = '24px'; + s.textDecoration = 'none'; + s.color = '#656A6B'; + snackbar.appendChild(snackbarText); + snackbar.appendChild(snackbarButton); + this.overlay = overlay; + this.text = text; + this.hide(); +} +RotateInstructions.prototype.show = function (parent) { + if (!parent && !this.overlay.parentElement) { + document.body.appendChild(this.overlay); + } else if (parent) { + if (this.overlay.parentElement && this.overlay.parentElement != parent) this.overlay.parentElement.removeChild(this.overlay); + parent.appendChild(this.overlay); + } + this.overlay.style.display = 'block'; + var img = this.overlay.querySelector('img'); + var s = img.style; + if (isLandscapeMode()) { + s.width = '20%'; + s.marginLeft = '40%'; + s.marginTop = '3%'; + } else { + s.width = '50%'; + s.marginLeft = '25%'; + s.marginTop = '25%'; + } +}; +RotateInstructions.prototype.hide = function () { + this.overlay.style.display = 'none'; +}; +RotateInstructions.prototype.showTemporarily = function (ms, parent) { + this.show(parent); + this.timer = setTimeout(this.hide.bind(this), ms); +}; +RotateInstructions.prototype.disableShowTemporarily = function () { + clearTimeout(this.timer); +}; +RotateInstructions.prototype.update = function () { + this.disableShowTemporarily(); + if (!isLandscapeMode() && isMobile()) { + this.show(); + } else { + this.hide(); + } +}; +RotateInstructions.prototype.loadIcon_ = function () { + this.icon = dataUri('image/svg+xml', rotateInstructionsAsset); +}; +var DEFAULT_VIEWER = 'CardboardV1'; +var VIEWER_KEY = 'WEBVR_CARDBOARD_VIEWER'; +var CLASS_NAME = 'webvr-polyfill-viewer-selector'; +function ViewerSelector(defaultViewer) { + try { + this.selectedKey = localStorage.getItem(VIEWER_KEY); + } catch (error) { + console.error('Failed to load viewer profile: %s', error); + } + if (!this.selectedKey) { + this.selectedKey = defaultViewer || DEFAULT_VIEWER; + } + this.dialog = this.createDialog_(DeviceInfo.Viewers); + this.root = null; + this.onChangeCallbacks_ = []; +} +ViewerSelector.prototype.show = function (root) { + this.root = root; + root.appendChild(this.dialog); + var selected = this.dialog.querySelector('#' + this.selectedKey); + selected.checked = true; + this.dialog.style.display = 'block'; +}; +ViewerSelector.prototype.hide = function () { + if (this.root && this.root.contains(this.dialog)) { + this.root.removeChild(this.dialog); + } + this.dialog.style.display = 'none'; +}; +ViewerSelector.prototype.getCurrentViewer = function () { + return DeviceInfo.Viewers[this.selectedKey]; +}; +ViewerSelector.prototype.getSelectedKey_ = function () { + var input = this.dialog.querySelector('input[name=field]:checked'); + if (input) { + return input.id; + } + return null; +}; +ViewerSelector.prototype.onChange = function (cb) { + this.onChangeCallbacks_.push(cb); +}; +ViewerSelector.prototype.fireOnChange_ = function (viewer) { + for (var i = 0; i < this.onChangeCallbacks_.length; i++) { + this.onChangeCallbacks_[i](viewer); + } +}; +ViewerSelector.prototype.onSave_ = function () { + this.selectedKey = this.getSelectedKey_(); + if (!this.selectedKey || !DeviceInfo.Viewers[this.selectedKey]) { + console.error('ViewerSelector.onSave_: this should never happen!'); + return; + } + this.fireOnChange_(DeviceInfo.Viewers[this.selectedKey]); + try { + localStorage.setItem(VIEWER_KEY, this.selectedKey); + } catch (error) { + console.error('Failed to save viewer profile: %s', error); + } + this.hide(); +}; +ViewerSelector.prototype.createDialog_ = function (options) { + var container = document.createElement('div'); + container.classList.add(CLASS_NAME); + container.style.display = 'none'; + var overlay = document.createElement('div'); + var s = overlay.style; + s.position = 'fixed'; + s.left = 0; + s.top = 0; + s.width = '100%'; + s.height = '100%'; + s.background = 'rgba(0, 0, 0, 0.3)'; + overlay.addEventListener('click', this.hide.bind(this)); + var width = 280; + var dialog = document.createElement('div'); + var s = dialog.style; + s.boxSizing = 'border-box'; + s.position = 'fixed'; + s.top = '24px'; + s.left = '50%'; + s.marginLeft = -width / 2 + 'px'; + s.width = width + 'px'; + s.padding = '24px'; + s.overflow = 'hidden'; + s.background = '#fafafa'; + s.fontFamily = "'Roboto', sans-serif"; + s.boxShadow = '0px 5px 20px #666'; + dialog.appendChild(this.createH1_('Select your viewer')); + for (var id in options) { + dialog.appendChild(this.createChoice_(id, options[id].label)); + } + dialog.appendChild(this.createButton_('Save', this.onSave_.bind(this))); + container.appendChild(overlay); + container.appendChild(dialog); + return container; +}; +ViewerSelector.prototype.createH1_ = function (name) { + var h1 = document.createElement('h1'); + var s = h1.style; + s.color = 'black'; + s.fontSize = '20px'; + s.fontWeight = 'bold'; + s.marginTop = 0; + s.marginBottom = '24px'; + h1.innerHTML = name; + return h1; +}; +ViewerSelector.prototype.createChoice_ = function (id, name) { + var div = document.createElement('div'); + div.style.marginTop = '8px'; + div.style.color = 'black'; + var input = document.createElement('input'); + input.style.fontSize = '30px'; + input.setAttribute('id', id); + input.setAttribute('type', 'radio'); + input.setAttribute('value', id); + input.setAttribute('name', 'field'); + var label = document.createElement('label'); + label.style.marginLeft = '4px'; + label.setAttribute('for', id); + label.innerHTML = name; + div.appendChild(input); + div.appendChild(label); + return div; +}; +ViewerSelector.prototype.createButton_ = function (label, onclick) { + var button = document.createElement('button'); + button.innerHTML = label; + var s = button.style; + s.float = 'right'; + s.textTransform = 'uppercase'; + s.color = '#1094f7'; + s.fontSize = '14px'; + s.letterSpacing = 0; + s.border = 0; + s.background = 'none'; + s.marginTop = '16px'; + button.addEventListener('click', onclick); + return button; +}; +var commonjsGlobal$$1 = typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {}; +function unwrapExports$$1 (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; +} +function createCommonjsModule$$1(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; +} +var NoSleep = createCommonjsModule$$1(function (module, exports) { +(function webpackUniversalModuleDefinition(root, factory) { + module.exports = factory(); +})(commonjsGlobal$$1, function() { +return (function(modules) { + var installedModules = {}; + function __webpack_require__(moduleId) { + if(installedModules[moduleId]) { + return installedModules[moduleId].exports; + } + var module = installedModules[moduleId] = { + i: moduleId, + l: false, + exports: {} + }; + modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + module.l = true; + return module.exports; + } + __webpack_require__.m = modules; + __webpack_require__.c = installedModules; + __webpack_require__.d = function(exports, name, getter) { + if(!__webpack_require__.o(exports, name)) { + Object.defineProperty(exports, name, { + configurable: false, + enumerable: true, + get: getter + }); + } + }; + __webpack_require__.n = function(module) { + var getter = module && module.__esModule ? + function getDefault() { return module['default']; } : + function getModuleExports() { return module; }; + __webpack_require__.d(getter, 'a', getter); + return getter; + }; + __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; + __webpack_require__.p = ""; + return __webpack_require__(__webpack_require__.s = 0); + }) + ([ + (function(module, exports, __webpack_require__) { +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +var mediaFile = __webpack_require__(1); +var oldIOS = typeof navigator !== 'undefined' && parseFloat(('' + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ''])[1]).replace('undefined', '3_2').replace('_', '.').replace('_', '')) < 10 && !window.MSStream; +var NoSleep = function () { + function NoSleep() { + _classCallCheck(this, NoSleep); + if (oldIOS) { + this.noSleepTimer = null; + } else { + this.noSleepVideo = document.createElement('video'); + this.noSleepVideo.setAttribute('playsinline', ''); + this.noSleepVideo.setAttribute('src', mediaFile); + this.noSleepVideo.addEventListener('timeupdate', function (e) { + if (this.noSleepVideo.currentTime > 0.5) { + this.noSleepVideo.currentTime = Math.random(); + } + }.bind(this)); + } + } + _createClass(NoSleep, [{ + key: 'enable', + value: function enable() { + if (oldIOS) { + this.disable(); + this.noSleepTimer = window.setInterval(function () { + window.location.href = '/'; + window.setTimeout(window.stop, 0); + }, 15000); + } else { + this.noSleepVideo.play(); + } + } + }, { + key: 'disable', + value: function disable() { + if (oldIOS) { + if (this.noSleepTimer) { + window.clearInterval(this.noSleepTimer); + this.noSleepTimer = null; + } + } else { + this.noSleepVideo.pause(); + } + } + }]); + return NoSleep; +}(); +module.exports = NoSleep; + }), + (function(module, exports, __webpack_require__) { +module.exports = 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA='; + }) + ]); +}); +}); +var NoSleep$1 = unwrapExports$$1(NoSleep); +var nextDisplayId = 1000; +var defaultLeftBounds = [0, 0, 0.5, 1]; +var defaultRightBounds = [0.5, 0, 0.5, 1]; +var raf = window.requestAnimationFrame; +var caf = window.cancelAnimationFrame; +function VRFrameData() { + this.leftProjectionMatrix = new Float32Array(16); + this.leftViewMatrix = new Float32Array(16); + this.rightProjectionMatrix = new Float32Array(16); + this.rightViewMatrix = new Float32Array(16); + this.pose = null; +} +function VRDisplayCapabilities(config) { + Object.defineProperties(this, { + hasPosition: { + writable: false, enumerable: true, value: config.hasPosition + }, + hasExternalDisplay: { + writable: false, enumerable: true, value: config.hasExternalDisplay + }, + canPresent: { + writable: false, enumerable: true, value: config.canPresent + }, + maxLayers: { + writable: false, enumerable: true, value: config.maxLayers + }, + hasOrientation: { + enumerable: true, get: function get() { + deprecateWarning('VRDisplayCapabilities.prototype.hasOrientation', 'VRDisplay.prototype.getFrameData'); + return config.hasOrientation; + } + } + }); +} +function VRDisplay(config) { + config = config || {}; + var USE_WAKELOCK = 'wakelock' in config ? config.wakelock : true; + this.isPolyfilled = true; + this.displayId = nextDisplayId++; + this.displayName = ''; + this.depthNear = 0.01; + this.depthFar = 10000.0; + this.isPresenting = false; + Object.defineProperty(this, 'isConnected', { + get: function get() { + deprecateWarning('VRDisplay.prototype.isConnected', 'VRDisplayCapabilities.prototype.hasExternalDisplay'); + return false; + } + }); + this.capabilities = new VRDisplayCapabilities({ + hasPosition: false, + hasOrientation: false, + hasExternalDisplay: false, + canPresent: false, + maxLayers: 1 + }); + this.stageParameters = null; + this.waitingForPresent_ = false; + this.layer_ = null; + this.originalParent_ = null; + this.fullscreenElement_ = null; + this.fullscreenWrapper_ = null; + this.fullscreenElementCachedStyle_ = null; + this.fullscreenEventTarget_ = null; + this.fullscreenChangeHandler_ = null; + this.fullscreenErrorHandler_ = null; + if (USE_WAKELOCK && isMobile()) { + this.wakelock_ = new NoSleep$1(); + } +} +VRDisplay.prototype.getFrameData = function (frameData) { + return frameDataFromPose(frameData, this._getPose(), this); +}; +VRDisplay.prototype.getPose = function () { + deprecateWarning('VRDisplay.prototype.getPose', 'VRDisplay.prototype.getFrameData'); + return this._getPose(); +}; +VRDisplay.prototype.resetPose = function () { + deprecateWarning('VRDisplay.prototype.resetPose'); + return this._resetPose(); +}; +VRDisplay.prototype.getImmediatePose = function () { + deprecateWarning('VRDisplay.prototype.getImmediatePose', 'VRDisplay.prototype.getFrameData'); + return this._getPose(); +}; +VRDisplay.prototype.requestAnimationFrame = function (callback) { + return raf(callback); +}; +VRDisplay.prototype.cancelAnimationFrame = function (id) { + return caf(id); +}; +VRDisplay.prototype.wrapForFullscreen = function (element) { + if (isIOS()) { + return element; + } + if (!this.fullscreenWrapper_) { + this.fullscreenWrapper_ = document.createElement('div'); + var cssProperties = ['height: ' + Math.min(screen.height, screen.width) + 'px !important', 'top: 0 !important', 'left: 0 !important', 'right: 0 !important', 'border: 0', 'margin: 0', 'padding: 0', 'z-index: 999999 !important', 'position: fixed']; + this.fullscreenWrapper_.setAttribute('style', cssProperties.join('; ') + ';'); + this.fullscreenWrapper_.classList.add('webvr-polyfill-fullscreen-wrapper'); + } + if (this.fullscreenElement_ == element) { + return this.fullscreenWrapper_; + } + if (this.fullscreenElement_) { + if (this.originalParent_) { + this.originalParent_.appendChild(this.fullscreenElement_); + } else { + this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_); + } + } + this.fullscreenElement_ = element; + this.originalParent_ = element.parentElement; + if (!this.originalParent_) { + document.body.appendChild(element); + } + if (!this.fullscreenWrapper_.parentElement) { + var parent = this.fullscreenElement_.parentElement; + parent.insertBefore(this.fullscreenWrapper_, this.fullscreenElement_); + parent.removeChild(this.fullscreenElement_); + } + this.fullscreenWrapper_.insertBefore(this.fullscreenElement_, this.fullscreenWrapper_.firstChild); + this.fullscreenElementCachedStyle_ = this.fullscreenElement_.getAttribute('style'); + var self = this; + function applyFullscreenElementStyle() { + if (!self.fullscreenElement_) { + return; + } + var cssProperties = ['position: absolute', 'top: 0', 'left: 0', 'width: ' + Math.max(screen.width, screen.height) + 'px', 'height: ' + Math.min(screen.height, screen.width) + 'px', 'border: 0', 'margin: 0', 'padding: 0']; + self.fullscreenElement_.setAttribute('style', cssProperties.join('; ') + ';'); + } + applyFullscreenElementStyle(); + return this.fullscreenWrapper_; +}; +VRDisplay.prototype.removeFullscreenWrapper = function () { + if (!this.fullscreenElement_) { + return; + } + var element = this.fullscreenElement_; + if (this.fullscreenElementCachedStyle_) { + element.setAttribute('style', this.fullscreenElementCachedStyle_); + } else { + element.removeAttribute('style'); + } + this.fullscreenElement_ = null; + this.fullscreenElementCachedStyle_ = null; + var parent = this.fullscreenWrapper_.parentElement; + this.fullscreenWrapper_.removeChild(element); + if (this.originalParent_ === parent) { + parent.insertBefore(element, this.fullscreenWrapper_); + } + else if (this.originalParent_) { + this.originalParent_.appendChild(element); + } + parent.removeChild(this.fullscreenWrapper_); + return element; +}; +VRDisplay.prototype.requestPresent = function (layers) { + var wasPresenting = this.isPresenting; + var self = this; + if (!(layers instanceof Array)) { + deprecateWarning('VRDisplay.prototype.requestPresent with non-array argument', 'an array of VRLayers as the first argument'); + layers = [layers]; + } + return new Promise(function (resolve, reject) { + if (!self.capabilities.canPresent) { + reject(new Error('VRDisplay is not capable of presenting.')); + return; + } + if (layers.length == 0 || layers.length > self.capabilities.maxLayers) { + reject(new Error('Invalid number of layers.')); + return; + } + var incomingLayer = layers[0]; + if (!incomingLayer.source) { + resolve(); + return; + } + var leftBounds = incomingLayer.leftBounds || defaultLeftBounds; + var rightBounds = incomingLayer.rightBounds || defaultRightBounds; + if (wasPresenting) { + var layer = self.layer_; + if (layer.source !== incomingLayer.source) { + layer.source = incomingLayer.source; + } + for (var i = 0; i < 4; i++) { + layer.leftBounds[i] = leftBounds[i]; + layer.rightBounds[i] = rightBounds[i]; + } + self.wrapForFullscreen(self.layer_.source); + self.updatePresent_(); + resolve(); + return; + } + self.layer_ = { + predistorted: incomingLayer.predistorted, + source: incomingLayer.source, + leftBounds: leftBounds.slice(0), + rightBounds: rightBounds.slice(0) + }; + self.waitingForPresent_ = false; + if (self.layer_ && self.layer_.source) { + var fullscreenElement = self.wrapForFullscreen(self.layer_.source); + var onFullscreenChange = function onFullscreenChange() { + var actualFullscreenElement = getFullscreenElement(); + self.isPresenting = fullscreenElement === actualFullscreenElement; + if (self.isPresenting) { + if (screen.orientation && screen.orientation.lock) { + screen.orientation.lock('landscape-primary').catch(function (error) { + console.error('screen.orientation.lock() failed due to', error.message); + }); + } + self.waitingForPresent_ = false; + self.beginPresent_(); + resolve(); + } else { + if (screen.orientation && screen.orientation.unlock) { + screen.orientation.unlock(); + } + self.removeFullscreenWrapper(); + self.disableWakeLock(); + self.endPresent_(); + self.removeFullscreenListeners_(); + } + self.fireVRDisplayPresentChange_(); + }; + var onFullscreenError = function onFullscreenError() { + if (!self.waitingForPresent_) { + return; + } + self.removeFullscreenWrapper(); + self.removeFullscreenListeners_(); + self.disableWakeLock(); + self.waitingForPresent_ = false; + self.isPresenting = false; + reject(new Error('Unable to present.')); + }; + self.addFullscreenListeners_(fullscreenElement, onFullscreenChange, onFullscreenError); + if (requestFullscreen(fullscreenElement)) { + self.enableWakeLock(); + self.waitingForPresent_ = true; + } else if (isIOS() || isWebViewAndroid()) { + self.enableWakeLock(); + self.isPresenting = true; + self.beginPresent_(); + self.fireVRDisplayPresentChange_(); + resolve(); + } + } + if (!self.waitingForPresent_ && !isIOS()) { + exitFullscreen(); + reject(new Error('Unable to present.')); + } + }); +}; +VRDisplay.prototype.exitPresent = function () { + var wasPresenting = this.isPresenting; + var self = this; + this.isPresenting = false; + this.layer_ = null; + this.disableWakeLock(); + return new Promise(function (resolve, reject) { + if (wasPresenting) { + if (!exitFullscreen() && isIOS()) { + self.endPresent_(); + self.fireVRDisplayPresentChange_(); + } + if (isWebViewAndroid()) { + self.removeFullscreenWrapper(); + self.removeFullscreenListeners_(); + self.endPresent_(); + self.fireVRDisplayPresentChange_(); + } + resolve(); + } else { + reject(new Error('Was not presenting to VRDisplay.')); + } + }); +}; +VRDisplay.prototype.getLayers = function () { + if (this.layer_) { + return [this.layer_]; + } + return []; +}; +VRDisplay.prototype.fireVRDisplayPresentChange_ = function () { + var event = new CustomEvent('vrdisplaypresentchange', { detail: { display: this } }); + window.dispatchEvent(event); +}; +VRDisplay.prototype.fireVRDisplayConnect_ = function () { + var event = new CustomEvent('vrdisplayconnect', { detail: { display: this } }); + window.dispatchEvent(event); +}; +VRDisplay.prototype.addFullscreenListeners_ = function (element, changeHandler, errorHandler) { + this.removeFullscreenListeners_(); + this.fullscreenEventTarget_ = element; + this.fullscreenChangeHandler_ = changeHandler; + this.fullscreenErrorHandler_ = errorHandler; + if (changeHandler) { + if (document.fullscreenEnabled) { + element.addEventListener('fullscreenchange', changeHandler, false); + } else if (document.webkitFullscreenEnabled) { + element.addEventListener('webkitfullscreenchange', changeHandler, false); + } else if (document.mozFullScreenEnabled) { + document.addEventListener('mozfullscreenchange', changeHandler, false); + } else if (document.msFullscreenEnabled) { + element.addEventListener('msfullscreenchange', changeHandler, false); + } + } + if (errorHandler) { + if (document.fullscreenEnabled) { + element.addEventListener('fullscreenerror', errorHandler, false); + } else if (document.webkitFullscreenEnabled) { + element.addEventListener('webkitfullscreenerror', errorHandler, false); + } else if (document.mozFullScreenEnabled) { + document.addEventListener('mozfullscreenerror', errorHandler, false); + } else if (document.msFullscreenEnabled) { + element.addEventListener('msfullscreenerror', errorHandler, false); + } + } +}; +VRDisplay.prototype.removeFullscreenListeners_ = function () { + if (!this.fullscreenEventTarget_) return; + var element = this.fullscreenEventTarget_; + if (this.fullscreenChangeHandler_) { + var changeHandler = this.fullscreenChangeHandler_; + element.removeEventListener('fullscreenchange', changeHandler, false); + element.removeEventListener('webkitfullscreenchange', changeHandler, false); + document.removeEventListener('mozfullscreenchange', changeHandler, false); + element.removeEventListener('msfullscreenchange', changeHandler, false); + } + if (this.fullscreenErrorHandler_) { + var errorHandler = this.fullscreenErrorHandler_; + element.removeEventListener('fullscreenerror', errorHandler, false); + element.removeEventListener('webkitfullscreenerror', errorHandler, false); + document.removeEventListener('mozfullscreenerror', errorHandler, false); + element.removeEventListener('msfullscreenerror', errorHandler, false); + } + this.fullscreenEventTarget_ = null; + this.fullscreenChangeHandler_ = null; + this.fullscreenErrorHandler_ = null; +}; +VRDisplay.prototype.enableWakeLock = function () { + if (this.wakelock_) { + this.wakelock_.enable(); + } +}; +VRDisplay.prototype.disableWakeLock = function () { + if (this.wakelock_) { + this.wakelock_.disable(); + } +}; +VRDisplay.prototype.beginPresent_ = function () { +}; +VRDisplay.prototype.endPresent_ = function () { +}; +VRDisplay.prototype.submitFrame = function (pose) { +}; +VRDisplay.prototype.getEyeParameters = function (whichEye) { + return null; +}; +var config = { + ADDITIONAL_VIEWERS: [], + DEFAULT_VIEWER: '', + MOBILE_WAKE_LOCK: true, + DEBUG: false, + DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json', + K_FILTER: 0.98, + PREDICTION_TIME_S: 0.040, + CARDBOARD_UI_DISABLED: false, + ROTATE_INSTRUCTIONS_DISABLED: false, + YAW_ONLY: false, + BUFFER_SCALE: 0.5, + DIRTY_SUBMIT_FRAME_BINDINGS: false +}; +var Eye = { + LEFT: 'left', + RIGHT: 'right' +}; +function CardboardVRDisplay(config$$1) { + var defaults = extend({}, config); + config$$1 = extend(defaults, config$$1 || {}); + VRDisplay.call(this, { + wakelock: config$$1.MOBILE_WAKE_LOCK + }); + this.config = config$$1; + this.displayName = 'Cardboard VRDisplay'; + this.capabilities = new VRDisplayCapabilities({ + hasPosition: false, + hasOrientation: true, + hasExternalDisplay: false, + canPresent: true, + maxLayers: 1 + }); + this.stageParameters = null; + this.bufferScale_ = this.config.BUFFER_SCALE; + this.poseSensor_ = new PoseSensor(this.config); + this.distorter_ = null; + this.cardboardUI_ = null; + this.dpdb_ = new Dpdb(this.config.DPDB_URL, this.onDeviceParamsUpdated_.bind(this)); + this.deviceInfo_ = new DeviceInfo(this.dpdb_.getDeviceParams(), config$$1.ADDITIONAL_VIEWERS); + this.viewerSelector_ = new ViewerSelector(config$$1.DEFAULT_VIEWER); + this.viewerSelector_.onChange(this.onViewerChanged_.bind(this)); + this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer()); + if (!this.config.ROTATE_INSTRUCTIONS_DISABLED) { + this.rotateInstructions_ = new RotateInstructions(); + } + if (isIOS()) { + window.addEventListener('resize', this.onResize_.bind(this)); + } +} +CardboardVRDisplay.prototype = Object.create(VRDisplay.prototype); +CardboardVRDisplay.prototype._getPose = function () { + return { + position: null, + orientation: this.poseSensor_.getOrientation(), + linearVelocity: null, + linearAcceleration: null, + angularVelocity: null, + angularAcceleration: null + }; +}; +CardboardVRDisplay.prototype._resetPose = function () { + if (this.poseSensor_.resetPose) { + this.poseSensor_.resetPose(); + } +}; +CardboardVRDisplay.prototype._getFieldOfView = function (whichEye) { + var fieldOfView; + if (whichEye == Eye.LEFT) { + fieldOfView = this.deviceInfo_.getFieldOfViewLeftEye(); + } else if (whichEye == Eye.RIGHT) { + fieldOfView = this.deviceInfo_.getFieldOfViewRightEye(); + } else { + console.error('Invalid eye provided: %s', whichEye); + return null; + } + return fieldOfView; +}; +CardboardVRDisplay.prototype._getEyeOffset = function (whichEye) { + var offset; + if (whichEye == Eye.LEFT) { + offset = [-this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0]; + } else if (whichEye == Eye.RIGHT) { + offset = [this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0]; + } else { + console.error('Invalid eye provided: %s', whichEye); + return null; + } + return offset; +}; +CardboardVRDisplay.prototype.getEyeParameters = function (whichEye) { + var offset = this._getEyeOffset(whichEye); + var fieldOfView = this._getFieldOfView(whichEye); + var eyeParams = { + offset: offset, + renderWidth: this.deviceInfo_.device.width * 0.5 * this.bufferScale_, + renderHeight: this.deviceInfo_.device.height * this.bufferScale_ + }; + Object.defineProperty(eyeParams, 'fieldOfView', { + enumerable: true, + get: function get() { + deprecateWarning('VRFieldOfView', 'VRFrameData\'s projection matrices'); + return fieldOfView; + } + }); + return eyeParams; +}; +CardboardVRDisplay.prototype.onDeviceParamsUpdated_ = function (newParams) { + if (this.config.DEBUG) { + console.log('DPDB reported that device params were updated.'); + } + this.deviceInfo_.updateDeviceParams(newParams); + if (this.distorter_) { + this.distorter_.updateDeviceInfo(this.deviceInfo_); + } +}; +CardboardVRDisplay.prototype.updateBounds_ = function () { + if (this.layer_ && this.distorter_ && (this.layer_.leftBounds || this.layer_.rightBounds)) { + this.distorter_.setTextureBounds(this.layer_.leftBounds, this.layer_.rightBounds); + } +}; +CardboardVRDisplay.prototype.beginPresent_ = function () { + var gl = this.layer_.source.getContext('webgl'); + if (!gl) gl = this.layer_.source.getContext('experimental-webgl'); + if (!gl) gl = this.layer_.source.getContext('webgl2'); + if (!gl) return; + if (this.layer_.predistorted) { + if (!this.config.CARDBOARD_UI_DISABLED) { + gl.canvas.width = getScreenWidth() * this.bufferScale_; + gl.canvas.height = getScreenHeight() * this.bufferScale_; + this.cardboardUI_ = new CardboardUI(gl); + } + } else { + if (!this.config.CARDBOARD_UI_DISABLED) { + this.cardboardUI_ = new CardboardUI(gl); + } + this.distorter_ = new CardboardDistorter(gl, this.cardboardUI_, this.config.BUFFER_SCALE, this.config.DIRTY_SUBMIT_FRAME_BINDINGS); + this.distorter_.updateDeviceInfo(this.deviceInfo_); + } + if (this.cardboardUI_) { + this.cardboardUI_.listen(function (e) { + this.viewerSelector_.show(this.layer_.source.parentElement); + e.stopPropagation(); + e.preventDefault(); + }.bind(this), function (e) { + this.exitPresent(); + e.stopPropagation(); + e.preventDefault(); + }.bind(this)); + } + if (this.rotateInstructions_) { + if (isLandscapeMode() && isMobile()) { + this.rotateInstructions_.showTemporarily(3000, this.layer_.source.parentElement); + } else { + this.rotateInstructions_.update(); + } + } + this.orientationHandler = this.onOrientationChange_.bind(this); + window.addEventListener('orientationchange', this.orientationHandler); + this.vrdisplaypresentchangeHandler = this.updateBounds_.bind(this); + window.addEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler); + this.fireVRDisplayDeviceParamsChange_(); +}; +CardboardVRDisplay.prototype.endPresent_ = function () { + if (this.distorter_) { + this.distorter_.destroy(); + this.distorter_ = null; + } + if (this.cardboardUI_) { + this.cardboardUI_.destroy(); + this.cardboardUI_ = null; + } + if (this.rotateInstructions_) { + this.rotateInstructions_.hide(); + } + this.viewerSelector_.hide(); + window.removeEventListener('orientationchange', this.orientationHandler); + window.removeEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler); +}; +CardboardVRDisplay.prototype.updatePresent_ = function () { + this.endPresent_(); + this.beginPresent_(); +}; +CardboardVRDisplay.prototype.submitFrame = function (pose) { + if (this.distorter_) { + this.updateBounds_(); + this.distorter_.submitFrame(); + } else if (this.cardboardUI_ && this.layer_) { + var canvas = this.layer_.source.getContext('webgl').canvas; + if (canvas.width != this.lastWidth || canvas.height != this.lastHeight) { + this.cardboardUI_.onResize(); + } + this.lastWidth = canvas.width; + this.lastHeight = canvas.height; + this.cardboardUI_.render(); + } +}; +CardboardVRDisplay.prototype.onOrientationChange_ = function (e) { + this.viewerSelector_.hide(); + if (this.rotateInstructions_) { + this.rotateInstructions_.update(); + } + this.onResize_(); +}; +CardboardVRDisplay.prototype.onResize_ = function (e) { + if (this.layer_) { + var gl = this.layer_.source.getContext('webgl'); + var cssProperties = ['position: absolute', 'top: 0', 'left: 0', + 'width: 100vw', 'height: 100vh', 'border: 0', 'margin: 0', + 'padding: 0px', 'box-sizing: content-box']; + gl.canvas.setAttribute('style', cssProperties.join('; ') + ';'); + safariCssSizeWorkaround(gl.canvas); + } +}; +CardboardVRDisplay.prototype.onViewerChanged_ = function (viewer) { + this.deviceInfo_.setViewer(viewer); + if (this.distorter_) { + this.distorter_.updateDeviceInfo(this.deviceInfo_); + } + this.fireVRDisplayDeviceParamsChange_(); +}; +CardboardVRDisplay.prototype.fireVRDisplayDeviceParamsChange_ = function () { + var event = new CustomEvent('vrdisplaydeviceparamschange', { + detail: { + vrdisplay: this, + deviceInfo: this.deviceInfo_ + } + }); + window.dispatchEvent(event); +}; +CardboardVRDisplay.VRFrameData = VRFrameData; +CardboardVRDisplay.VRDisplay = VRDisplay; +return CardboardVRDisplay; +}))); +}); +var CardboardVRDisplay = unwrapExports(cardboardVrDisplay); + +class XRDevice extends EventTarget { + constructor(global) { + super(); + this.global = global; + this.onWindowResize = this.onWindowResize.bind(this); + this.global.window.addEventListener('resize', this.onWindowResize); + this.environmentBlendMode = 'opaque'; + } + onBaseLayerSet(sessionId, layer) { throw new Error('Not implemented'); } + isSessionSupported(mode) { throw new Error('Not implemented'); } + isFeatureSupported(featureDescriptor) { throw new Error('Not implemented'); } + async requestSession(mode, enabledFeatures) { throw new Error('Not implemented'); } + requestAnimationFrame(callback) { throw new Error('Not implemented'); } + onFrameStart(sessionId) { throw new Error('Not implemented'); } + onFrameEnd(sessionId) { throw new Error('Not implemented'); } + doesSessionSupportReferenceSpace(sessionId, type) { throw new Error('Not implemented'); } + requestStageBounds() { throw new Error('Not implemented'); } + async requestFrameOfReferenceTransform(type, options) { + return undefined; + } + cancelAnimationFrame(handle) { throw new Error('Not implemented'); } + endSession(sessionId) { throw new Error('Not implemented'); } + getViewport(sessionId, eye, layer, target) { throw new Error('Not implemented'); } + getProjectionMatrix(eye) { throw new Error('Not implemented'); } + getBasePoseMatrix() { throw new Error('Not implemented'); } + getBaseViewMatrix(eye) { throw new Error('Not implemented'); } + getInputSources() { throw new Error('Not implemented'); } + getInputPose(inputSource, coordinateSystem, poseType) { throw new Error('Not implemented'); } + onWindowResize() { + this.onWindowResize(); + } +} + +let daydream = { + mapping: '', + profiles: ['google-daydream', 'generic-trigger-touchpad'], + buttons: { + length: 3, + 0: null, + 1: null, + 2: 0 + }, +}; +let viveFocus = { + mapping: 'xr-standard', + profiles: ['htc-vive-focus', 'generic-trigger-touchpad'], + buttons: { + length: 3, + 0: 1, + 1: null, + 2: 0 + }, +}; +let oculusGo = { + mapping: 'xr-standard', + profiles: ['oculus-go', 'generic-trigger-touchpad'], + buttons: { + length: 3, + 0: 1, + 1: null, + 2: 0 + }, + gripTransform: { + orientation: [Math.PI * 0.11, 0, 0, 1] + } +}; +let oculusTouch = { + mapping: 'xr-standard', + displayProfiles: { + 'Oculus Quest': ['oculus-touch-v2', 'oculus-touch', 'generic-trigger-squeeze-thumbstick'] + }, + profiles: ['oculus-touch', 'generic-trigger-squeeze-thumbstick'], + axes: { + length: 4, + 0: null, + 1: null, + 2: 0, + 3: 1 + }, + buttons: { + length: 7, + 0: 1, + 1: 2, + 2: null, + 3: 0, + 4: 3, + 5: 4, + 6: null + }, + gripTransform: { + position: [0, -0.02, 0.04, 1], + orientation: [Math.PI * 0.11, 0, 0, 1] + } +}; +let openVr = { + mapping: 'xr-standard', + profiles: ['htc-vive', 'generic-trigger-squeeze-touchpad'], + displayProfiles: { + 'HTC Vive': ['htc-vive', 'generic-trigger-squeeze-touchpad'], + 'HTC Vive DVT': ['htc-vive', 'generic-trigger-squeeze-touchpad'], + 'Valve Index': ['valve-index', 'generic-trigger-squeeze-touchpad-thumbstick'] + }, + buttons: { + length: 3, + 0: 1, + 1: 2, + 2: 0 + }, + gripTransform: { + position: [0, 0, 0.05, 1], + }, + targetRayTransform: { + orientation: [Math.PI * -0.08, 0, 0, 1] + }, + userAgentOverrides: { + "Firefox": { + axes: { + invert: [1, 3] + } + } + } +}; +let samsungGearVR = { + mapping: 'xr-standard', + profiles: ['samsung-gearvr', 'generic-trigger-touchpad'], + buttons: { + length: 3, + 0: 1, + 1: null, + 2: 0 + }, + gripTransform: { + orientation: [Math.PI * 0.11, 0, 0, 1] + } +}; +let samsungOdyssey = { + mapping: 'xr-standard', + profiles: ['samsung-odyssey', 'microsoft-mixed-reality', 'generic-trigger-squeeze-touchpad-thumbstick'], + buttons: { + length: 4, + 0: 1, + 1: 0, + 2: 2, + 3: 4, + }, + gripTransform: { + position: [0, -0.02, 0.04, 1], + orientation: [Math.PI * 0.11, 0, 0, 1] + } +}; +let windowsMixedReality = { + mapping: 'xr-standard', + profiles: ['microsoft-mixed-reality', 'generic-trigger-squeeze-touchpad-thumbstick'], + buttons: { + length: 4, + 0: 1, + 1: 0, + 2: 2, + 3: 4, + }, + gripTransform: { + position: [0, -0.02, 0.04, 1], + orientation: [Math.PI * 0.11, 0, 0, 1] + } +}; +let GamepadMappings = { + 'Daydream Controller': daydream, + 'Gear VR Controller': samsungGearVR, + 'HTC Vive Focus Controller': viveFocus, + 'Oculus Go Controller': oculusGo, + 'Oculus Touch (Right)': oculusTouch, + 'Oculus Touch (Left)': oculusTouch, + 'OpenVR Gamepad': openVr, + 'Spatial Controller (Spatial Interaction Source) 045E-065A': windowsMixedReality, + 'Spatial Controller (Spatial Interaction Source) 045E-065D': samsungOdyssey, + 'Windows Mixed Reality (Right)': windowsMixedReality, + 'Windows Mixed Reality (Left)': windowsMixedReality, +}; + +const HEAD_ELBOW_OFFSET_RIGHTHANDED = fromValues$1(0.155, -0.465, -0.15); +const HEAD_ELBOW_OFFSET_LEFTHANDED = fromValues$1(-0.155, -0.465, -0.15); +const ELBOW_WRIST_OFFSET = fromValues$1(0, 0, -0.25); +const WRIST_CONTROLLER_OFFSET = fromValues$1(0, 0, 0.05); +const ARM_EXTENSION_OFFSET = fromValues$1(-0.08, 0.14, 0.08); +const ELBOW_BEND_RATIO = 0.4; +const EXTENSION_RATIO_WEIGHT = 0.4; +const MIN_ANGULAR_SPEED = 0.61; +const MIN_ANGLE_DELTA = 0.175; +const MIN_EXTENSION_COS = 0.12; +const MAX_EXTENSION_COS = 0.87; +const RAD_TO_DEG = 180 / Math.PI; +function eulerFromQuaternion(out, q, order) { + function clamp(value, min$$1, max$$1) { + return (value < min$$1 ? min$$1 : (value > max$$1 ? max$$1 : value)); + } + var sqx = q[0] * q[0]; + var sqy = q[1] * q[1]; + var sqz = q[2] * q[2]; + var sqw = q[3] * q[3]; + if ( order === 'XYZ' ) { + out[0] = Math.atan2( 2 * ( q[0] * q[3] - q[1] * q[2] ), ( sqw - sqx - sqy + sqz ) ); + out[1] = Math.asin( clamp( 2 * ( q[0] * q[2] + q[1] * q[3] ), -1, 1 ) ); + out[2] = Math.atan2( 2 * ( q[2] * q[3] - q[0] * q[1] ), ( sqw + sqx - sqy - sqz ) ); + } else if ( order === 'YXZ' ) { + out[0] = Math.asin( clamp( 2 * ( q[0] * q[3] - q[1] * q[2] ), -1, 1 ) ); + out[1] = Math.atan2( 2 * ( q[0] * q[2] + q[1] * q[3] ), ( sqw - sqx - sqy + sqz ) ); + out[2] = Math.atan2( 2 * ( q[0] * q[1] + q[2] * q[3] ), ( sqw - sqx + sqy - sqz ) ); + } else if ( order === 'ZXY' ) { + out[0] = Math.asin( clamp( 2 * ( q[0] * q[3] + q[1] * q[2] ), -1, 1 ) ); + out[1] = Math.atan2( 2 * ( q[1] * q[3] - q[2] * q[0] ), ( sqw - sqx - sqy + sqz ) ); + out[2] = Math.atan2( 2 * ( q[2] * q[3] - q[0] * q[1] ), ( sqw - sqx + sqy - sqz ) ); + } else if ( order === 'ZYX' ) { + out[0] = Math.atan2( 2 * ( q[0] * q[3] + q[2] * q[1] ), ( sqw - sqx - sqy + sqz ) ); + out[1] = Math.asin( clamp( 2 * ( q[1] * q[3] - q[0] * q[2] ), -1, 1 ) ); + out[2] = Math.atan2( 2 * ( q[0] * q[1] + q[2] * q[3] ), ( sqw + sqx - sqy - sqz ) ); + } else if ( order === 'YZX' ) { + out[0] = Math.atan2( 2 * ( q[0] * q[3] - q[2] * q[1] ), ( sqw - sqx + sqy - sqz ) ); + out[1] = Math.atan2( 2 * ( q[1] * q[3] - q[0] * q[2] ), ( sqw + sqx - sqy - sqz ) ); + out[2] = Math.asin( clamp( 2 * ( q[0] * q[1] + q[2] * q[3] ), -1, 1 ) ); + } else if ( order === 'XZY' ) { + out[0] = Math.atan2( 2 * ( q[0] * q[3] + q[1] * q[2] ), ( sqw - sqx + sqy - sqz ) ); + out[1] = Math.atan2( 2 * ( q[0] * q[2] + q[1] * q[3] ), ( sqw + sqx - sqy - sqz ) ); + out[2] = Math.asin( clamp( 2 * ( q[2] * q[3] - q[0] * q[1] ), -1, 1 ) ); + } else { + console.log('No order given for quaternion to euler conversion.'); + return; + } +} +class OrientationArmModel { + constructor() { + this.hand = 'right'; + this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED; + this.controllerQ = create$4(); + this.lastControllerQ = create$4(); + this.headQ = create$4(); + this.headPos = create$1(); + this.elbowPos = create$1(); + this.wristPos = create$1(); + this.time = null; + this.lastTime = null; + this.rootQ = create$4(); + this.position = create$1(); + } + setHandedness(hand) { + if (this.hand != hand) { + this.hand = hand; + if (this.hand == 'left') { + this.headElbowOffset = HEAD_ELBOW_OFFSET_LEFTHANDED; + } else { + this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED; + } + } + } + update(controllerOrientation, headPoseMatrix) { + this.time = now$1(); + if (controllerOrientation) { + copy$4(this.lastControllerQ, this.controllerQ); + copy$4(this.controllerQ, controllerOrientation); + } + if (headPoseMatrix) { + getTranslation(this.headPos, headPoseMatrix); + getRotation(this.headQ, headPoseMatrix); + } + let headYawQ = this.getHeadYawOrientation_(); + let angleDelta = this.quatAngle_(this.lastControllerQ, this.controllerQ); + let timeDelta = (this.time - this.lastTime) / 1000; + let controllerAngularSpeed = angleDelta / timeDelta; + if (controllerAngularSpeed > MIN_ANGULAR_SPEED) { + slerp(this.rootQ, this.rootQ, headYawQ, + Math.min(angleDelta / MIN_ANGLE_DELTA, 1.0)); + } else { + copy$4(this.rootQ, headYawQ); + } + let controllerForward = fromValues$1(0, 0, -1.0); + transformQuat(controllerForward, controllerForward, this.controllerQ); + let controllerDotY = dot(controllerForward, [0, 1, 0]); + let extensionRatio = this.clamp_( + (controllerDotY - MIN_EXTENSION_COS) / MAX_EXTENSION_COS, 0.0, 1.0); + let controllerCameraQ = clone$4(this.rootQ); + invert$2(controllerCameraQ, controllerCameraQ); + multiply$4(controllerCameraQ, controllerCameraQ, this.controllerQ); + let elbowPos = this.elbowPos; + copy$1(elbowPos, this.headPos); + add$1(elbowPos, elbowPos, this.headElbowOffset); + let elbowOffset = clone$1(ARM_EXTENSION_OFFSET); + scale$1(elbowOffset, elbowOffset, extensionRatio); + add$1(elbowPos, elbowPos, elbowOffset); + let totalAngle = this.quatAngle_(controllerCameraQ, create$4()); + let totalAngleDeg = totalAngle * RAD_TO_DEG; + let lerpSuppression = 1 - Math.pow(totalAngleDeg / 180, 4);let elbowRatio = ELBOW_BEND_RATIO; + let wristRatio = 1 - ELBOW_BEND_RATIO; + let lerpValue = lerpSuppression * + (elbowRatio + wristRatio * extensionRatio * EXTENSION_RATIO_WEIGHT); + let wristQ = create$4(); + slerp(wristQ, wristQ, controllerCameraQ, lerpValue); + let invWristQ = invert$2(create$4(), wristQ); + let elbowQ = clone$4(controllerCameraQ); + multiply$4(elbowQ, elbowQ, invWristQ); + let wristPos = this.wristPos; + copy$1(wristPos, WRIST_CONTROLLER_OFFSET); + transformQuat(wristPos, wristPos, wristQ); + add$1(wristPos, wristPos, ELBOW_WRIST_OFFSET); + transformQuat(wristPos, wristPos, elbowQ); + add$1(wristPos, wristPos, elbowPos); + let offset = clone$1(ARM_EXTENSION_OFFSET); + scale$1(offset, offset, extensionRatio); + add$1(this.position, this.wristPos, offset); + transformQuat(this.position, this.position, this.rootQ); + this.lastTime = this.time; + } + getPosition() { + return this.position; + } + getHeadYawOrientation_() { + let headEuler = create$1(); + eulerFromQuaternion(headEuler, this.headQ, 'YXZ'); + let destinationQ = fromEuler(create$4(), 0, headEuler[1] * RAD_TO_DEG, 0); + return destinationQ; + } + clamp_(value, min$$1, max$$1) { + return Math.min(Math.max(value, min$$1), max$$1); + } + quatAngle_(q1, q2) { + let vec1 = [0, 0, -1]; + let vec2 = [0, 0, -1]; + transformQuat(vec1, vec1, q1); + transformQuat(vec2, vec2, q2); + return angle(vec1, vec2); + } +} + +const PRIVATE$18 = Symbol('@@webxr-polyfill/XRRemappedGamepad'); +const PLACEHOLDER_BUTTON = { pressed: false, touched: false, value: 0.0 }; +Object.freeze(PLACEHOLDER_BUTTON); +class XRRemappedGamepad { + constructor(gamepad, display, map) { + if (!map) { + map = {}; + } + if (map.userAgentOverrides) { + for (let agent in map.userAgentOverrides) { + if (navigator.userAgent.includes(agent)) { + let override = map.userAgentOverrides[agent]; + for (let key in override) { + if (key in map) { + Object.assign(map[key], override[key]); + } else { + map[key] = override[key]; + } + } + break; + } + } + } + let axes = new Array(map.axes && map.axes.length ? map.axes.length : gamepad.axes.length); + let buttons = new Array(map.buttons && map.buttons.length ? map.buttons.length : gamepad.buttons.length); + let gripTransform = null; + if (map.gripTransform) { + let orientation = map.gripTransform.orientation || [0, 0, 0, 1]; + gripTransform = create(); + fromRotationTranslation( + gripTransform, + normalize$2(orientation, orientation), + map.gripTransform.position || [0, 0, 0] + ); + } + let targetRayTransform = null; + if (map.targetRayTransform) { + let orientation = map.targetRayTransform.orientation || [0, 0, 0, 1]; + targetRayTransform = create(); + fromRotationTranslation( + targetRayTransform, + normalize$2(orientation, orientation), + map.targetRayTransform.position || [0, 0, 0] + ); + } + let profiles = map.profiles; + if (map.displayProfiles) { + if (display.displayName in map.displayProfiles) { + profiles = map.displayProfiles[display.displayName]; + } + } + this[PRIVATE$18] = { + gamepad, + map, + profiles: profiles || [gamepad.id], + mapping: map.mapping || gamepad.mapping, + axes, + buttons, + gripTransform, + targetRayTransform, + }; + this._update(); + } + _update() { + let gamepad = this[PRIVATE$18].gamepad; + let map = this[PRIVATE$18].map; + let axes = this[PRIVATE$18].axes; + for (let i = 0; i < axes.length; ++i) { + if (map.axes && i in map.axes) { + if (map.axes[i] === null) { + axes[i] = 0; + } else { + axes[i] = gamepad.axes[map.axes[i]]; + } + } else { + axes[i] = gamepad.axes[i]; + } + } + if (map.axes && map.axes.invert) { + for (let axis of map.axes.invert) { + if (axis < axes.length) { + axes[axis] *= -1; + } + } + } + let buttons = this[PRIVATE$18].buttons; + for (let i = 0; i < buttons.length; ++i) { + if (map.buttons && i in map.buttons) { + if (map.buttons[i] === null) { + buttons[i] = PLACEHOLDER_BUTTON; + } else { + buttons[i] = gamepad.buttons[map.buttons[i]]; + } + } else { + buttons[i] = gamepad.buttons[i]; + } + } + } + get id() { + return ''; + } + get _profiles() { + return this[PRIVATE$18].profiles; + } + get index() { + return -1; + } + get connected() { + return this[PRIVATE$18].gamepad.connected; + } + get timestamp() { + return this[PRIVATE$18].gamepad.timestamp; + } + get mapping() { + return this[PRIVATE$18].mapping; + } + get axes() { + return this[PRIVATE$18].axes; + } + get buttons() { + return this[PRIVATE$18].buttons; + } + get hapticActuators() { + return this[PRIVATE$18].gamepad.hapticActuators; + } +} +class GamepadXRInputSource { + constructor(polyfill, display, primaryButtonIndex = 0, primarySqueezeButtonIndex = -1) { + this.polyfill = polyfill; + this.display = display; + this.nativeGamepad = null; + this.gamepad = null; + this.inputSource = new XRInputSource(this); + this.lastPosition = create$1(); + this.emulatedPosition = false; + this.basePoseMatrix = create(); + this.outputMatrix = create(); + this.primaryButtonIndex = primaryButtonIndex; + this.primaryActionPressed = false; + this.primarySqueezeButtonIndex = primarySqueezeButtonIndex; + this.primarySqueezeActionPressed = false; + this.handedness = ''; + this.targetRayMode = 'gaze'; + this.armModel = null; + } + get profiles() { + return this.gamepad ? this.gamepad._profiles : []; + } + updateFromGamepad(gamepad) { + if (this.nativeGamepad !== gamepad) { + this.nativeGamepad = gamepad; + if (gamepad) { + this.gamepad = new XRRemappedGamepad(gamepad, this.display, GamepadMappings[gamepad.id]); + } else { + this.gamepad = null; + } + } + this.handedness = gamepad.hand === '' ? 'none' : gamepad.hand; + if (this.gamepad) { + this.gamepad._update(); + } + if (gamepad.pose) { + this.targetRayMode = 'tracked-pointer'; + this.emulatedPosition = !gamepad.pose.hasPosition; + } else if (gamepad.hand === '') { + this.targetRayMode = 'gaze'; + this.emulatedPosition = false; + } + } + updateBasePoseMatrix() { + if (this.nativeGamepad && this.nativeGamepad.pose) { + let pose = this.nativeGamepad.pose; + let position = pose.position; + let orientation = pose.orientation; + if (!position && !orientation) { + return; + } + if (!position) { + if (!pose.hasPosition) { + if (!this.armModel) { + this.armModel = new OrientationArmModel(); + } + this.armModel.setHandedness(this.nativeGamepad.hand); + this.armModel.update(orientation, this.polyfill.getBasePoseMatrix()); + position = this.armModel.getPosition(); + } else { + position = this.lastPosition; + } + } else { + this.lastPosition[0] = position[0]; + this.lastPosition[1] = position[1]; + this.lastPosition[2] = position[2]; + } + fromRotationTranslation(this.basePoseMatrix, orientation, position); + } else { + copy(this.basePoseMatrix, this.polyfill.getBasePoseMatrix()); + } + return this.basePoseMatrix; + } + getXRPose(coordinateSystem, poseType) { + this.updateBasePoseMatrix(); + switch(poseType) { + case "target-ray": + coordinateSystem._transformBasePoseMatrix(this.outputMatrix, this.basePoseMatrix); + if (this.gamepad && this.gamepad[PRIVATE$18].targetRayTransform) { + multiply(this.outputMatrix, this.outputMatrix, this.gamepad[PRIVATE$18].targetRayTransform); + } + break; + case "grip": + if (!this.nativeGamepad || !this.nativeGamepad.pose) { + return null; + } + coordinateSystem._transformBasePoseMatrix(this.outputMatrix, this.basePoseMatrix); + if (this.gamepad && this.gamepad[PRIVATE$18].gripTransform) { + multiply(this.outputMatrix, this.outputMatrix, this.gamepad[PRIVATE$18].gripTransform); + } + break; + default: + return null; + } + coordinateSystem._adjustForOriginOffset(this.outputMatrix); + return new XRPose(new XRRigidTransform(this.outputMatrix), this.emulatedPosition); + } +} + +const TEST_ENV = "production" === 'test'; +const EXTRA_PRESENTATION_ATTRIBUTES = { + highRefreshRate: true, +}; +const PRIMARY_BUTTON_MAP = { + oculus: 1, + openvr: 1, + 'spatial controller (spatial interaction source)': 1 +}; +let SESSION_ID = 0; +class Session { + constructor(mode, enabledFeatures, polyfillOptions={}) { + this.mode = mode; + this.enabledFeatures = enabledFeatures; + this.outputContext = null; + this.immersive = mode == 'immersive-vr' || mode == 'immersive-ar'; + this.ended = null; + this.baseLayer = null; + this.id = ++SESSION_ID; + this.modifiedCanvasLayer = false; + if (this.outputContext && !TEST_ENV) { + const renderContextType = polyfillOptions.renderContextType || '2d'; + this.renderContext = this.outputContext.canvas.getContext(renderContextType); + } + } +} +class WebVRDevice extends XRDevice { + constructor(global, display) { + const { canPresent } = display.capabilities; + super(global); + this.display = display; + this.frame = new global.VRFrameData(); + this.sessions = new Map(); + this.immersiveSession = null; + this.canPresent = canPresent; + this.baseModelMatrix = create(); + this.gamepadInputSources = {}; + this.tempVec3 = new Float32Array(3); + this.onVRDisplayPresentChange = this.onVRDisplayPresentChange.bind(this); + global.window.addEventListener('vrdisplaypresentchange', this.onVRDisplayPresentChange); + this.CAN_USE_GAMEPAD = global.navigator && ('getGamepads' in global.navigator); + this.HAS_BITMAP_SUPPORT = isImageBitmapSupported(global); + } + get depthNear() { return this.display.depthNear; } + set depthNear(val) { this.display.depthNear = val; } + get depthFar() { return this.display.depthFar; } + set depthFar(val) { this.display.depthFar = val; } + onBaseLayerSet(sessionId, layer) { + const session = this.sessions.get(sessionId); + const canvas = layer.context.canvas; + if (session.immersive) { + const left = this.display.getEyeParameters('left'); + const right = this.display.getEyeParameters('right'); + canvas.width = Math.max(left.renderWidth, right.renderWidth) * 2; + canvas.height = Math.max(left.renderHeight, right.renderHeight); + this.display.requestPresent([{ + source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES + }]).then(() => { + if (!TEST_ENV && !this.global.document.body.contains(canvas)) { + session.modifiedCanvasLayer = true; + this.global.document.body.appendChild(canvas); + applyCanvasStylesForMinimalRendering(canvas); + } + session.baseLayer = layer; + }); + } + else { + session.baseLayer = layer; + } + } + isSessionSupported(mode) { + if (mode == 'immersive-ar') { + return false; + } + if (mode == 'immersive-vr' && this.canPresent === false) { + return false; + } + return true; + } + isFeatureSupported(featureDescriptor) { + switch(featureDescriptor) { + case 'viewer': return true; + case 'local': return true; + case 'local-floor': return true; + case 'bounded': return false; + case 'unbounded': return false; + default: return false; + } + } + async requestSession(mode, enabledFeatures) { + if (!this.isSessionSupported(mode)) { + return Promise.reject(); + } + let immersive = mode == 'immersive-vr'; + if (immersive) { + const canvas = this.global.document.createElement('canvas'); + if (!TEST_ENV) { + const ctx = canvas.getContext('webgl'); + } + await this.display.requestPresent([{ + source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES }]); + } + const session = new Session(mode, enabledFeatures, { + renderContextType: this.HAS_BITMAP_SUPPORT ? 'bitmaprenderer' : '2d' + }); + this.sessions.set(session.id, session); + if (immersive) { + this.immersiveSession = session; + this.dispatchEvent('@@webxr-polyfill/vr-present-start', session.id); + } + return Promise.resolve(session.id); + } + requestAnimationFrame(callback) { + return this.display.requestAnimationFrame(callback); + } + getPrimaryButtonIndex(gamepad) { + let primaryButton = 0; + let name = gamepad.id.toLowerCase(); + for (let key in PRIMARY_BUTTON_MAP) { + if (name.includes(key)) { + primaryButton = PRIMARY_BUTTON_MAP[key]; + break; + } + } + return Math.min(primaryButton, gamepad.buttons.length - 1); + } + onFrameStart(sessionId, renderState) { + this.display.depthNear = renderState.depthNear; + this.display.depthFar = renderState.depthFar; + this.display.getFrameData(this.frame); + const session = this.sessions.get(sessionId); + if (session.immersive && this.CAN_USE_GAMEPAD) { + let prevInputSources = this.gamepadInputSources; + this.gamepadInputSources = {}; + let gamepads = this.global.navigator.getGamepads(); + for (let i = 0; i < gamepads.length; ++i) { + let gamepad = gamepads[i]; + if (gamepad && gamepad.displayId > 0) { + let inputSourceImpl = prevInputSources[i]; + if (!inputSourceImpl) { + inputSourceImpl = new GamepadXRInputSource(this, this.display, this.getPrimaryButtonIndex(gamepad)); + } + inputSourceImpl.updateFromGamepad(gamepad); + this.gamepadInputSources[i] = inputSourceImpl; + if (inputSourceImpl.primaryButtonIndex != -1) { + let primaryActionPressed = gamepad.buttons[inputSourceImpl.primaryButtonIndex].pressed; + if (primaryActionPressed && !inputSourceImpl.primaryActionPressed) { + this.dispatchEvent('@@webxr-polyfill/input-select-start', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); + } else if (!primaryActionPressed && inputSourceImpl.primaryActionPressed) { + this.dispatchEvent('@@webxr-polyfill/input-select-end', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); + } + inputSourceImpl.primaryActionPressed = primaryActionPressed; + } + if (inputSourceImpl.primarySqueezeButtonIndex != -1) { + let primarySqueezeActionPressed = gamepad.buttons[inputSourceImpl.primarySqueezeButtonIndex].pressed; + if (primarySqueezeActionPressed && !inputSourceImpl.primarySqueezeActionPressed) { + this.dispatchEvent('@@webxr-polyfill/input-squeeze-start', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); + } else if (!primarySqueezeActionPressed && inputSourceImpl.primarySqueezeActionPressed) { + this.dispatchEvent('@@webxr-polyfill/input-squeeze-end', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); + } + inputSourceImpl.primarySqueezeActionPressed = primarySqueezeActionPressed; + } + } + } + } + if (TEST_ENV) { + return; + } + if (!session.immersive && session.baseLayer) { + const canvas = session.baseLayer.context.canvas; + perspective(this.frame.leftProjectionMatrix, renderState.inlineVerticalFieldOfView, + canvas.width/canvas.height, renderState.depthNear, renderState.depthFar); + } + } + onFrameEnd(sessionId) { + const session = this.sessions.get(sessionId); + if (session.ended || !session.baseLayer) { + return; + } + if (session.outputContext && + !(session.immersive && !this.display.capabilities.hasExternalDisplay)) { + const mirroring = + session.immersive && this.display.capabilities.hasExternalDisplay; + const iCanvas = session.baseLayer.context.canvas; + const iWidth = mirroring ? iCanvas.width / 2 : iCanvas.width; + const iHeight = iCanvas.height; + if (!TEST_ENV) { + const oCanvas = session.outputContext.canvas; + const oWidth = oCanvas.width; + const oHeight = oCanvas.height; + const renderContext = session.renderContext; + if (this.HAS_BITMAP_SUPPORT) { + if (iCanvas.transferToImageBitmap) { + renderContext.transferFromImageBitmap(iCanvas.transferToImageBitmap()); + } + else { + this.global.createImageBitmap(iCanvas, 0, 0, iWidth, iHeight, { + resizeWidth: oWidth, + resizeHeight: oHeight, + }).then(bitmap => renderContext.transferFromImageBitmap(bitmap)); + } + } else { + renderContext.drawImage(iCanvas, 0, 0, iWidth, iHeight, + 0, 0, oWidth, oHeight); + } + } + } + if (session.immersive && session.baseLayer) { + this.display.submitFrame(); + } + } + cancelAnimationFrame(handle) { + this.display.cancelAnimationFrame(handle); + } + async endSession(sessionId) { + const session = this.sessions.get(sessionId); + if (session.ended) { + return; + } + if (session.immersive) { + return this.display.exitPresent(); + } else { + session.ended = true; + } + } + doesSessionSupportReferenceSpace(sessionId, type) { + const session = this.sessions.get(sessionId); + if (session.ended) { + return false; + } + return session.enabledFeatures.has(type); + } + requestStageBounds() { + if (this.display.stageParameters) { + const width = this.display.stageParameters.sizeX; + const depth = this.display.stageParameters.sizeZ; + const data = []; + data.push(-width / 2); + data.push(-depth / 2); + data.push(width / 2); + data.push(-depth / 2); + data.push(width / 2); + data.push(depth / 2); + data.push(-width / 2); + data.push(depth / 2); + return data; + } + return null; + } + async requestFrameOfReferenceTransform(type, options) { + if ((type === 'local-floor' || type === 'bounded-floor') && + this.display.stageParameters && + this.display.stageParameters.sittingToStandingTransform) { + return this.display.stageParameters.sittingToStandingTransform; + } + return null; + } + getProjectionMatrix(eye) { + if (eye === 'left') { + return this.frame.leftProjectionMatrix; + } else if (eye === 'right') { + return this.frame.rightProjectionMatrix; + } else if (eye === 'none') { + return this.frame.leftProjectionMatrix; + } else { + throw new Error(`eye must be of type 'left' or 'right'`); + } + } + getViewport(sessionId, eye, layer, target) { + const session = this.sessions.get(sessionId); + const { width, height } = layer.context.canvas; + if (!session.immersive) { + target.x = target.y = 0; + target.width = width; + target.height = height; + return true; + } + if (eye === 'left' || eye === 'none') { + target.x = 0; + } else if (eye === 'right') { + target.x = width / 2; + } else { + return false; + } + target.y = 0; + target.width = width / 2; + target.height = height; + return true; + } + getBasePoseMatrix() { + let { position, orientation } = this.frame.pose; + if (!position && !orientation) { + return this.baseModelMatrix; + } + if (!position) { + position = this.tempVec3; + position[0] = position[1] = position[2] = 0; + } + fromRotationTranslation(this.baseModelMatrix, orientation, position); + return this.baseModelMatrix; + } + getBaseViewMatrix(eye) { + if (eye === 'left' || eye === 'none') { + return this.frame.leftViewMatrix; + } else if (eye === 'right') { + return this.frame.rightViewMatrix; + } else { + throw new Error(`eye must be of type 'left' or 'right'`); + } + } + getInputSources() { + let inputSources = []; + for (let i in this.gamepadInputSources) { + inputSources.push(this.gamepadInputSources[i].inputSource); + } + return inputSources; + } + getInputPose(inputSource, coordinateSystem, poseType) { + if (!coordinateSystem) { + return null; + } + for (let i in this.gamepadInputSources) { + let inputSourceImpl = this.gamepadInputSources[i]; + if (inputSourceImpl.inputSource === inputSource) { + return inputSourceImpl.getXRPose(coordinateSystem, poseType); + } + } + return null; + } + onWindowResize() { + } + onVRDisplayPresentChange(e) { + if (!this.display.isPresenting) { + this.sessions.forEach(session => { + if (session.immersive && !session.ended) { + if (session.modifiedCanvasLayer) { + const canvas = session.baseLayer.context.canvas; + document.body.removeChild(canvas); + canvas.setAttribute('style', ''); + } + if (this.immersiveSession === session) { + this.immersiveSession = null; + } + this.dispatchEvent('@@webxr-polyfill/vr-present-end', session.id); + } + }); + } + } +} + +class CardboardXRDevice extends WebVRDevice { + constructor(global, cardboardConfig) { + const display = new CardboardVRDisplay(cardboardConfig || {}); + super(global, display); + this.display = display; + this.frame = { + rightViewMatrix: new Float32Array(16), + leftViewMatrix: new Float32Array(16), + rightProjectionMatrix: new Float32Array(16), + leftProjectionMatrix: new Float32Array(16), + pose: null, + timestamp: null, + }; + } +} + +const TEST_ENV$1 = "production" === 'test'; +let SESSION_ID$1 = 0; +class Session$1 { + constructor(mode, enabledFeatures) { + this.mode = mode; + this.enabledFeatures = enabledFeatures; + this.ended = null; + this.baseLayer = null; + this.id = ++SESSION_ID$1; + } +} +class InlineDevice extends XRDevice { + constructor(global) { + super(global); + this.sessions = new Map(); + this.projectionMatrix = create(); + this.identityMatrix = create(); + } + onBaseLayerSet(sessionId, layer) { + const session = this.sessions.get(sessionId); + session.baseLayer = layer; + } + isSessionSupported(mode) { + return mode == 'inline'; + } + isFeatureSupported(featureDescriptor) { + switch(featureDescriptor) { + case 'viewer': return true; + default: return false; + } + } + async requestSession(mode, enabledFeatures) { + if (!this.isSessionSupported(mode)) { + return Promise.reject(); + } + const session = new Session$1(mode, enabledFeatures); + this.sessions.set(session.id, session); + return Promise.resolve(session.id); + } + requestAnimationFrame(callback) { + return window.requestAnimationFrame(callback); + } + cancelAnimationFrame(handle) { + window.cancelAnimationFrame(handle); + } + onFrameStart(sessionId, renderState) { + if (TEST_ENV$1) { + return; + } + const session = this.sessions.get(sessionId); + if (session.baseLayer) { + const canvas = session.baseLayer.context.canvas; + perspective(this.projectionMatrix, renderState.inlineVerticalFieldOfView, + canvas.width/canvas.height, renderState.depthNear, renderState.depthFar); + } + } + onFrameEnd(sessionId) { + } + async endSession(sessionId) { + const session = this.sessions.get(sessionId); + session.ended = true; + } + doesSessionSupportReferenceSpace(sessionId, type) { + const session = this.sessions.get(sessionId); + if (session.ended) { + return false; + } + return session.enabledFeatures.has(type); + } + requestStageBounds() { + return null; + } + async requestFrameOfReferenceTransform(type, options) { + return null; + } + getProjectionMatrix(eye) { + return this.projectionMatrix; + } + getViewport(sessionId, eye, layer, target) { + const session = this.sessions.get(sessionId); + const { width, height } = layer.context.canvas; + target.x = target.y = 0; + target.width = width; + target.height = height; + return true; + } + getBasePoseMatrix() { + return this.identityMatrix; + } + getBaseViewMatrix(eye) { + return this.identityMatrix; + } + getInputSources() { + return []; + } + getInputPose(inputSource, coordinateSystem, poseType) { + return null; + } + onWindowResize() { + } +} + +const getWebVRDevice = async function (global) { + let device = null; + if ('getVRDisplays' in global.navigator) { + try { + const displays = await global.navigator.getVRDisplays(); + if (displays && displays.length) { + device = new WebVRDevice(global, displays[0]); + } + } catch (e) {} + } + return device; +}; +const requestXRDevice = async function (global, config) { + if (config.webvr) { + let xr = await getWebVRDevice(global); + if (xr) { + return xr; + } + } + let mobile = isMobile(global); + if ((mobile && config.cardboard) || + (!mobile && config.allowCardboardOnDesktop)) { + if (!global.VRFrameData) { + global.VRFrameData = function () { + this.rightViewMatrix = new Float32Array(16); + this.leftViewMatrix = new Float32Array(16); + this.rightProjectionMatrix = new Float32Array(16); + this.leftProjectionMatrix = new Float32Array(16); + this.pose = null; + }; + } + return new CardboardXRDevice(global, config.cardboardConfig); + } + return new InlineDevice(global); +}; + +const CONFIG_DEFAULTS = { + global: _global, + webvr: true, + cardboard: true, + cardboardConfig: null, + allowCardboardOnDesktop: false, +}; +const partials = ['navigator', 'HTMLCanvasElement', 'WebGLRenderingContext']; +class WebXRPolyfill { + constructor(config={}) { + this.config = Object.freeze(Object.assign({}, CONFIG_DEFAULTS, config)); + this.global = this.config.global; + this.nativeWebXR = 'xr' in this.global.navigator; + this.injected = false; + if (!this.nativeWebXR) { + this._injectPolyfill(this.global); + } else { + this._injectCompatibilityShims(this.global); + } + } + _injectPolyfill(global) { + if (!partials.every(iface => !!global[iface])) { + throw new Error(`Global must have the following attributes : ${partials}`); + } + for (const className of Object.keys(API)) { + if (global[className] !== undefined) { + console.warn(`${className} already defined on global.`); + } else { + global[className] = API[className]; + } + } + { + const polyfilledCtx = polyfillMakeXRCompatible(global.WebGLRenderingContext); + if (polyfilledCtx) { + polyfillGetContext(global.HTMLCanvasElement); + if (global.OffscreenCanvas) { + polyfillGetContext(global.OffscreenCanvas); + } + if (global.WebGL2RenderingContext){ + polyfillMakeXRCompatible(global.WebGL2RenderingContext); + } + } + } + this.injected = true; + this._patchNavigatorXR(); + } + _patchNavigatorXR() { + let devicePromise = requestXRDevice(this.global, this.config); + this.xr = new API.XR(devicePromise); + Object.defineProperty(this.global.navigator, 'xr', { + value: this.xr, + configurable: true, + }); + } + _injectCompatibilityShims(global) { + if (!partials.every(iface => !!global[iface])) { + throw new Error(`Global must have the following attributes : ${partials}`); + } + if (global.navigator.xr && + 'supportsSession' in global.navigator.xr && + !('isSessionSupported' in global.navigator.xr)) { + let originalSupportsSession = global.navigator.xr.supportsSession; + global.navigator.xr.isSessionSupported = function(mode) { + return originalSupportsSession.call(this, mode).then(() => { + return true; + }).catch(() => { + return false; + }); + }; + global.navigator.xr.supportsSession = function(mode) { + console.warn("navigator.xr.supportsSession() is deprecated. Please " + + "call navigator.xr.isSessionSupported() instead and check the boolean " + + "value returned when the promise resolves."); + return originalSupportsSession.call(this, mode); + }; + } + } +} + +return WebXRPolyfill; + +}))); diff --git a/build/webxr-polyfill.min.js b/build/webxr-polyfill.min.js new file mode 100644 index 0000000..ff4b6e1 --- /dev/null +++ b/build/webxr-polyfill.min.js @@ -0,0 +1,95 @@ +/** + * @license + * webxr-polyfill + * Copyright (c) 2017 Google + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @license + * cardboard-vr-display + * Copyright (c) 2015-2017 Google + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @license + * webvr-polyfill-dpdb + * Copyright (c) 2017 Google + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @license + * wglu-preserve-state + * Copyright (c) 2016, Brandon Jones. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/** + * @license + * nosleep.js + * Copyright (c) 2017, Rich Tibbett + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.WebXRPolyfill=t()}(this,function(){"use strict";const e="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},t=Symbol("@@webxr-polyfill/EventTarget");class i{constructor(){this[t]={listeners:new Map}}addEventListener(e,i){if("string"!=typeof e)throw new Error("`type` must be a string");if("function"!=typeof i)throw new Error("`listener` must be a function");const r=this[t].listeners.get(e)||[];r.push(i),this[t].listeners.set(e,r)}removeEventListener(e,i){if("string"!=typeof e)throw new Error("`type` must be a string");if("function"!=typeof i)throw new Error("`listener` must be a function");const r=this[t].listeners.get(e)||[];for(let e=r.length;e>=0;e--)r[e]===i&&r.pop()}dispatchEvent(e,i){const r=this[t].listeners.get(e)||[],s=[];for(let e=0;e0?(r=2*Math.sqrt(i+1),e[3]=.25*r,e[0]=(t[6]-t[9])/r,e[1]=(t[8]-t[2])/r,e[2]=(t[1]-t[4])/r):t[0]>t[5]&&t[0]>t[10]?(r=2*Math.sqrt(1+t[0]-t[5]-t[10]),e[3]=(t[6]-t[9])/r,e[0]=.25*r,e[1]=(t[1]+t[4])/r,e[2]=(t[8]+t[2])/r):t[5]>t[10]?(r=2*Math.sqrt(1+t[5]-t[0]-t[10]),e[3]=(t[8]-t[2])/r,e[0]=(t[1]+t[4])/r,e[1]=.25*r,e[2]=(t[6]+t[9])/r):(r=2*Math.sqrt(1+t[10]-t[0]-t[5]),e[3]=(t[1]-t[4])/r,e[0]=(t[8]+t[2])/r,e[1]=(t[6]+t[9])/r,e[2]=.25*r),e}function d(e,t,i,r,s){let n,a=1/Math.tan(t/2);return e[0]=a/i,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=a,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[11]=-1,e[12]=0,e[13]=0,e[15]=0,null!=s&&s!==1/0?(n=1/(r-s),e[10]=(s+r)*n,e[14]=2*s*r*n):(e[10]=-1,e[14]=-2*r),e}function u(){let e=new s(3);return s!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e}function p(e){var t=new s(3);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t}function f(e,t,i){let r=new s(3);return r[0]=e,r[1]=t,r[2]=i,r}function m(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e}function g(e,t,i){return e[0]=t[0]+i[0],e[1]=t[1]+i[1],e[2]=t[2]+i[2],e}function v(e,t,i){return e[0]=t[0]*i,e[1]=t[1]*i,e[2]=t[2]*i,e}function w(e,t){let i=t[0],r=t[1],s=t[2],n=i*i+r*r+s*s;return n>0&&(n=1/Math.sqrt(n),e[0]=t[0]*n,e[1]=t[1]*n,e[2]=t[2]*n),e}function y(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]}function b(e,t,i){let r=t[0],s=t[1],n=t[2],a=i[0],o=i[1],l=i[2];return e[0]=s*l-n*o,e[1]=n*a-r*l,e[2]=r*o-s*a,e}function E(e,t,i){let r=i[0],s=i[1],n=i[2],a=i[3],o=t[0],l=t[1],A=t[2],h=s*A-n*l,c=n*o-r*A,d=r*l-s*o,u=s*d-n*c,p=n*h-r*d,f=r*c-s*h,m=2*a;return h*=m,c*=m,d*=m,u*=2,p*=2,f*=2,e[0]=o+h+u,e[1]=l+c+p,e[2]=A+d+f,e}const S=function(e){let t=e[0],i=e[1],r=e[2];return Math.sqrt(t*t+i*i+r*r)};!function(){let e=u()}();!function(){let e=function(){let e=new s(4);return s!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0,e[3]=0),e}()}();function M(){let e=new s(4);return s!=Float32Array&&(e[0]=0,e[1]=0,e[2]=0),e[3]=1,e}function x(e,t,i){let r=t[0],s=t[1],n=t[2],a=t[3],o=i[0],l=i[1],A=i[2],h=i[3];return e[0]=r*h+a*o+s*A-n*l,e[1]=s*h+a*l+n*o-r*A,e[2]=n*h+a*A+r*l-s*o,e[3]=a*h-r*o-s*l-n*A,e}function _(e,t,i,s){let n,a,o,l,A,h=t[0],c=t[1],d=t[2],u=t[3],p=i[0],f=i[1],m=i[2],g=i[3];return(a=h*p+c*f+d*m+u*g)<0&&(a=-a,p=-p,f=-f,m=-m,g=-g),1-a>r?(n=Math.acos(a),o=Math.sin(n),l=Math.sin((1-s)*n)/o,A=Math.sin(s*n)/o):(l=1-s,A=s),e[0]=l*h+A*p,e[1]=l*c+A*f,e[2]=l*d+A*m,e[3]=l*u+A*g,e}function F(e,t){let i=t[0],r=t[1],s=t[2],n=t[3],a=i*i+r*r+s*s+n*n,o=a?1/a:0;return e[0]=-i*o,e[1]=-r*o,e[2]=-s*o,e[3]=n*o,e}const R=function(e){let t=new s(4);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},T=function(e,t,i,r){let n=new s(4);return n[0]=e,n[1]=t,n[2]=i,n[3]=r,n},B=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e},C=function(e,t){let i=t[0],r=t[1],s=t[2],n=t[3],a=i*i+r*r+s*s+n*n;return a>0&&(a=1/Math.sqrt(a),e[0]=i*a,e[1]=r*a,e[2]=s*a,e[3]=n*a),e},D=(function(){let e=u(),t=f(1,0,0),i=f(0,1,0)}(),function(){let e=M(),t=M()}(),function(){let e=function(){let e=new s(9);return s!=Float32Array&&(e[1]=0,e[2]=0,e[3]=0,e[5]=0,e[6]=0,e[7]=0),e[0]=1,e[4]=1,e[8]=1,e}()}(),Symbol("@@webxr-polyfill/XRRigidTransform"));class P{constructor(){if(this[D]={matrix:null,position:null,orientation:null,inverse:null},0===arguments.length)this[D].matrix=a(new Float32Array(16));else if(1===arguments.length)arguments[0]instanceof Float32Array?this[D].matrix=arguments[0]:(this[D].position=this._getPoint(arguments[0]),this[D].orientation=DOMPointReadOnly.fromPoint({x:0,y:0,z:0,w:1}));else{if(2!==arguments.length)throw new Error("Too many arguments!");this[D].position=this._getPoint(arguments[0]),this[D].orientation=this._getPoint(arguments[1])}if(this[D].matrix){let e=u();h(e,this[D].matrix),this[D].position=DOMPointReadOnly.fromPoint({x:e[0],y:e[1],z:e[2]});let t=M();c(t,this[D].matrix),this[D].orientation=DOMPointReadOnly.fromPoint({x:t[0],y:t[1],z:t[2],w:t[3]})}else this[D].matrix=a(new Float32Array(16)),A(this[D].matrix,T(this[D].orientation.x,this[D].orientation.y,this[D].orientation.z,this[D].orientation.w),f(this[D].position.x,this[D].position.y,this[D].position.z))}_getPoint(e){return e instanceof DOMPointReadOnly?e:DOMPointReadOnly.fromPoint(e)}get matrix(){return this[D].matrix}get position(){return this[D].position}get orientation(){return this[D].orientation}get inverse(){if(null===this[D].inverse){let e=a(new Float32Array(16));o(e,this[D].matrix),this[D].inverse=new P(e),this[D].inverse[D].inverse=this}return this[D].inverse}}const I=Symbol("@@webxr-polyfill/XRSpace");class L{constructor(e=null,t=null){this[I]={specialType:e,inputSource:t,baseMatrix:null,inverseBaseMatrix:null,lastFrameId:-1}}get _specialType(){return this[I].specialType}get _inputSource(){return this[I].inputSource}_ensurePoseUpdated(e,t){t!=this[I].lastFrameId&&(this[I].lastFrameId=t,this._onPoseUpdate(e))}_onPoseUpdate(e){"viewer"==this[I].specialType&&(this._baseMatrix=e.getBasePoseMatrix())}set _baseMatrix(e){this[I].baseMatrix=e,this[I].inverseBaseMatrix=null}get _baseMatrix(){return this[I].baseMatrix||this[I].inverseBaseMatrix&&(this[I].baseMatrix=new Float32Array(16),o(this[I].baseMatrix,this[I].inverseBaseMatrix)),this[I].baseMatrix}set _inverseBaseMatrix(e){this[I].inverseBaseMatrix=e,this[I].baseMatrix=null}get _inverseBaseMatrix(){return this[I].inverseBaseMatrix||this[I].baseMatrix&&(this[I].inverseBaseMatrix=new Float32Array(16),o(this[I].inverseBaseMatrix,this[I].baseMatrix)),this[I].inverseBaseMatrix}_getSpaceRelativeTransform(e){if(!this._inverseBaseMatrix||!e._baseMatrix)return null;let t=new Float32Array(16);return l(t,this._inverseBaseMatrix,e._baseMatrix),new P(t)}}const O=1.6,N=Symbol("@@webxr-polyfill/XRReferenceSpace"),Q=["viewer","local","local-floor","bounded-floor","unbounded"];class G extends L{constructor(e,t=null){if(!Q.includes(e))throw new Error(`XRReferenceSpaceType must be one of ${Q}`);if(super(e),"bounded-floor"===e&&!t)throw new Error("XRReferenceSpace cannot use 'bounded-floor' type if the platform does not provide the floor level");(function(e){return"bounded-floor"===e||"local-floor"===e})(e)&&!t&&((t=a(new Float32Array(16)))[13]=O),this._inverseBaseMatrix=t||a(new Float32Array(16)),this[N]={type:e,transform:t,originOffset:a(new Float32Array(16))}}_transformBasePoseMatrix(e,t){l(e,this._inverseBaseMatrix,t)}_originOffsetMatrix(){return this[N].originOffset}_adjustForOriginOffset(e){let t=new Float32Array(16);o(t,this[N].originOffset),l(e,t,e)}_getSpaceRelativeTransform(e){let t=super._getSpaceRelativeTransform(e);return this._adjustForOriginOffset(t.matrix),new XRRigidTransform(t.matrix)}getOffsetReferenceSpace(e){let t=new G(this[N].type,this[N].transform,this[N].bounds);return l(t[N].originOffset,this[N].originOffset,e.matrix),t}}const k=Symbol("@@webxr-polyfill/XR"),z=["inline","immersive-vr","immersive-ar"],V={inline:{requiredFeatures:["viewer"],optionalFeatures:[]},"immersive-vr":{requiredFeatures:["viewer","local"],optionalFeatures:[]},"immersive-ar":{requiredFeatures:["viewer","local"],optionalFeatures:[]}},U="Polyfill Error: Must call navigator.xr.isSessionSupported() with any XRSessionMode\nor navigator.xr.requestSession('inline') prior to requesting an immersive\nsession. This is a limitation specific to the WebXR Polyfill and does not apply\nto native implementations of the API.";let H;if("performance"in e==!1){let e=Date.now();H=(()=>Date.now()-e)}else H=(()=>performance.now());var X=H;const W=Symbol("@@webxr-polyfill/XRPose");class j{constructor(e,t){this[W]={transform:e,emulatedPosition:t}}get transform(){return this[W].transform}get emulatedPosition(){return this[W].emulatedPosition}}const q=Symbol("@@webxr-polyfill/XRViewerPose");class Y extends j{constructor(e,t,i=!1){super(e,i),this[q]={views:t}}get views(){return this[q].views}}const Z=Symbol("@@webxr-polyfill/XRViewport");class J{constructor(e){this[Z]={target:e}}get x(){return this[Z].target.x}get y(){return this[Z].target.y}get width(){return this[Z].target.width}get height(){return this[Z].target.height}}const K=["left","right","none"],$=Symbol("@@webxr-polyfill/XRView");class ee{constructor(e,t,i,r){if(!K.includes(i))throw new Error(`XREye must be one of: ${K}`);const s=Object.create(null),n=new J(s);this[$]={device:e,eye:i,viewport:n,temp:s,sessionId:r,transform:t}}get eye(){return this[$].eye}get projectionMatrix(){return this[$].device.getProjectionMatrix(this.eye)}get transform(){return this[$].transform}_getViewport(e){if(this[$].device.getViewport(this[$].sessionId,this.eye,e,this[$].temp))return this[$].viewport}}const te=Symbol("@@webxr-polyfill/XRFrame"),ie="XRFrame access outside the callback that produced it is invalid.",re="getViewerPose can only be called on XRFrame objects passed to XRSession.requestAnimationFrame callbacks.";let se=0;class ne{constructor(e,t,i){this[te]={id:++se,active:!1,animationFrame:!1,device:e,session:t,sessionId:i}}get session(){return this[te].session}getViewerPose(e){if(!this[te].animationFrame)throw new DOMException(re,"InvalidStateError");if(!this[te].active)throw new DOMException(ie,"InvalidStateError");const t=this[te].device,i=this[te].session;i[we].viewerSpace._ensurePoseUpdated(t,this[te].id),e._ensurePoseUpdated(t,this[te].id);let r=e._getSpaceRelativeTransform(i[we].viewerSpace);const s=[];for(let r of i[we].viewSpaces){r._ensurePoseUpdated(t,this[te].id);let i=e._getSpaceRelativeTransform(r),n=new ee(t,i,r.eye,this[te].sessionId);s.push(n)}return new Y(r,s,!1)}getPose(e,t){if(!this[te].active)throw new DOMException(ie,"InvalidStateError");const i=this[te].device;if("target-ray"===e._specialType||"grip"===e._specialType)return i.getInputPose(e._inputSource,t,e._specialType);{e._ensurePoseUpdated(i,this[te].id),t._ensurePoseUpdated(i,this[te].id);let r=t._getSpaceRelativeTransform(e);return r?new XRPose(r,!1):null}}}const ae=Symbol("@@webxr-polyfill/XRRenderState"),oe=Object.freeze({depthNear:.1,depthFar:1e3,inlineVerticalFieldOfView:null,baseLayer:null});class le{constructor(e={}){const t=Object.assign({},oe,e);this[ae]={config:t}}get depthNear(){return this[ae].config.depthNear}get depthFar(){return this[ae].config.depthFar}get inlineVerticalFieldOfView(){return this[ae].config.inlineVerticalFieldOfView}get baseLayer(){return this[ae].config.baseLayer}}const Ae=Symbol("@@webxr-polyfill/polyfilled-xr-compatible"),he=Symbol("@@webxr-polyfill/xr-compatible"),ce=Symbol("@@webxr-polyfill/XRWebGLLayer"),de=Object.freeze({antialias:!0,depth:!1,stencil:!1,alpha:!0,multiview:!1,ignoreDepthValues:!1,framebufferScaleFactor:1});const ue=Symbol("@@webxr-polyfill/XRInputSourceEvent");class pe extends Event{constructor(e,t){super(e,t),this[ue]={frame:t.frame,inputSource:t.inputSource}}get frame(){return this[ue].frame}get inputSource(){return this[ue].inputSource}}const fe=Symbol("@@webxr-polyfill/XRSessionEvent");class me extends Event{constructor(e,t){super(e,t),this[fe]={session:t.session}}get session(){return this[fe].session}}const ge=Symbol("@@webxr-polyfill/XRInputSourcesChangeEvent");class ve extends Event{constructor(e,t){super(e,t),this[ge]={session:t.session,added:t.added,removed:t.removed}}get session(){return this[ge].session}get added(){return this[ge].added}get removed(){return this[ge].removed}}const we=Symbol("@@webxr-polyfill/XRSession");class ye extends L{constructor(e){super(e)}get eye(){return this._specialType}_onPoseUpdate(e){this._inverseBaseMatrix=e.getBaseViewMatrix(this._specialType)}}class be extends i{constructor(e,t,i){super();let r="inline"!=t,s=new le({inlineVerticalFieldOfView:r?null:.5*Math.PI});this[we]={device:e,mode:t,immersive:r,ended:!1,suspended:!1,frameCallbacks:[],currentFrameCallbacks:null,frameHandle:0,deviceFrameHandle:null,id:i,activeRenderState:s,pendingRenderState:null,viewerSpace:new G("viewer"),viewSpaces:[],currentInputSources:[]},r?this[we].viewSpaces.push(new ye("left"),new ye("right")):this[we].viewSpaces.push(new ye("none")),this[we].onDeviceFrame=(()=>{if(this[we].ended||this[we].suspended)return;if(this[we].deviceFrameHandle=null,this[we].startDeviceFrameLoop(),null!==this[we].pendingRenderState&&(this[we].activeRenderState=new le(this[we].pendingRenderState),this[we].pendingRenderState=null,this[we].activeRenderState.baseLayer&&this[we].device.onBaseLayerSet(this[we].id,this[we].activeRenderState.baseLayer)),null===this[we].activeRenderState.baseLayer)return;const t=new ne(e,this,this[we].id),i=this[we].currentFrameCallbacks=this[we].frameCallbacks;this[we].frameCallbacks=[],t[te].active=!0,t[te].animationFrame=!0,this[we].device.onFrameStart(this[we].id,this[we].activeRenderState),this._checkInputSourcesChange();const r=X();for(let e=0;e{null===this[we].deviceFrameHandle&&(this[we].deviceFrameHandle=this[we].device.requestAnimationFrame(this[we].onDeviceFrame))}),this[we].stopDeviceFrameLoop=(()=>{const e=this[we].deviceFrameHandle;null!==e&&(this[we].device.cancelAnimationFrame(e),this[we].deviceFrameHandle=null)}),this[we].onPresentationEnd=(t=>{if(t!==this[we].id)return this[we].suspended=!1,this[we].startDeviceFrameLoop(),void this.dispatchEvent("focus",{session:this});this[we].ended=!0,this[we].stopDeviceFrameLoop(),e.removeEventListener("@webvr-polyfill/vr-present-end",this[we].onPresentationEnd),e.removeEventListener("@webvr-polyfill/vr-present-start",this[we].onPresentationStart),e.removeEventListener("@@webvr-polyfill/input-select-start",this[we].onSelectStart),e.removeEventListener("@@webvr-polyfill/input-select-end",this[we].onSelectEnd),this.dispatchEvent("end",new me("end",{session:this}))}),e.addEventListener("@@webxr-polyfill/vr-present-end",this[we].onPresentationEnd),this[we].onPresentationStart=(e=>{e!==this[we].id&&(this[we].suspended=!0,this[we].stopDeviceFrameLoop(),this.dispatchEvent("blur",{session:this}))}),e.addEventListener("@@webxr-polyfill/vr-present-start",this[we].onPresentationStart),this[we].onSelectStart=(e=>{e.sessionId===this[we].id&&this[we].dispatchInputSourceEvent("selectstart",e.inputSource)}),e.addEventListener("@@webxr-polyfill/input-select-start",this[we].onSelectStart),this[we].onSelectEnd=(e=>{e.sessionId===this[we].id&&(this[we].dispatchInputSourceEvent("selectend",e.inputSource),this[we].dispatchInputSourceEvent("select",e.inputSource))}),e.addEventListener("@@webxr-polyfill/input-select-end",this[we].onSelectEnd),this[we].onSqueezeStart=(e=>{e.sessionId===this[we].id&&this[we].dispatchInputSourceEvent("squeezestart",e.inputSource)}),e.addEventListener("@@webxr-polyfill/input-squeeze-start",this[we].onSqueezeStart),this[we].onSqueezeEnd=(e=>{e.sessionId===this[we].id&&(this[we].dispatchInputSourceEvent("squeezeend",e.inputSource),this[we].dispatchInputSourceEvent("squeeze",e.inputSource))}),e.addEventListener("@@webxr-polyfill/input-squeeze-end",this[we].onSqueezeEnd),this[we].dispatchInputSourceEvent=((t,i)=>{const r=new ne(e,this,this[we].id),s=new pe(t,{frame:r,inputSource:i});r[te].active=!0,this.dispatchEvent(t,s),r[te].active=!1}),this[we].startDeviceFrameLoop(),this.onblur=void 0,this.onfocus=void 0,this.onresetpose=void 0,this.onend=void 0,this.onselect=void 0,this.onselectstart=void 0,this.onselectend=void 0}get renderState(){return this[we].activeRenderState}get environmentBlendMode(){return this[we].device.environmentBlendMode||"opaque"}async requestReferenceSpace(e){if(this[we].ended)return;if(!Q.includes(e))throw new TypeError(`XRReferenceSpaceType must be one of ${Q}`);if(!this[we].device.doesSessionSupportReferenceSpace(this[we].id,e))throw new DOMException(`The ${e} reference space is not supported by this session.`,"NotSupportedError");if("viewer"===e)return this[we].viewerSpace;let t=await this[we].device.requestFrameOfReferenceTransform(e);if("bounded-floor"===e){if(!t)throw new DOMException(`${e} XRReferenceSpace not supported by this device.`,"NotSupportedError");if(!this[we].device.requestStageBounds())throw new DOMException(`${e} XRReferenceSpace not supported by this device.`,"NotSupportedError");throw new DOMException(`The WebXR polyfill does not support the ${e} reference space yet.`,"NotSupportedError")}return new G(e,t)}requestAnimationFrame(e){if(this[we].ended)return;const t=++this[we].frameHandle;return this[we].frameCallbacks.push({handle:t,callback:e,cancelled:!1}),t}cancelAnimationFrame(e){let t=this[we].frameCallbacks,i=t.findIndex(t=>t&&t.handle===e);i>-1&&(t[i].cancelled=!0,t.splice(i,1)),(t=this[we].currentFrameCallbacks)&&(i=t.findIndex(t=>t&&t.handle===e))>-1&&(t[i].cancelled=!0)}get inputSources(){return this[we].device.getInputSources()}async end(){if(!this[we].ended)return this.immersive&&(this[we].ended=!0,this[we].device.removeEventListener("@@webvr-polyfill/vr-present-start",this[we].onPresentationStart),this[we].device.removeEventListener("@@webvr-polyfill/vr-present-end",this[we].onPresentationEnd),this[we].device.removeEventListener("@@webvr-polyfill/input-select-start",this[we].onSelectStart),this[we].device.removeEventListener("@@webvr-polyfill/input-select-end",this[we].onSelectEnd),this.dispatchEvent("end",new me("end",{session:this}))),this[we].stopDeviceFrameLoop(),this[we].device.endSession(this[we].id)}updateRenderState(e){if(this[we].ended){throw new Error("Can't call updateRenderState on an XRSession that has already ended.")}if(e.baseLayer&&e.baseLayer._session!==this){throw new Error("Called updateRenderState with a base layer that was created by a different session.")}if(null!==e.inlineVerticalFieldOfView&&void 0!==e.inlineVerticalFieldOfView){if(this[we].immersive){throw new Error("inlineVerticalFieldOfView must not be set for an XRRenderState passed to updateRenderState for an immersive session.")}e.inlineVerticalFieldOfView=Math.min(3.13,Math.max(.01,e.inlineVerticalFieldOfView))}if(null===this[we].pendingRenderState){const e=this[we].activeRenderState;this[we].pendingRenderState={depthNear:e.depthNear,depthFar:e.depthFar,inlineVerticalFieldOfView:e.inlineVerticalFieldOfView,baseLayer:e.baseLayer}}Object.assign(this[we].pendingRenderState,e)}_checkInputSourcesChange(){const e=[],t=[],i=this.inputSources,r=this[we].currentInputSources;for(const t of i)r.includes(t)||e.push(t);for(const e of r)i.includes(e)||t.push(e);(e.length>0||t.length>0)&&this.dispatchEvent("inputsourceschange",new ve("inputsourceschange",{session:this,added:e,removed:t})),this[we].currentInputSources.length=0;for(const e of i)this[we].currentInputSources.push(e)}}const Ee=Symbol("@@webxr-polyfill/XRInputSource");class Se{constructor(e){this[Ee]={impl:e,gripSpace:new L("grip",this),targetRaySpace:new L("target-ray",this)}}get handedness(){return this[Ee].impl.handedness}get targetRayMode(){return this[Ee].impl.targetRayMode}get gripSpace(){let e=this[Ee].impl.targetRayMode;return"gaze"===e||"screen"===e?null:this[Ee].gripSpace}get targetRaySpace(){return this[Ee].targetRaySpace}get profiles(){return this[Ee].impl.profiles}get gamepad(){return this[Ee].impl.gamepad}}const Me=Symbol("@@webxr-polyfill/XRReferenceSpaceEvent");var xe={XR:class extends i{constructor(e){super(),this[k]={device:null,devicePromise:e,immersiveSession:null,inlineSessions:new Set},e.then(e=>{this[k].device=e})}async isSessionSupported(e){return this[k].device||await this[k].devicePromise,"inline"!=e?Promise.resolve(this[k].device.isSessionSupported(e)):Promise.resolve(!0)}async requestSession(e,t){if(!this[k].device){if("inline"!=e)throw new Error(U);await this[k].devicePromise}if(!z.includes(e))throw new TypeError(`The provided value '${e}' is not a valid enum value of type XRSessionMode`);const i=V[e],r=i.requiredFeatures.concat(t&&t.requiredFeatures?t.requiredFeatures:[]),s=i.optionalFeatures.concat(t&&t.optionalFeatures?t.optionalFeatures:[]),n=new Set;let a=!1;for(let e of r)this[k].device.isFeatureSupported(e)?n.add(e):(console.error(`The required feature '${e}' is not supported`),a=!0);if(a)throw new DOMException("Session does not support some required features","NotSupportedError");for(let e of s)this[k].device.isFeatureSupported(e)?n.add(e):console.log(`The optional feature '${e}' is not supported`);const o=await this[k].device.requestSession(e,n),l=new XRSession(this[k].device,e,o);"inline"==e?this[k].inlineSessions.add(l):this[k].immersiveSession=l;const A=()=>{"inline"==e?this[k].inlineSessions.delete(l):this[k].immersiveSession=null,l.removeEventListener("end",A)};return l.addEventListener("end",A),l}},XRSession:be,XRSessionEvent:me,XRFrame:ne,XRView:ee,XRViewport:J,XRViewerPose:Y,XRWebGLLayer:class{constructor(e,t,i={}){const r=Object.assign({},de,i);if(!(e instanceof be))throw new Error("session must be a XRSession");if(e.ended)throw new Error("InvalidStateError");if(t[Ae]&&!0!==t[he])throw new Error("InvalidStateError");const s=t.getParameter(t.FRAMEBUFFER_BINDING);this[ce]={context:t,config:r,framebuffer:s,session:e}}get context(){return this[ce].context}get antialias(){return this[ce].config.antialias}get ignoreDepthValues(){return!0}get framebuffer(){return this[ce].framebuffer}get framebufferWidth(){return this[ce].context.drawingBufferWidth}get framebufferHeight(){return this[ce].context.drawingBufferHeight}get _session(){return this[ce].session}getViewport(e){return e._getViewport(this)}static getNativeFramebufferScaleFactor(e){if(!e)throw new TypeError("getNativeFramebufferScaleFactor must be passed a session.");return e[we].ended?0:1}},XRSpace:L,XRReferenceSpace:G,XRReferenceSpaceEvent:class extends Event{constructor(e,t){super(e,t),this[Me]={referenceSpace:t.referenceSpace,transform:t.transform||null}}get referenceSpace(){return this[Me].referenceSpace}get transform(){return this[Me].transform}},XRInputSource:Se,XRInputSourceEvent:pe,XRInputSourcesChangeEvent:ve,XRRenderState:le,XRRigidTransform:P,XRPose:j};const _e=e=>"function"!=typeof e.prototype.makeXRCompatible&&(e.prototype.makeXRCompatible=function(){return this[he]=!0,Promise.resolve()},!0),Fe=e=>{const t=e.prototype.getContext;e.prototype.getContext=function(e,i){const r=t.call(this,e,i);return r&&(r[Ae]=!0,i&&"xrCompatible"in i&&(r[he]=i.xrCompatible)),r}},Re=e=>!(!e.ImageBitmapRenderingContext||!e.createImageBitmap);var Te;const Be=e=>{e.style.display="block",e.style.position="absolute",e.style.width=e.style.height="1px",e.style.top=e.style.left="0px"};var Ce="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var De,Pe,Ie=(function(e,t){e.exports=function(){var e,t,i,r=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},s=function(){function e(e,t){for(var i=0;ie.TEXTURE31){console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit"),r.push(null,null);break}s||(s=e.getParameter(e.ACTIVE_TEXTURE)),e.activeTexture(o),r.push(e.getParameter(a),null);break;case e.ACTIVE_TEXTURE:s=e.getParameter(e.ACTIVE_TEXTURE),r.push(null);break;default:r.push(e.getParameter(a))}}i(e);for(var n=0;ne.TEXTURE31)break;e.activeTexture(o),e.bindTexture(e.TEXTURE_2D,l);break;case e.TEXTURE_BINDING_CUBE_MAP:var o=t[++n];if(oe.TEXTURE31)break;e.activeTexture(o),e.bindTexture(e.TEXTURE_CUBE_MAP,l);break;case e.VIEWPORT:e.viewport(l[0],l[1],l[2],l[3]);break;case e.BLEND:case e.CULL_FACE:case e.DEPTH_TEST:case e.SCISSOR_TEST:case e.STENCIL_TEST:l?e.enable(a):e.disable(a);break;default:console.log("No GL restore behavior for 0x"+a.toString(16))}s&&e.activeTexture(s)}}else i(e)},F=["attribute vec2 position;","attribute vec3 texCoord;","varying vec2 vTexCoord;","uniform vec4 viewportOffsetScale[2];","void main() {"," vec4 viewport = viewportOffsetScale[int(texCoord.z)];"," vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;"," gl_Position = vec4( position, 1.0, 1.0 );","}"].join("\n"),R=["precision mediump float;","uniform sampler2D diffuse;","varying vec2 vTexCoord;","void main() {"," gl_FragColor = texture2D(diffuse, vTexCoord);","}"].join("\n");function T(e,t,i,r){this.gl=e,this.cardboardUI=t,this.bufferScale=i,this.dirtySubmitFrameBindings=r,this.ctxAttribs=e.getContextAttributes(),this.meshWidth=20,this.meshHeight=20,this.bufferWidth=e.drawingBufferWidth,this.bufferHeight=e.drawingBufferHeight,this.realBindFramebuffer=e.bindFramebuffer,this.realEnable=e.enable,this.realDisable=e.disable,this.realColorMask=e.colorMask,this.realClearColor=e.clearColor,this.realViewport=e.viewport,o()||(this.realCanvasWidth=Object.getOwnPropertyDescriptor(e.canvas.__proto__,"width"),this.realCanvasHeight=Object.getOwnPropertyDescriptor(e.canvas.__proto__,"height")),this.isPatched=!1,this.lastBoundFramebuffer=null,this.cullFace=!1,this.depthTest=!1,this.blend=!1,this.scissorTest=!1,this.stencilTest=!1,this.viewport=[0,0,0,0],this.colorMask=[!0,!0,!0,!0],this.clearColor=[0,0,0,0],this.attribs={position:0,texCoord:1},this.program=g(e,F,R,this.attribs),this.uniforms=v(e,this.program),this.viewportOffsetScale=new Float32Array(8),this.setTextureBounds(),this.vertexBuffer=e.createBuffer(),this.indexBuffer=e.createBuffer(),this.indexCount=0,this.renderTarget=e.createTexture(),this.framebuffer=e.createFramebuffer(),this.depthStencilBuffer=null,this.depthBuffer=null,this.stencilBuffer=null,this.ctxAttribs.depth&&this.ctxAttribs.stencil?this.depthStencilBuffer=e.createRenderbuffer():this.ctxAttribs.depth?this.depthBuffer=e.createRenderbuffer():this.ctxAttribs.stencil&&(this.stencilBuffer=e.createRenderbuffer()),this.patch(),this.onResize()}T.prototype.destroy=function(){var e=this.gl;this.unpatch(),e.deleteProgram(this.program),e.deleteBuffer(this.vertexBuffer),e.deleteBuffer(this.indexBuffer),e.deleteTexture(this.renderTarget),e.deleteFramebuffer(this.framebuffer),this.depthStencilBuffer&&e.deleteRenderbuffer(this.depthStencilBuffer),this.depthBuffer&&e.deleteRenderbuffer(this.depthBuffer),this.stencilBuffer&&e.deleteRenderbuffer(this.stencilBuffer),this.cardboardUI&&this.cardboardUI.destroy()},T.prototype.onResize=function(){var e=this.gl,t=this,i=[e.RENDERBUFFER_BINDING,e.TEXTURE_BINDING_2D,e.TEXTURE0];_(e,i,function(e){t.realBindFramebuffer.call(e,e.FRAMEBUFFER,null),t.scissorTest&&t.realDisable.call(e,e.SCISSOR_TEST),t.realColorMask.call(e,!0,!0,!0,!0),t.realViewport.call(e,0,0,e.drawingBufferWidth,e.drawingBufferHeight),t.realClearColor.call(e,0,0,0,1),e.clear(e.COLOR_BUFFER_BIT),t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.framebuffer),e.bindTexture(e.TEXTURE_2D,t.renderTarget),e.texImage2D(e.TEXTURE_2D,0,t.ctxAttribs.alpha?e.RGBA:e.RGB,t.bufferWidth,t.bufferHeight,0,t.ctxAttribs.alpha?e.RGBA:e.RGB,e.UNSIGNED_BYTE,null),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t.renderTarget,0),t.ctxAttribs.depth&&t.ctxAttribs.stencil?(e.bindRenderbuffer(e.RENDERBUFFER,t.depthStencilBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.DEPTH_STENCIL,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.DEPTH_STENCIL_ATTACHMENT,e.RENDERBUFFER,t.depthStencilBuffer)):t.ctxAttribs.depth?(e.bindRenderbuffer(e.RENDERBUFFER,t.depthBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.DEPTH_COMPONENT16,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.DEPTH_ATTACHMENT,e.RENDERBUFFER,t.depthBuffer)):t.ctxAttribs.stencil&&(e.bindRenderbuffer(e.RENDERBUFFER,t.stencilBuffer),e.renderbufferStorage(e.RENDERBUFFER,e.STENCIL_INDEX8,t.bufferWidth,t.bufferHeight),e.framebufferRenderbuffer(e.FRAMEBUFFER,e.STENCIL_ATTACHMENT,e.RENDERBUFFER,t.stencilBuffer)),!e.checkFramebufferStatus(e.FRAMEBUFFER)===e.FRAMEBUFFER_COMPLETE&&console.error("Framebuffer incomplete!"),t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.lastBoundFramebuffer),t.scissorTest&&t.realEnable.call(e,e.SCISSOR_TEST),t.realColorMask.apply(e,t.colorMask),t.realViewport.apply(e,t.viewport),t.realClearColor.apply(e,t.clearColor)}),this.cardboardUI&&this.cardboardUI.onResize()},T.prototype.patch=function(){if(!this.isPatched){var e=this,t=this.gl.canvas,i=this.gl;o()||(t.width=p()*this.bufferScale,t.height=f()*this.bufferScale,Object.defineProperty(t,"width",{configurable:!0,enumerable:!0,get:function(){return e.bufferWidth},set:function(i){e.bufferWidth=i,e.realCanvasWidth.set.call(t,i),e.onResize()}}),Object.defineProperty(t,"height",{configurable:!0,enumerable:!0,get:function(){return e.bufferHeight},set:function(i){e.bufferHeight=i,e.realCanvasHeight.set.call(t,i),e.onResize()}})),this.lastBoundFramebuffer=i.getParameter(i.FRAMEBUFFER_BINDING),null==this.lastBoundFramebuffer&&(this.lastBoundFramebuffer=this.framebuffer,this.gl.bindFramebuffer(i.FRAMEBUFFER,this.framebuffer)),this.gl.bindFramebuffer=function(t,r){e.lastBoundFramebuffer=r||e.framebuffer,e.realBindFramebuffer.call(i,t,e.lastBoundFramebuffer)},this.cullFace=i.getParameter(i.CULL_FACE),this.depthTest=i.getParameter(i.DEPTH_TEST),this.blend=i.getParameter(i.BLEND),this.scissorTest=i.getParameter(i.SCISSOR_TEST),this.stencilTest=i.getParameter(i.STENCIL_TEST),i.enable=function(t){switch(t){case i.CULL_FACE:e.cullFace=!0;break;case i.DEPTH_TEST:e.depthTest=!0;break;case i.BLEND:e.blend=!0;break;case i.SCISSOR_TEST:e.scissorTest=!0;break;case i.STENCIL_TEST:e.stencilTest=!0}e.realEnable.call(i,t)},i.disable=function(t){switch(t){case i.CULL_FACE:e.cullFace=!1;break;case i.DEPTH_TEST:e.depthTest=!1;break;case i.BLEND:e.blend=!1;break;case i.SCISSOR_TEST:e.scissorTest=!1;break;case i.STENCIL_TEST:e.stencilTest=!1}e.realDisable.call(i,t)},this.colorMask=i.getParameter(i.COLOR_WRITEMASK),i.colorMask=function(t,r,s,n){e.colorMask[0]=t,e.colorMask[1]=r,e.colorMask[2]=s,e.colorMask[3]=n,e.realColorMask.call(i,t,r,s,n)},this.clearColor=i.getParameter(i.COLOR_CLEAR_VALUE),i.clearColor=function(t,r,s,n){e.clearColor[0]=t,e.clearColor[1]=r,e.clearColor[2]=s,e.clearColor[3]=n,e.realClearColor.call(i,t,r,s,n)},this.viewport=i.getParameter(i.VIEWPORT),i.viewport=function(t,r,s,n){e.viewport[0]=t,e.viewport[1]=r,e.viewport[2]=s,e.viewport[3]=n,e.realViewport.call(i,t,r,s,n)},this.isPatched=!0,b(t)}},T.prototype.unpatch=function(){if(this.isPatched){var e=this.gl,t=this.gl.canvas;o()||(Object.defineProperty(t,"width",this.realCanvasWidth),Object.defineProperty(t,"height",this.realCanvasHeight)),t.width=this.bufferWidth,t.height=this.bufferHeight,e.bindFramebuffer=this.realBindFramebuffer,e.enable=this.realEnable,e.disable=this.realDisable,e.colorMask=this.realColorMask,e.clearColor=this.realClearColor,e.viewport=this.realViewport,this.lastBoundFramebuffer==this.framebuffer&&e.bindFramebuffer(e.FRAMEBUFFER,null),this.isPatched=!1,setTimeout(function(){b(t)},1)}},T.prototype.setTextureBounds=function(e,t){e||(e=[0,0,.5,1]),t||(t=[.5,0,.5,1]),this.viewportOffsetScale[0]=e[0],this.viewportOffsetScale[1]=e[1],this.viewportOffsetScale[2]=e[2],this.viewportOffsetScale[3]=e[3],this.viewportOffsetScale[4]=t[0],this.viewportOffsetScale[5]=t[1],this.viewportOffsetScale[6]=t[2],this.viewportOffsetScale[7]=t[3]},T.prototype.submitFrame=function(){var e=this.gl,t=this,i=[];if(this.dirtySubmitFrameBindings||i.push(e.CURRENT_PROGRAM,e.ARRAY_BUFFER_BINDING,e.ELEMENT_ARRAY_BUFFER_BINDING,e.TEXTURE_BINDING_2D,e.TEXTURE0),_(e,i,function(e){t.realBindFramebuffer.call(e,e.FRAMEBUFFER,null),t.cullFace&&t.realDisable.call(e,e.CULL_FACE),t.depthTest&&t.realDisable.call(e,e.DEPTH_TEST),t.blend&&t.realDisable.call(e,e.BLEND),t.scissorTest&&t.realDisable.call(e,e.SCISSOR_TEST),t.stencilTest&&t.realDisable.call(e,e.STENCIL_TEST),t.realColorMask.call(e,!0,!0,!0,!0),t.realViewport.call(e,0,0,e.drawingBufferWidth,e.drawingBufferHeight),(t.ctxAttribs.alpha||o())&&(t.realClearColor.call(e,0,0,0,1),e.clear(e.COLOR_BUFFER_BIT)),e.useProgram(t.program),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,t.indexBuffer),e.bindBuffer(e.ARRAY_BUFFER,t.vertexBuffer),e.enableVertexAttribArray(t.attribs.position),e.enableVertexAttribArray(t.attribs.texCoord),e.vertexAttribPointer(t.attribs.position,2,e.FLOAT,!1,20,0),e.vertexAttribPointer(t.attribs.texCoord,3,e.FLOAT,!1,20,8),e.activeTexture(e.TEXTURE0),e.uniform1i(t.uniforms.diffuse,0),e.bindTexture(e.TEXTURE_2D,t.renderTarget),e.uniform4fv(t.uniforms.viewportOffsetScale,t.viewportOffsetScale),e.drawElements(e.TRIANGLES,t.indexCount,e.UNSIGNED_SHORT,0),t.cardboardUI&&t.cardboardUI.renderNoState(),t.realBindFramebuffer.call(t.gl,e.FRAMEBUFFER,t.framebuffer),t.ctxAttribs.preserveDrawingBuffer||(t.realClearColor.call(e,0,0,0,0),e.clear(e.COLOR_BUFFER_BIT)),t.dirtySubmitFrameBindings||t.realBindFramebuffer.call(e,e.FRAMEBUFFER,t.lastBoundFramebuffer),t.cullFace&&t.realEnable.call(e,e.CULL_FACE),t.depthTest&&t.realEnable.call(e,e.DEPTH_TEST),t.blend&&t.realEnable.call(e,e.BLEND),t.scissorTest&&t.realEnable.call(e,e.SCISSOR_TEST),t.stencilTest&&t.realEnable.call(e,e.STENCIL_TEST),t.realColorMask.apply(e,t.colorMask),t.realViewport.apply(e,t.viewport),!t.ctxAttribs.alpha&&t.ctxAttribs.preserveDrawingBuffer||t.realClearColor.apply(e,t.clearColor)}),o()){var r=e.canvas;r.width==t.bufferWidth&&r.height==t.bufferHeight||(t.bufferWidth=r.width,t.bufferHeight=r.height,t.onResize())}},T.prototype.updateDeviceInfo=function(e){var t=this.gl,i=this,r=[t.ARRAY_BUFFER_BINDING,t.ELEMENT_ARRAY_BUFFER_BINDING];_(t,r,function(t){var r=i.computeMeshVertices_(i.meshWidth,i.meshHeight,e);if(t.bindBuffer(t.ARRAY_BUFFER,i.vertexBuffer),t.bufferData(t.ARRAY_BUFFER,r,t.STATIC_DRAW),!i.indexCount){var s=i.computeMeshIndices_(i.meshWidth,i.meshHeight);t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,i.indexBuffer),t.bufferData(t.ELEMENT_ARRAY_BUFFER,s,t.STATIC_DRAW),i.indexCount=s.length}})},T.prototype.computeMeshVertices_=function(e,t,i){for(var r=new Float32Array(2*e*t*5),s=i.getLeftEyeVisibleTanAngles(),n=i.getLeftEyeNoLensTanAngles(),o=i.getLeftEyeVisibleScreenRect(n),l=0,A=0;A<2;A++){for(var h=0;hs-42&&r.clientXi.clientHeight-42?e(r):r.clientX<42&&r.clientY<42&&t(r)},i.addEventListener("click",this.listener,!1)},I.prototype.onResize=function(){var e=this.gl,t=this,i=[e.ARRAY_BUFFER_BINDING];_(e,i,function(e){var i=[],r=e.drawingBufferWidth/2,s=Math.max(screen.width,screen.height)*window.devicePixelRatio,n=e.drawingBufferWidth/s,a=n*window.devicePixelRatio,o=4*a/2,l=42*a,A=28*a/2,h=14*a;function c(e,t){var s=(90-e)*D,n=Math.cos(s),a=Math.sin(s);i.push(P*n*A+r,P*a*A+A),i.push(t*n*A+r,t*a*A+A)}i.push(r-o,l),i.push(r-o,e.drawingBufferHeight),i.push(r+o,l),i.push(r+o,e.drawingBufferHeight),t.gearOffset=i.length/2;for(var d=0;d<=6;d++){var u=60*d;c(u,1),c(u+12,1),c(u+20,.75),c(u+40,.75),c(u+48,1)}function p(t,r){i.push(h+t,e.drawingBufferHeight-h-r)}t.gearVertexCount=i.length/2-t.gearOffset,t.arrowOffset=i.length/2;var f=o/Math.sin(45*D);p(0,A),p(A,0),p(A+f,f),p(f,A+f),p(f,A-f),p(0,A),p(A,2*A),p(A+f,2*A-f),p(f,A-f),p(0,A),p(f,A-o),p(28*a,A-o),p(f,A+o),p(28*a,A+o),t.arrowVertexCount=i.length/2-t.arrowOffset,e.bindBuffer(e.ARRAY_BUFFER,t.vertexBuffer),e.bufferData(e.ARRAY_BUFFER,new Float32Array(i),e.STATIC_DRAW)})},I.prototype.render=function(){var e=this.gl,t=this,i=[e.CULL_FACE,e.DEPTH_TEST,e.BLEND,e.SCISSOR_TEST,e.STENCIL_TEST,e.COLOR_WRITEMASK,e.VIEWPORT,e.CURRENT_PROGRAM,e.ARRAY_BUFFER_BINDING];_(e,i,function(e){e.disable(e.CULL_FACE),e.disable(e.DEPTH_TEST),e.disable(e.BLEND),e.disable(e.SCISSOR_TEST),e.disable(e.STENCIL_TEST),e.colorMask(!0,!0,!0,!0),e.viewport(0,0,e.drawingBufferWidth,e.drawingBufferHeight),t.renderNoState()})},I.prototype.renderNoState=function(){var e,t,i,r,s,n,a,o,l,A,h=this.gl;h.useProgram(this.program),h.bindBuffer(h.ARRAY_BUFFER,this.vertexBuffer),h.enableVertexAttribArray(this.attribs.position),h.vertexAttribPointer(this.attribs.position,2,h.FLOAT,!1,8,0),h.uniform4f(this.uniforms.color,1,1,1,1),e=this.projMat,t=0,i=h.drawingBufferWidth,r=0,s=h.drawingBufferHeight,o=1/(t-i),l=1/(r-s),A=1/((n=.1)-(a=1024)),e[0]=-2*o,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=-2*l,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=2*A,e[11]=0,e[12]=(t+i)*o,e[13]=(s+r)*l,e[14]=(a+n)*A,e[15]=1,h.uniformMatrix4fv(this.uniforms.projectionMat,!1,this.projMat),h.drawArrays(h.TRIANGLE_STRIP,0,4),h.drawArrays(h.TRIANGLE_STRIP,this.gearOffset,this.gearVertexCount),h.drawArrays(h.TRIANGLE_STRIP,this.arrowOffset,this.arrowVertexCount)},L.prototype.distortInverse=function(e){for(var t=0,i=1,r=e-this.distort(t);Math.abs(i-t)>1e-4;){var s=e-this.distort(i),n=i-s*((i-t)/(s-r));t=i,i=n,r=s}return i},L.prototype.distort=function(e){for(var t=e*e,i=0,r=0;r=1)return this.w=n,this.x=i,this.y=r,this.z=s,this;var o=Math.acos(a),l=Math.sqrt(1-a*a);if(Math.abs(l)<.001)return this.w=.5*(n+this.w),this.x=.5*(i+this.x),this.y=.5*(r+this.y),this.z=.5*(s+this.z),this;var A=Math.sin((1-t)*o)/l,h=Math.sin(t*o)/l;return this.w=n*A+this.w*h,this.x=i*A+this.x*h,this.y=r*A+this.y*h,this.z=s*A+this.z*h,this},setFromUnitVectors:function(e,t){return void 0===G&&(G=new Q),(k=e.dot(t)+1)<1e-6?(k=0,Math.abs(e.x)>Math.abs(e.z)?G.set(-e.y,e.x,0):G.set(0,-e.z,e.y)):G.crossVectors(e,t),this.x=G.x,this.y=G.y,this.z=G.z,this.w=k,this.normalize(),this}};var U=new V({widthMeters:.11,heightMeters:.062,bevelMeters:.004}),H=new V({widthMeters:.1038,heightMeters:.0584,bevelMeters:.004}),X={CardboardV1:new j({id:"CardboardV1",label:"Cardboard I/O 2014",fov:40,interLensDistance:.06,baselineLensDistance:.035,screenLensDistance:.042,distortionCoefficients:[.441,.156],inverseCoefficients:[-.4410035,.42756155,-.4804439,.5460139,-.58821183,.5733938,-.48303202,.33299083,-.17573841,.0651772,-.01488963,.001559834]}),CardboardV2:new j({id:"CardboardV2",label:"Cardboard I/O 2015",fov:60,interLensDistance:.064,baselineLensDistance:.035,screenLensDistance:.039,distortionCoefficients:[.34,.55],inverseCoefficients:[-.33836704,-.18162185,.862655,-1.2462051,1.0560602,-.58208317,.21609078,-.05444823,.009177956,-.0009904169,6183535e-11,-16981803e-13]})};function W(e,t){this.viewer=X.CardboardV2,this.updateDeviceParams(e),this.distortion=new L(this.viewer.distortionCoefficients);for(var i=0;i=200&&i.status<=299?(r.dpdb=JSON.parse(i.response),r.recalculateDeviceParams_()):console.error("Error loading online DPDB!")}),i.send()}}function Z(e){this.xdpi=e.xdpi,this.ydpi=e.ydpi,this.bevelMm=e.bevelMm}function J(e,t){this.set(e,t)}function K(e,t){this.kFilter=e,this.isDebug=t,this.currentAccelMeasurement=new J,this.currentGyroMeasurement=new J,this.previousGyroMeasurement=new J,o()?this.filterQ=new z(-1,0,0,1):this.filterQ=new z(1,0,0,1),this.previousFilterQ=new z,this.previousFilterQ.copy(this.filterQ),this.accelQ=new z,this.isOrientationInitialized=!1,this.estimatedGravity=new Q,this.measuredGravity=new Q,this.gyroIntegralQ=new z}function $(e,t){this.predictionTimeS=e,this.isDebug=t,this.previousQ=new z,this.previousTimestampS=null,this.deltaQ=new z,this.outQ=new z}function ee(e,t,i,r){this.yawOnly=i,this.accelerometer=new Q,this.gyroscope=new Q,this.filter=new K(e,r),this.posePredictor=new $(t,r),this.isFirefoxAndroid=A(),this.isIOS=o();var s=h();this.isDeviceMotionInRadians=!this.isIOS&&s&&s<66,this.isWithoutDeviceMotion=c(),this.filterToWorldQ=new z,o()?this.filterToWorldQ.setFromAxisAngle(new Q(1,0,0),Math.PI/2):this.filterToWorldQ.setFromAxisAngle(new Q(1,0,0),-Math.PI/2),this.inverseWorldToScreenQ=new z,this.worldToScreenQ=new z,this.originalPoseAdjustQ=new z,this.originalPoseAdjustQ.setFromAxisAngle(new Q(0,0,1),-window.orientation*Math.PI/180),this.setScreenTransform_(),u()&&this.filterToWorldQ.multiply(this.inverseWorldToScreenQ),this.resetQ=new z,this.orientationOut_=new Float32Array(4),this.start()}Y.prototype.getDeviceParams=function(){return this.deviceParams},Y.prototype.recalculateDeviceParams_=function(){var e=this.calcDeviceParams_();e?(this.deviceParams=e,this.onDeviceParamsUpdated&&this.onDeviceParamsUpdated(this.deviceParams)):console.error("Failed to recalculate device parameters.")},Y.prototype.calcDeviceParams_=function(){var e=this.dpdb;if(!e)return console.error("DPDB not available."),null;if(1!=e.format)return console.error("DPDB has unexpected format version."),null;if(!e.devices||!e.devices.length)return console.error("DPDB does not have a devices section."),null;var t=navigator.userAgent||navigator.vendor||window.opera,i=p(),r=f();if(!e.devices)return console.error("DPDB has no devices section."),null;for(var s=0;s1)&&this.run_(),this.previousGyroMeasurement.copy(this.currentGyroMeasurement)},K.prototype.run_=function(){if(!this.isOrientationInitialized)return this.accelQ=this.accelToQuaternion_(this.currentAccelMeasurement.sample),this.previousFilterQ.copy(this.accelQ),void(this.isOrientationInitialized=!0);var e=this.currentGyroMeasurement.timestampS-this.previousGyroMeasurement.timestampS,t=this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample,e);this.gyroIntegralQ.multiply(t),this.filterQ.copy(this.previousFilterQ),this.filterQ.multiply(t);var i=new z;i.copy(this.filterQ),i.inverse(),this.estimatedGravity.set(0,0,-1),this.estimatedGravity.applyQuaternion(i),this.estimatedGravity.normalize(),this.measuredGravity.copy(this.currentAccelMeasurement.sample),this.measuredGravity.normalize();var r,s=new z;s.setFromUnitVectors(this.estimatedGravity,this.measuredGravity),s.inverse(),this.isDebug&&console.log("Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)",N*((r=s).w>1?(console.warn("getQuaternionAngle: w > 1"),0):2*Math.acos(r.w)),this.estimatedGravity.x.toFixed(1),this.estimatedGravity.y.toFixed(1),this.estimatedGravity.z.toFixed(1),this.measuredGravity.x.toFixed(1),this.measuredGravity.y.toFixed(1),this.measuredGravity.z.toFixed(1));var n=new z;n.copy(this.filterQ),n.multiply(s),this.filterQ.slerp(n,1-this.kFilter),this.previousFilterQ.copy(this.filterQ)},K.prototype.getOrientation=function(){return this.filterQ},K.prototype.accelToQuaternion_=function(e){var t=new Q;t.copy(e),t.normalize();var i=new z;return i.setFromUnitVectors(new Q(0,0,-1),t),i.inverse(),i},K.prototype.gyroToQuaternionDelta_=function(e,t){var i=new z,r=new Q;return r.copy(e),r.normalize(),i.setFromAxisAngle(r,e.length()*t),i},$.prototype.getPrediction=function(e,t,i){if(!this.previousTimestampS)return this.previousQ.copy(e),this.previousTimestampS=i,e;var r=new Q;r.copy(t),r.normalize();var s=t.length();if(s<20*O)return this.isDebug&&console.log("Moving slowly, at %s deg/s: no prediction",(N*s).toFixed(1)),this.outQ.copy(e),this.previousQ.copy(e),this.outQ;var n=s*this.predictionTimeS;return this.deltaQ.setFromAxisAngle(r,n),this.outQ.copy(this.previousQ),this.outQ.multiply(this.deltaQ),this.previousQ.copy(e),this.previousTimestampS=i,this.outQ},ee.prototype.getPosition=function(){return null},ee.prototype.getOrientation=function(){var e=void 0;if(this.isWithoutDeviceMotion&&this._deviceOrientationQ){this.deviceOrientationFixQ=this.deviceOrientationFixQ||(r=(new z).setFromAxisAngle(new Q(0,0,-1),0),s=new z,-90===window.orientation?s.setFromAxisAngle(new Q(0,1,0),Math.PI/-2):s.setFromAxisAngle(new Q(0,1,0),Math.PI/2),r.multiply(s)),this.deviceOrientationFilterToWorldQ=this.deviceOrientationFilterToWorldQ||((i=new z).setFromAxisAngle(new Q(1,0,0),-Math.PI/2),i),e=this._deviceOrientationQ;var t=new z;return t.copy(e),t.multiply(this.deviceOrientationFilterToWorldQ),t.multiply(this.resetQ),t.multiply(this.worldToScreenQ),t.multiplyQuaternions(this.deviceOrientationFixQ,t),this.yawOnly&&(t.x=0,t.z=0,t.normalize()),this.orientationOut_[0]=t.x,this.orientationOut_[1]=t.y,this.orientationOut_[2]=t.z,this.orientationOut_[3]=t.w,this.orientationOut_}var i,r,s,n=this.filter.getOrientation();e=this.posePredictor.getPrediction(n,this.gyroscope,this.previousTimestampS);var t=new z;return t.copy(this.filterToWorldQ),t.multiply(this.resetQ),t.multiply(e),t.multiply(this.worldToScreenQ),this.yawOnly&&(t.x=0,t.z=0,t.normalize()),this.orientationOut_[0]=t.x,this.orientationOut_[1]=t.y,this.orientationOut_[2]=t.z,this.orientationOut_[3]=t.w,this.orientationOut_},ee.prototype.resetPose=function(){this.resetQ.copy(this.filter.getOrientation()),this.resetQ.x=0,this.resetQ.y=0,this.resetQ.z*=-1,this.resetQ.normalize(),u()&&this.resetQ.multiply(this.inverseWorldToScreenQ),this.resetQ.multiply(this.originalPoseAdjustQ)},ee.prototype.onDeviceOrientation_=function(e){this._deviceOrientationQ=this._deviceOrientationQ||new z;var t=e.alpha,i=e.beta,r=e.gamma;t=(t||0)*Math.PI/180,i=(i||0)*Math.PI/180,r=(r||0)*Math.PI/180,this._deviceOrientationQ.setFromEulerYXZ(i,t,-r)},ee.prototype.onDeviceMotion_=function(e){this.updateDeviceMotion_(e)},ee.prototype.updateDeviceMotion_=function(e){var t=e.accelerationIncludingGravity,i=e.rotationRate,r=e.timeStamp/1e3,s=r-this.previousTimestampS;return s<0?(M("fusion-pose-sensor:invalid:non-monotonic","Invalid timestamps detected: non-monotonic timestamp from devicemotion"),void(this.previousTimestampS=r)):s<=.001||s>1?(M("fusion-pose-sensor:invalid:outside-threshold","Invalid timestamps detected: Timestamp from devicemotion outside expected range."),void(this.previousTimestampS=r)):(this.accelerometer.set(-t.x,-t.y,-t.z),d()?this.gyroscope.set(-i.beta,i.alpha,i.gamma):this.gyroscope.set(i.alpha,i.beta,i.gamma),this.isDeviceMotionInRadians||this.gyroscope.multiplyScalar(Math.PI/180),this.filter.addAccelMeasurement(this.accelerometer,r),this.filter.addGyroMeasurement(this.gyroscope,r),void(this.previousTimestampS=r))},ee.prototype.onOrientationChange_=function(e){this.setScreenTransform_()},ee.prototype.onMessage_=function(e){var t=e.data;if(t&&t.type){var i=t.type.toLowerCase();"devicemotion"===i&&this.updateDeviceMotion_(t.deviceMotionEvent)}},ee.prototype.setScreenTransform_=function(){switch(this.worldToScreenQ.set(0,0,0,1),window.orientation){case 0:break;case 90:this.worldToScreenQ.setFromAxisAngle(new Q(0,0,1),-Math.PI/2);break;case-90:this.worldToScreenQ.setFromAxisAngle(new Q(0,0,1),Math.PI/2)}this.inverseWorldToScreenQ.copy(this.worldToScreenQ),this.inverseWorldToScreenQ.inverse()},ee.prototype.start=function(){var e,t,i;this.onDeviceMotionCallback_=this.onDeviceMotion_.bind(this),this.onOrientationChangeCallback_=this.onOrientationChange_.bind(this),this.onMessageCallback_=this.onMessage_.bind(this),this.onDeviceOrientationCallback_=this.onDeviceOrientation_.bind(this),o()&&(e=window.self!==window.top,t=S(document.referrer),i=S(window.location.href),e&&t!==i)&&window.addEventListener("message",this.onMessageCallback_),window.addEventListener("orientationchange",this.onOrientationChangeCallback_),this.isWithoutDeviceMotion?window.addEventListener("deviceorientation",this.onDeviceOrientationCallback_):window.addEventListener("devicemotion",this.onDeviceMotionCallback_)},ee.prototype.stop=function(){window.removeEventListener("devicemotion",this.onDeviceMotionCallback_),window.removeEventListener("deviceorientation",this.onDeviceOrientationCallback_),window.removeEventListener("orientationchange",this.onOrientationChangeCallback_),window.removeEventListener("message",this.onMessageCallback_)};var te=new Q(1,0,0),ie=new Q(0,0,1),re=new z;re.setFromAxisAngle(te,-Math.PI/2),re.multiply((new z).setFromAxisAngle(ie,Math.PI/2));var se=function(){function e(t){r(this,e),this.config=t,this.sensor=null,this.fusionSensor=null,this._out=new Float32Array(4),this.api=null,this.errors=[],this._sensorQ=new z,this._outQ=new z,this._onSensorRead=this._onSensorRead.bind(this),this._onSensorError=this._onSensorError.bind(this),this.init()}return s(e,[{key:"init",value:function(){var e=null;try{(e=new RelativeOrientationSensor({frequency:60,referenceFrame:"screen"})).addEventListener("error",this._onSensorError)}catch(e){this.errors.push(e),"SecurityError"===e.name?(console.error("Cannot construct sensors due to the Feature Policy"),console.warn('Attempting to fall back using "devicemotion"; however this will fail in the future without correct permissions.'),this.useDeviceMotion()):"ReferenceError"===e.name?this.useDeviceMotion():console.error(e)}e&&(this.api="sensor",this.sensor=e,this.sensor.addEventListener("reading",this._onSensorRead),this.sensor.start())}},{key:"useDeviceMotion",value:function(){this.api="devicemotion",this.fusionSensor=new ee(this.config.K_FILTER,this.config.PREDICTION_TIME_S,this.config.YAW_ONLY,this.config.DEBUG),this.sensor&&(this.sensor.removeEventListener("reading",this._onSensorRead),this.sensor.removeEventListener("error",this._onSensorError),this.sensor=null)}},{key:"getOrientation",value:function(){if(this.fusionSensor)return this.fusionSensor.getOrientation();if(!this.sensor||!this.sensor.quaternion)return this._out[0]=this._out[1]=this._out[2]=0,this._out[3]=1,this._out;var e=this.sensor.quaternion;this._sensorQ.set(e[0],e[1],e[2],e[3]);var t=this._outQ;return t.copy(re),t.multiply(this._sensorQ),this.config.YAW_ONLY&&(t.x=t.z=0,t.normalize()),this._out[0]=t.x,this._out[1]=t.y,this._out[2]=t.z,this._out[3]=t.w,this._out}},{key:"_onSensorError",value:function(e){this.errors.push(e.error),"NotAllowedError"===e.error.name?console.error("Permission to access sensor was denied"):"NotReadableError"===e.error.name?console.error("Sensor could not be read"):console.error(e.error),this.useDeviceMotion()}},{key:"_onSensorRead",value:function(){}}]),e}();function ne(){this.loadIcon_();var e=document.createElement("div"),t=e.style;t.position="fixed",t.top=0,t.right=0,t.bottom=0,t.left=0,t.backgroundColor="gray",t.fontFamily="sans-serif",t.zIndex=1e6;var i=document.createElement("img");i.src=this.icon;var t=i.style;t.marginLeft="25%",t.marginTop="25%",t.width="50%",e.appendChild(i);var r=document.createElement("div"),t=r.style;t.textAlign="center",t.fontSize="16px",t.lineHeight="24px",t.margin="24px 25%",t.width="50%",r.innerHTML="Place your phone into your Cardboard viewer.",e.appendChild(r);var s=document.createElement("div"),t=s.style;t.backgroundColor="#CFD8DC",t.position="fixed",t.bottom=0,t.width="100%",t.height="48px",t.padding="14px 24px",t.boxSizing="border-box",t.color="#656A6B",e.appendChild(s);var n=document.createElement("div");n.style.float="left",n.innerHTML="No Cardboard viewer?";var a=document.createElement("a");a.href="https://www.google.com/get/cardboard/get-cardboard/",a.innerHTML="get one",a.target="_blank";var t=a.style;t.float="right",t.fontWeight=600,t.textTransform="uppercase",t.borderLeft="1px solid gray",t.paddingLeft="24px",t.textDecoration="none",t.color="#656A6B",s.appendChild(n),s.appendChild(a),this.overlay=e,this.text=r,this.hide()}ne.prototype.show=function(e){e||this.overlay.parentElement?e&&(this.overlay.parentElement&&this.overlay.parentElement!=e&&this.overlay.parentElement.removeChild(this.overlay),e.appendChild(this.overlay)):document.body.appendChild(this.overlay),this.overlay.style.display="block";var t=this.overlay.querySelector("img"),i=t.style;u()?(i.width="20%",i.marginLeft="40%",i.marginTop="3%"):(i.width="50%",i.marginLeft="25%",i.marginTop="25%")},ne.prototype.hide=function(){this.overlay.style.display="none"},ne.prototype.showTemporarily=function(e,t){this.show(t),this.timer=setTimeout(this.hide.bind(this),e)},ne.prototype.disableShowTemporarily=function(){clearTimeout(this.timer)},ne.prototype.update=function(){this.disableShowTemporarily(),!u()&&w()?this.show():this.hide()},ne.prototype.loadIcon_=function(){this.icon="data:image/svg+xml,"+encodeURIComponent("")};var ae="CardboardV1",oe="WEBVR_CARDBOARD_VIEWER";function le(e){try{this.selectedKey=localStorage.getItem(oe)}catch(e){console.error("Failed to load viewer profile: %s",e)}this.selectedKey||(this.selectedKey=e||ae),this.dialog=this.createDialog_(W.Viewers),this.root=null,this.onChangeCallbacks_=[]}le.prototype.show=function(e){this.root=e,e.appendChild(this.dialog);var t=this.dialog.querySelector("#"+this.selectedKey);t.checked=!0,this.dialog.style.display="block"},le.prototype.hide=function(){this.root&&this.root.contains(this.dialog)&&this.root.removeChild(this.dialog),this.dialog.style.display="none"},le.prototype.getCurrentViewer=function(){return W.Viewers[this.selectedKey]},le.prototype.getSelectedKey_=function(){var e=this.dialog.querySelector("input[name=field]:checked");return e?e.id:null},le.prototype.onChange=function(e){this.onChangeCallbacks_.push(e)},le.prototype.fireOnChange_=function(e){for(var t=0;t.5&&(this.noSleepVideo.currentTime=Math.random())}.bind(this)))}return r(e,[{key:"enable",value:function(){n?(this.disable(),this.noSleepTimer=window.setInterval(function(){window.location.href="/",window.setTimeout(window.stop,0)},15e3)):this.noSleepVideo.play()}},{key:"disable",value:function(){n?this.noSleepTimer&&(window.clearInterval(this.noSleepTimer),this.noSleepTimer=null):this.noSleepVideo.pause()}}]),e}();e.exports=a},function(e,t,i){e.exports="data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA="}])},e.exports=i()}(he={exports:{}},he.exports),(Ae=he.exports)&&Ae.__esModule&&Object.prototype.hasOwnProperty.call(Ae,"default")?Ae.default:Ae),de=1e3,ue=[0,0,.5,1],pe=[.5,0,.5,1],fe=window.requestAnimationFrame,me=window.cancelAnimationFrame;function ge(e){Object.defineProperties(this,{hasPosition:{writable:!1,enumerable:!0,value:e.hasPosition},hasExternalDisplay:{writable:!1,enumerable:!0,value:e.hasExternalDisplay},canPresent:{writable:!1,enumerable:!0,value:e.canPresent},maxLayers:{writable:!1,enumerable:!0,value:e.maxLayers},hasOrientation:{enumerable:!0,get:function(){return x("VRDisplayCapabilities.prototype.hasOrientation","VRDisplay.prototype.getFrameData"),e.hasOrientation}}})}function ve(e){var t=!("wakelock"in(e=e||{}))||e.wakelock;this.isPolyfilled=!0,this.displayId=de++,this.displayName="",this.depthNear=.01,this.depthFar=1e4,this.isPresenting=!1,Object.defineProperty(this,"isConnected",{get:function(){return x("VRDisplay.prototype.isConnected","VRDisplayCapabilities.prototype.hasExternalDisplay"),!1}}),this.capabilities=new ge({hasPosition:!1,hasOrientation:!1,hasExternalDisplay:!1,canPresent:!1,maxLayers:1}),this.stageParameters=null,this.waitingForPresent_=!1,this.layer_=null,this.originalParent_=null,this.fullscreenElement_=null,this.fullscreenWrapper_=null,this.fullscreenElementCachedStyle_=null,this.fullscreenEventTarget_=null,this.fullscreenChangeHandler_=null,this.fullscreenErrorHandler_=null,t&&w()&&(this.wakelock_=new ce)}ve.prototype.getFrameData=function(e){return E(e,this._getPose(),this)},ve.prototype.getPose=function(){return x("VRDisplay.prototype.getPose","VRDisplay.prototype.getFrameData"),this._getPose()},ve.prototype.resetPose=function(){return x("VRDisplay.prototype.resetPose"),this._resetPose()},ve.prototype.getImmediatePose=function(){return x("VRDisplay.prototype.getImmediatePose","VRDisplay.prototype.getFrameData"),this._getPose()},ve.prototype.requestAnimationFrame=function(e){return fe(e)},ve.prototype.cancelAnimationFrame=function(e){return me(e)},ve.prototype.wrapForFullscreen=function(e){if(o())return e;if(!this.fullscreenWrapper_){this.fullscreenWrapper_=document.createElement("div");var t=["height: "+Math.min(screen.height,screen.width)+"px !important","top: 0 !important","left: 0 !important","right: 0 !important","border: 0","margin: 0","padding: 0","z-index: 999999 !important","position: fixed"];this.fullscreenWrapper_.setAttribute("style",t.join("; ")+";"),this.fullscreenWrapper_.classList.add("webvr-polyfill-fullscreen-wrapper")}if(this.fullscreenElement_==e)return this.fullscreenWrapper_;if(this.fullscreenElement_&&(this.originalParent_?this.originalParent_.appendChild(this.fullscreenElement_):this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_)),this.fullscreenElement_=e,this.originalParent_=e.parentElement,this.originalParent_||document.body.appendChild(e),!this.fullscreenWrapper_.parentElement){var i=this.fullscreenElement_.parentElement;i.insertBefore(this.fullscreenWrapper_,this.fullscreenElement_),i.removeChild(this.fullscreenElement_)}this.fullscreenWrapper_.insertBefore(this.fullscreenElement_,this.fullscreenWrapper_.firstChild),this.fullscreenElementCachedStyle_=this.fullscreenElement_.getAttribute("style");var r=this;return function(){if(r.fullscreenElement_){var e=["position: absolute","top: 0","left: 0","width: "+Math.max(screen.width,screen.height)+"px","height: "+Math.min(screen.height,screen.width)+"px","border: 0","margin: 0","padding: 0"];r.fullscreenElement_.setAttribute("style",e.join("; ")+";")}}(),this.fullscreenWrapper_},ve.prototype.removeFullscreenWrapper=function(){if(this.fullscreenElement_){var e=this.fullscreenElement_;this.fullscreenElementCachedStyle_?e.setAttribute("style",this.fullscreenElementCachedStyle_):e.removeAttribute("style"),this.fullscreenElement_=null,this.fullscreenElementCachedStyle_=null;var t=this.fullscreenWrapper_.parentElement;return this.fullscreenWrapper_.removeChild(e),this.originalParent_===t?t.insertBefore(e,this.fullscreenWrapper_):this.originalParent_&&this.originalParent_.appendChild(e),t.removeChild(this.fullscreenWrapper_),e}},ve.prototype.requestPresent=function(e){var t=this.isPresenting,i=this;return e instanceof Array||(x("VRDisplay.prototype.requestPresent with non-array argument","an array of VRLayers as the first argument"),e=[e]),new Promise(function(r,s){if(i.capabilities.canPresent)if(0==e.length||e.length>i.capabilities.maxLayers)s(new Error("Invalid number of layers."));else{var n=e[0];if(n.source){var a=n.leftBounds||ue,A=n.rightBounds||pe;if(t){var h=i.layer_;h.source!==n.source&&(h.source=n.source);for(var c=0;c<4;c++)h.leftBounds[c]=a[c],h.rightBounds[c]=A[c];return i.wrapForFullscreen(i.layer_.source),i.updatePresent_(),void r()}if(i.layer_={predistorted:n.predistorted,source:n.source,leftBounds:a.slice(0),rightBounds:A.slice(0)},i.waitingForPresent_=!1,i.layer_&&i.layer_.source){var d=i.wrapForFullscreen(i.layer_.source);i.addFullscreenListeners_(d,function(){var e=document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement;i.isPresenting=d===e,i.isPresenting?(screen.orientation&&screen.orientation.lock&&screen.orientation.lock("landscape-primary").catch(function(e){console.error("screen.orientation.lock() failed due to",e.message)}),i.waitingForPresent_=!1,i.beginPresent_(),r()):(screen.orientation&&screen.orientation.unlock&&screen.orientation.unlock(),i.removeFullscreenWrapper(),i.disableWakeLock(),i.endPresent_(),i.removeFullscreenListeners_()),i.fireVRDisplayPresentChange_()},function(){i.waitingForPresent_&&(i.removeFullscreenWrapper(),i.removeFullscreenListeners_(),i.disableWakeLock(),i.waitingForPresent_=!1,i.isPresenting=!1,s(new Error("Unable to present.")))}),function(e){if(l())return!1;if(e.requestFullscreen)e.requestFullscreen();else if(e.webkitRequestFullscreen)e.webkitRequestFullscreen();else if(e.mozRequestFullScreen)e.mozRequestFullScreen();else{if(!e.msRequestFullscreen)return!1;e.msRequestFullscreen()}return!0}(d)?(i.enableWakeLock(),i.waitingForPresent_=!0):(o()||l())&&(i.enableWakeLock(),i.isPresenting=!0,i.beginPresent_(),i.fireVRDisplayPresentChange_(),r())}i.waitingForPresent_||o()||(m(),s(new Error("Unable to present.")))}else r()}else s(new Error("VRDisplay is not capable of presenting."))})},ve.prototype.exitPresent=function(){var e=this.isPresenting,t=this;return this.isPresenting=!1,this.layer_=null,this.disableWakeLock(),new Promise(function(i,r){e?(!m()&&o()&&(t.endPresent_(),t.fireVRDisplayPresentChange_()),l()&&(t.removeFullscreenWrapper(),t.removeFullscreenListeners_(),t.endPresent_(),t.fireVRDisplayPresentChange_()),i()):r(new Error("Was not presenting to VRDisplay."))})},ve.prototype.getLayers=function(){return this.layer_?[this.layer_]:[]},ve.prototype.fireVRDisplayPresentChange_=function(){var e=new CustomEvent("vrdisplaypresentchange",{detail:{display:this}});window.dispatchEvent(e)},ve.prototype.fireVRDisplayConnect_=function(){var e=new CustomEvent("vrdisplayconnect",{detail:{display:this}});window.dispatchEvent(e)},ve.prototype.addFullscreenListeners_=function(e,t,i){this.removeFullscreenListeners_(),this.fullscreenEventTarget_=e,this.fullscreenChangeHandler_=t,this.fullscreenErrorHandler_=i,t&&(document.fullscreenEnabled?e.addEventListener("fullscreenchange",t,!1):document.webkitFullscreenEnabled?e.addEventListener("webkitfullscreenchange",t,!1):document.mozFullScreenEnabled?document.addEventListener("mozfullscreenchange",t,!1):document.msFullscreenEnabled&&e.addEventListener("msfullscreenchange",t,!1)),i&&(document.fullscreenEnabled?e.addEventListener("fullscreenerror",i,!1):document.webkitFullscreenEnabled?e.addEventListener("webkitfullscreenerror",i,!1):document.mozFullScreenEnabled?document.addEventListener("mozfullscreenerror",i,!1):document.msFullscreenEnabled&&e.addEventListener("msfullscreenerror",i,!1))},ve.prototype.removeFullscreenListeners_=function(){if(this.fullscreenEventTarget_){var e=this.fullscreenEventTarget_;if(this.fullscreenChangeHandler_){var t=this.fullscreenChangeHandler_;e.removeEventListener("fullscreenchange",t,!1),e.removeEventListener("webkitfullscreenchange",t,!1),document.removeEventListener("mozfullscreenchange",t,!1),e.removeEventListener("msfullscreenchange",t,!1)}if(this.fullscreenErrorHandler_){var i=this.fullscreenErrorHandler_;e.removeEventListener("fullscreenerror",i,!1),e.removeEventListener("webkitfullscreenerror",i,!1),document.removeEventListener("mozfullscreenerror",i,!1),e.removeEventListener("msfullscreenerror",i,!1)}this.fullscreenEventTarget_=null,this.fullscreenChangeHandler_=null,this.fullscreenErrorHandler_=null}},ve.prototype.enableWakeLock=function(){this.wakelock_&&this.wakelock_.enable()},ve.prototype.disableWakeLock=function(){this.wakelock_&&this.wakelock_.disable()},ve.prototype.beginPresent_=function(){},ve.prototype.endPresent_=function(){},ve.prototype.submitFrame=function(e){},ve.prototype.getEyeParameters=function(e){return null};var we={ADDITIONAL_VIEWERS:[],DEFAULT_VIEWER:"",MOBILE_WAKE_LOCK:!0,DEBUG:!1,DPDB_URL:"https://dpdb.webvr.rocks/dpdb.json",K_FILTER:.98,PREDICTION_TIME_S:.04,CARDBOARD_UI_DISABLED:!1,ROTATE_INSTRUCTIONS_DISABLED:!1,YAW_ONLY:!1,BUFFER_SCALE:.5,DIRTY_SUBMIT_FRAME_BINDINGS:!1},ye={LEFT:"left",RIGHT:"right"};function be(e){var t=y({},we);e=y(t,e||{}),ve.call(this,{wakelock:e.MOBILE_WAKE_LOCK}),this.config=e,this.displayName="Cardboard VRDisplay",this.capabilities=new ge({hasPosition:!1,hasOrientation:!0,hasExternalDisplay:!1,canPresent:!0,maxLayers:1}),this.stageParameters=null,this.bufferScale_=this.config.BUFFER_SCALE,this.poseSensor_=new se(this.config),this.distorter_=null,this.cardboardUI_=null,this.dpdb_=new Y(this.config.DPDB_URL,this.onDeviceParamsUpdated_.bind(this)),this.deviceInfo_=new W(this.dpdb_.getDeviceParams(),e.ADDITIONAL_VIEWERS),this.viewerSelector_=new le(e.DEFAULT_VIEWER),this.viewerSelector_.onChange(this.onViewerChanged_.bind(this)),this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer()),this.config.ROTATE_INSTRUCTIONS_DISABLED||(this.rotateInstructions_=new ne),o()&&window.addEventListener("resize",this.onResize_.bind(this))}return be.prototype=Object.create(ve.prototype),be.prototype._getPose=function(){return{position:null,orientation:this.poseSensor_.getOrientation(),linearVelocity:null,linearAcceleration:null,angularVelocity:null,angularAcceleration:null}},be.prototype._resetPose=function(){this.poseSensor_.resetPose&&this.poseSensor_.resetPose()},be.prototype._getFieldOfView=function(e){var t;if(e==ye.LEFT)t=this.deviceInfo_.getFieldOfViewLeftEye();else{if(e!=ye.RIGHT)return console.error("Invalid eye provided: %s",e),null;t=this.deviceInfo_.getFieldOfViewRightEye()}return t},be.prototype._getEyeOffset=function(e){var t;if(e==ye.LEFT)t=[.5*-this.deviceInfo_.viewer.interLensDistance,0,0];else{if(e!=ye.RIGHT)return console.error("Invalid eye provided: %s",e),null;t=[.5*this.deviceInfo_.viewer.interLensDistance,0,0]}return t},be.prototype.getEyeParameters=function(e){var t=this._getEyeOffset(e),i=this._getFieldOfView(e),r={offset:t,renderWidth:.5*this.deviceInfo_.device.width*this.bufferScale_,renderHeight:this.deviceInfo_.device.height*this.bufferScale_};return Object.defineProperty(r,"fieldOfView",{enumerable:!0,get:function(){return x("VRFieldOfView","VRFrameData's projection matrices"),i}}),r},be.prototype.onDeviceParamsUpdated_=function(e){this.config.DEBUG&&console.log("DPDB reported that device params were updated."),this.deviceInfo_.updateDeviceParams(e),this.distorter_&&this.distorter_.updateDeviceInfo(this.deviceInfo_)},be.prototype.updateBounds_=function(){this.layer_&&this.distorter_&&(this.layer_.leftBounds||this.layer_.rightBounds)&&this.distorter_.setTextureBounds(this.layer_.leftBounds,this.layer_.rightBounds)},be.prototype.beginPresent_=function(){var e=this.layer_.source.getContext("webgl");e||(e=this.layer_.source.getContext("experimental-webgl")),e||(e=this.layer_.source.getContext("webgl2")),e&&(this.layer_.predistorted?this.config.CARDBOARD_UI_DISABLED||(e.canvas.width=p()*this.bufferScale_,e.canvas.height=f()*this.bufferScale_,this.cardboardUI_=new I(e)):(this.config.CARDBOARD_UI_DISABLED||(this.cardboardUI_=new I(e)),this.distorter_=new T(e,this.cardboardUI_,this.config.BUFFER_SCALE,this.config.DIRTY_SUBMIT_FRAME_BINDINGS),this.distorter_.updateDeviceInfo(this.deviceInfo_)),this.cardboardUI_&&this.cardboardUI_.listen(function(e){this.viewerSelector_.show(this.layer_.source.parentElement),e.stopPropagation(),e.preventDefault()}.bind(this),function(e){this.exitPresent(),e.stopPropagation(),e.preventDefault()}.bind(this)),this.rotateInstructions_&&(u()&&w()?this.rotateInstructions_.showTemporarily(3e3,this.layer_.source.parentElement):this.rotateInstructions_.update()),this.orientationHandler=this.onOrientationChange_.bind(this),window.addEventListener("orientationchange",this.orientationHandler),this.vrdisplaypresentchangeHandler=this.updateBounds_.bind(this),window.addEventListener("vrdisplaypresentchange",this.vrdisplaypresentchangeHandler),this.fireVRDisplayDeviceParamsChange_())},be.prototype.endPresent_=function(){this.distorter_&&(this.distorter_.destroy(),this.distorter_=null),this.cardboardUI_&&(this.cardboardUI_.destroy(),this.cardboardUI_=null),this.rotateInstructions_&&this.rotateInstructions_.hide(),this.viewerSelector_.hide(),window.removeEventListener("orientationchange",this.orientationHandler),window.removeEventListener("vrdisplaypresentchange",this.vrdisplaypresentchangeHandler)},be.prototype.updatePresent_=function(){this.endPresent_(),this.beginPresent_()},be.prototype.submitFrame=function(e){if(this.distorter_)this.updateBounds_(),this.distorter_.submitFrame();else if(this.cardboardUI_&&this.layer_){var t=this.layer_.source.getContext("webgl").canvas;t.width==this.lastWidth&&t.height==this.lastHeight||this.cardboardUI_.onResize(),this.lastWidth=t.width,this.lastHeight=t.height,this.cardboardUI_.render()}},be.prototype.onOrientationChange_=function(e){this.viewerSelector_.hide(),this.rotateInstructions_&&this.rotateInstructions_.update(),this.onResize_()},be.prototype.onResize_=function(e){if(this.layer_){var t=this.layer_.source.getContext("webgl");t.canvas.setAttribute("style",["position: absolute","top: 0","left: 0","width: 100vw","height: 100vh","border: 0","margin: 0","padding: 0px","box-sizing: content-box"].join("; ")+";"),b(t.canvas)}},be.prototype.onViewerChanged_=function(e){this.deviceInfo_.setViewer(e),this.distorter_&&this.distorter_.updateDeviceInfo(this.deviceInfo_),this.fireVRDisplayDeviceParamsChange_()},be.prototype.fireVRDisplayDeviceParamsChange_=function(){var e=new CustomEvent("vrdisplaydeviceparamschange",{detail:{vrdisplay:this,deviceInfo:this.deviceInfo_}});window.dispatchEvent(e)},be.VRFrameData=function(){this.leftProjectionMatrix=new Float32Array(16),this.leftViewMatrix=new Float32Array(16),this.rightProjectionMatrix=new Float32Array(16),this.rightViewMatrix=new Float32Array(16),this.pose=null},be.VRDisplay=ve,be}()}(De={exports:{}},De.exports),De.exports),Le=(Pe=Ie)&&Pe.__esModule&&Object.prototype.hasOwnProperty.call(Pe,"default")?Pe.default:Pe;class Oe extends i{constructor(e){super(),this.global=e,this.onWindowResize=this.onWindowResize.bind(this),this.global.window.addEventListener("resize",this.onWindowResize),this.environmentBlendMode="opaque"}onBaseLayerSet(e,t){throw new Error("Not implemented")}isSessionSupported(e){throw new Error("Not implemented")}isFeatureSupported(e){throw new Error("Not implemented")}async requestSession(e,t){throw new Error("Not implemented")}requestAnimationFrame(e){throw new Error("Not implemented")}onFrameStart(e){throw new Error("Not implemented")}onFrameEnd(e){throw new Error("Not implemented")}doesSessionSupportReferenceSpace(e,t){throw new Error("Not implemented")}requestStageBounds(){throw new Error("Not implemented")}async requestFrameOfReferenceTransform(e,t){}cancelAnimationFrame(e){throw new Error("Not implemented")}endSession(e){throw new Error("Not implemented")}getViewport(e,t,i,r){throw new Error("Not implemented")}getProjectionMatrix(e){throw new Error("Not implemented")}getBasePoseMatrix(){throw new Error("Not implemented")}getBaseViewMatrix(e){throw new Error("Not implemented")}getInputSources(){throw new Error("Not implemented")}getInputPose(e,t,i){throw new Error("Not implemented")}onWindowResize(){this.onWindowResize()}}let Ne={mapping:"xr-standard",profiles:["oculus-go","generic-trigger-touchpad"],buttons:{length:3,0:1,1:null,2:0},gripTransform:{orientation:[.11*Math.PI,0,0,1]}},Qe={mapping:"xr-standard",displayProfiles:{"Oculus Quest":["oculus-touch-v2","oculus-touch","generic-trigger-squeeze-thumbstick"]},profiles:["oculus-touch","generic-trigger-squeeze-thumbstick"],axes:{length:4,0:null,1:null,2:0,3:1},buttons:{length:7,0:1,1:2,2:null,3:0,4:3,5:4,6:null},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Ge={mapping:"xr-standard",profiles:["htc-vive","generic-trigger-squeeze-touchpad"],displayProfiles:{"HTC Vive":["htc-vive","generic-trigger-squeeze-touchpad"],"HTC Vive DVT":["htc-vive","generic-trigger-squeeze-touchpad"],"Valve Index":["valve-index","generic-trigger-squeeze-touchpad-thumbstick"]},buttons:{length:3,0:1,1:2,2:0},gripTransform:{position:[0,0,.05,1]},targetRayTransform:{orientation:[-.08*Math.PI,0,0,1]},userAgentOverrides:{Firefox:{axes:{invert:[1,3]}}}},ke={mapping:"xr-standard",profiles:["samsung-gearvr","generic-trigger-touchpad"],buttons:{length:3,0:1,1:null,2:0},gripTransform:{orientation:[.11*Math.PI,0,0,1]}},ze={mapping:"xr-standard",profiles:["samsung-odyssey","microsoft-mixed-reality","generic-trigger-squeeze-touchpad-thumbstick"],buttons:{length:4,0:1,1:0,2:2,3:4},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Ve={mapping:"xr-standard",profiles:["microsoft-mixed-reality","generic-trigger-squeeze-touchpad-thumbstick"],buttons:{length:4,0:1,1:0,2:2,3:4},gripTransform:{position:[0,-.02,.04,1],orientation:[.11*Math.PI,0,0,1]}},Ue={"Daydream Controller":{mapping:"",profiles:["google-daydream","generic-trigger-touchpad"],buttons:{length:3,0:null,1:null,2:0}},"Gear VR Controller":ke,"HTC Vive Focus Controller":{mapping:"xr-standard",profiles:["htc-vive-focus","generic-trigger-touchpad"],buttons:{length:3,0:1,1:null,2:0}},"Oculus Go Controller":Ne,"Oculus Touch (Right)":Qe,"Oculus Touch (Left)":Qe,"OpenVR Gamepad":Ge,"Spatial Controller (Spatial Interaction Source) 045E-065A":Ve,"Spatial Controller (Spatial Interaction Source) 045E-065D":ze,"Windows Mixed Reality (Right)":Ve,"Windows Mixed Reality (Left)":Ve};const He=f(.155,-.465,-.15),Xe=f(-.155,-.465,-.15),We=f(0,0,-.25),je=f(0,0,.05),qe=f(-.08,.14,.08),Ye=.4,Ze=.4,Je=.61,Ke=.175,$e=.12,et=.87,tt=180/Math.PI;class it{constructor(){this.hand="right",this.headElbowOffset=He,this.controllerQ=M(),this.lastControllerQ=M(),this.headQ=M(),this.headPos=u(),this.elbowPos=u(),this.wristPos=u(),this.time=null,this.lastTime=null,this.rootQ=M(),this.position=u()}setHandedness(e){this.hand!=e&&(this.hand=e,"left"==this.hand?this.headElbowOffset=Xe:this.headElbowOffset=He)}update(e,t){this.time=X(),e&&(B(this.lastControllerQ,this.controllerQ),B(this.controllerQ,e)),t&&(h(this.headPos,t),c(this.headQ,t));let i=this.getHeadYawOrientation_(),r=this.quatAngle_(this.lastControllerQ,this.controllerQ);r/((this.time-this.lastTime)/1e3)>Je?_(this.rootQ,this.rootQ,i,Math.min(r/Ke,1)):B(this.rootQ,i);let s=f(0,0,-1);E(s,s,this.controllerQ);let n=y(s,[0,1,0]),a=this.clamp_((n-$e)/et,0,1),o=R(this.rootQ);F(o,o),x(o,o,this.controllerQ);let l=this.elbowPos;m(l,this.headPos),g(l,l,this.headElbowOffset);let A=p(qe);v(A,A,a),g(l,l,A);let d=this.quatAngle_(o,M())*tt,u=(1-Math.pow(d/180,4))*(Ye+(1-Ye)*a*Ze),w=M();_(w,w,o,u);let b=F(M(),w),S=R(o);x(S,S,b);let T=this.wristPos;m(T,je),E(T,T,w),g(T,T,We),E(T,T,S),g(T,T,l);let C=p(qe);v(C,C,a),g(this.position,this.wristPos,C),E(this.position,this.position,this.rootQ),this.lastTime=this.time}getPosition(){return this.position}getHeadYawOrientation_(){let e=u();return function(e,t,i){function r(e,t,i){return ei?i:e}var s=t[0]*t[0],n=t[1]*t[1],a=t[2]*t[2],o=t[3]*t[3];if("XYZ"===i)e[0]=Math.atan2(2*(t[0]*t[3]-t[1]*t[2]),o-s-n+a),e[1]=Math.asin(r(2*(t[0]*t[2]+t[1]*t[3]),-1,1)),e[2]=Math.atan2(2*(t[2]*t[3]-t[0]*t[1]),o+s-n-a);else if("YXZ"===i)e[0]=Math.asin(r(2*(t[0]*t[3]-t[1]*t[2]),-1,1)),e[1]=Math.atan2(2*(t[0]*t[2]+t[1]*t[3]),o-s-n+a),e[2]=Math.atan2(2*(t[0]*t[1]+t[2]*t[3]),o-s+n-a);else if("ZXY"===i)e[0]=Math.asin(r(2*(t[0]*t[3]+t[1]*t[2]),-1,1)),e[1]=Math.atan2(2*(t[1]*t[3]-t[2]*t[0]),o-s-n+a),e[2]=Math.atan2(2*(t[2]*t[3]-t[0]*t[1]),o-s+n-a);else if("ZYX"===i)e[0]=Math.atan2(2*(t[0]*t[3]+t[2]*t[1]),o-s-n+a),e[1]=Math.asin(r(2*(t[1]*t[3]-t[0]*t[2]),-1,1)),e[2]=Math.atan2(2*(t[0]*t[1]+t[2]*t[3]),o+s-n-a);else if("YZX"===i)e[0]=Math.atan2(2*(t[0]*t[3]-t[2]*t[1]),o-s+n-a),e[1]=Math.atan2(2*(t[1]*t[3]-t[0]*t[2]),o+s-n-a),e[2]=Math.asin(r(2*(t[0]*t[1]+t[2]*t[3]),-1,1));else{if("XZY"!==i)return void console.log("No order given for quaternion to euler conversion.");e[0]=Math.atan2(2*(t[0]*t[3]+t[1]*t[2]),o-s+n-a),e[1]=Math.atan2(2*(t[0]*t[2]+t[1]*t[3]),o+s-n-a),e[2]=Math.asin(r(2*(t[2]*t[3]-t[0]*t[1]),-1,1))}}(e,this.headQ,"YXZ"),function(e,t,i,r){let s=.5*Math.PI/180;t*=s,i*=s,r*=s;let n=Math.sin(t),a=Math.cos(t),o=Math.sin(i),l=Math.cos(i),A=Math.sin(r),h=Math.cos(r);return e[0]=n*l*h-a*o*A,e[1]=a*o*h+n*l*A,e[2]=a*l*A-n*o*h,e[3]=a*l*h+n*o*A,e}(M(),0,e[1]*tt,0)}clamp_(e,t,i){return Math.min(Math.max(e,t),i)}quatAngle_(e,t){let i=[0,0,-1],r=[0,0,-1];return E(i,i,e),E(r,r,t),function(e,t){let i=f(e[0],e[1],e[2]),r=f(t[0],t[1],t[2]);w(i,i),w(r,r);let s=y(i,r);return s>1?0:s<-1?Math.PI:Math.acos(s)}(i,r)}}const rt=Symbol("@@webxr-polyfill/XRRemappedGamepad"),st={pressed:!1,touched:!1,value:0};Object.freeze(st);class nt{constructor(e,t,i){if(i||(i={}),i.userAgentOverrides)for(let e in i.userAgentOverrides)if(navigator.userAgent.includes(e)){let t=i.userAgentOverrides[e];for(let e in t)e in i?Object.assign(i[e],t[e]):i[e]=t[e];break}let r=new Array(i.axes&&i.axes.length?i.axes.length:e.axes.length),s=new Array(i.buttons&&i.buttons.length?i.buttons.length:e.buttons.length),a=null;if(i.gripTransform){let e=i.gripTransform.orientation||[0,0,0,1];A(a=n(),C(e,e),i.gripTransform.position||[0,0,0])}let o=null;if(i.targetRayTransform){let e=i.targetRayTransform.orientation||[0,0,0,1];A(o=n(),C(e,e),i.targetRayTransform.position||[0,0,0])}let l=i.profiles;i.displayProfiles&&t.displayName in i.displayProfiles&&(l=i.displayProfiles[t.displayName]),this[rt]={gamepad:e,map:i,profiles:l||[e.id],mapping:i.mapping||e.mapping,axes:r,buttons:s,gripTransform:a,targetRayTransform:o},this._update()}_update(){let e=this[rt].gamepad,t=this[rt].map,i=this[rt].axes;for(let r=0;r{ot||this.global.document.body.contains(r)||(i.modifiedCanvasLayer=!0,this.global.document.body.appendChild(r),Be(r)),i.baseLayer=t})}else i.baseLayer=t}isSessionSupported(e){return"immersive-ar"!=e&&("immersive-vr"!=e||!1!==this.canPresent)}isFeatureSupported(e){switch(e){case"viewer":case"local":case"local-floor":return!0;case"bounded":case"unbounded":default:return!1}}async requestSession(e,t){if(!this.isSessionSupported(e))return Promise.reject();let i="immersive-vr"==e;if(i){const e=this.global.document.createElement("canvas");if(!ot){e.getContext("webgl")}await this.display.requestPresent([{source:e,attributes:lt}])}const r=new ct(e,t,{renderContextType:this.HAS_BITMAP_SUPPORT?"bitmaprenderer":"2d"});return this.sessions.set(r.id,r),i&&(this.immersiveSession=r,this.dispatchEvent("@@webxr-polyfill/vr-present-start",r.id)),Promise.resolve(r.id)}requestAnimationFrame(e){return this.display.requestAnimationFrame(e)}getPrimaryButtonIndex(e){let t=0,i=e.id.toLowerCase();for(let e in At)if(i.includes(e)){t=At[e];break}return Math.min(t,e.buttons.length-1)}onFrameStart(e,t){this.display.depthNear=t.depthNear,this.display.depthFar=t.depthFar,this.display.getFrameData(this.frame);const i=this.sessions.get(e);if(i.immersive&&this.CAN_USE_GAMEPAD){let e=this.gamepadInputSources;this.gamepadInputSources={};let t=this.global.navigator.getGamepads();for(let r=0;r0){let t=e[r];if(t||(t=new at(this,this.display,this.getPrimaryButtonIndex(s))),t.updateFromGamepad(s),this.gamepadInputSources[r]=t,-1!=t.primaryButtonIndex){let e=s.buttons[t.primaryButtonIndex].pressed;e&&!t.primaryActionPressed?this.dispatchEvent("@@webxr-polyfill/input-select-start",{sessionId:i.id,inputSource:t.inputSource}):!e&&t.primaryActionPressed&&this.dispatchEvent("@@webxr-polyfill/input-select-end",{sessionId:i.id,inputSource:t.inputSource}),t.primaryActionPressed=e}if(-1!=t.primarySqueezeButtonIndex){let e=s.buttons[t.primarySqueezeButtonIndex].pressed;e&&!t.primarySqueezeActionPressed?this.dispatchEvent("@@webxr-polyfill/input-squeeze-start",{sessionId:i.id,inputSource:t.inputSource}):!e&&t.primarySqueezeActionPressed&&this.dispatchEvent("@@webxr-polyfill/input-squeeze-end",{sessionId:i.id,inputSource:t.inputSource}),t.primarySqueezeActionPressed=e}}}}if(!ot&&!i.immersive&&i.baseLayer){const e=i.baseLayer.context.canvas;d(this.frame.leftProjectionMatrix,t.inlineVerticalFieldOfView,e.width/e.height,t.depthNear,t.depthFar)}}onFrameEnd(e){const t=this.sessions.get(e);if(!t.ended&&t.baseLayer){if(t.outputContext&&(!t.immersive||this.display.capabilities.hasExternalDisplay)){const e=t.immersive&&this.display.capabilities.hasExternalDisplay,i=t.baseLayer.context.canvas,r=e?i.width/2:i.width,s=i.height;if(!ot){const e=t.outputContext.canvas,n=e.width,a=e.height,o=t.renderContext;this.HAS_BITMAP_SUPPORT?i.transferToImageBitmap?o.transferFromImageBitmap(i.transferToImageBitmap()):this.global.createImageBitmap(i,0,0,r,s,{resizeWidth:n,resizeHeight:a}).then(e=>o.transferFromImageBitmap(e)):o.drawImage(i,0,0,r,s,0,0,n,a)}}t.immersive&&t.baseLayer&&this.display.submitFrame()}}cancelAnimationFrame(e){this.display.cancelAnimationFrame(e)}async endSession(e){const t=this.sessions.get(e);if(!t.ended)return t.immersive?this.display.exitPresent():void(t.ended=!0)}doesSessionSupportReferenceSpace(e,t){const i=this.sessions.get(e);return!i.ended&&i.enabledFeatures.has(t)}requestStageBounds(){if(this.display.stageParameters){const e=this.display.stageParameters.sizeX,t=this.display.stageParameters.sizeZ,i=[];return i.push(-e/2),i.push(-t/2),i.push(e/2),i.push(-t/2),i.push(e/2),i.push(t/2),i.push(-e/2),i.push(t/2),i}return null}async requestFrameOfReferenceTransform(e,t){return("local-floor"===e||"bounded-floor"===e)&&this.display.stageParameters&&this.display.stageParameters.sittingToStandingTransform?this.display.stageParameters.sittingToStandingTransform:null}getProjectionMatrix(e){if("left"===e)return this.frame.leftProjectionMatrix;if("right"===e)return this.frame.rightProjectionMatrix;if("none"===e)return this.frame.leftProjectionMatrix;throw new Error("eye must be of type 'left' or 'right'")}getViewport(e,t,i,r){const s=this.sessions.get(e),{width:n,height:a}=i.context.canvas;if(!s.immersive)return r.x=r.y=0,r.width=n,r.height=a,!0;if("left"===t||"none"===t)r.x=0;else{if("right"!==t)return!1;r.x=n/2}return r.y=0,r.width=n/2,r.height=a,!0}getBasePoseMatrix(){let{position:e,orientation:t}=this.frame.pose;return e||t?(e||((e=this.tempVec3)[0]=e[1]=e[2]=0),A(this.baseModelMatrix,t,e),this.baseModelMatrix):this.baseModelMatrix}getBaseViewMatrix(e){if("left"===e||"none"===e)return this.frame.leftViewMatrix;if("right"===e)return this.frame.rightViewMatrix;throw new Error("eye must be of type 'left' or 'right'")}getInputSources(){let e=[];for(let t in this.gamepadInputSources)e.push(this.gamepadInputSources[t].inputSource);return e}getInputPose(e,t,i){if(!t)return null;for(let r in this.gamepadInputSources){let s=this.gamepadInputSources[r];if(s.inputSource===e)return s.getXRPose(t,i)}return null}onWindowResize(){}onVRDisplayPresentChange(e){this.display.isPresenting||this.sessions.forEach(e=>{if(e.immersive&&!e.ended){if(e.modifiedCanvasLayer){const t=e.baseLayer.context.canvas;document.body.removeChild(t),t.setAttribute("style","")}this.immersiveSession===e&&(this.immersiveSession=null),this.dispatchEvent("@@webxr-polyfill/vr-present-end",e.id)}})}}const ut=!1;let pt=0;class ft{constructor(e,t){this.mode=e,this.enabledFeatures=t,this.ended=null,this.baseLayer=null,this.id=++pt}}const mt=async function(e,t){if(t.webvr){let t=await async function(e){let t=null;if("getVRDisplays"in e.navigator)try{const i=await e.navigator.getVRDisplays();i&&i.length&&(t=new dt(e,i[0]))}catch(e){}return t}(e);if(t)return t}let i=(e=>{var t=!1;return Te=e.navigator.userAgent||e.navigator.vendor||e.opera,(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(Te)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(Te.substr(0,4)))&&(t=!0),t})(e);return i&&t.cardboard||!i&&t.allowCardboardOnDesktop?(e.VRFrameData||(e.VRFrameData=function(){this.rightViewMatrix=new Float32Array(16),this.leftViewMatrix=new Float32Array(16),this.rightProjectionMatrix=new Float32Array(16),this.leftProjectionMatrix=new Float32Array(16),this.pose=null}),new class extends dt{constructor(e,t){const i=new Le(t||{});super(e,i),this.display=i,this.frame={rightViewMatrix:new Float32Array(16),leftViewMatrix:new Float32Array(16),rightProjectionMatrix:new Float32Array(16),leftProjectionMatrix:new Float32Array(16),pose:null,timestamp:null}}}(e,t.cardboardConfig)):new class extends Oe{constructor(e){super(e),this.sessions=new Map,this.projectionMatrix=n(),this.identityMatrix=n()}onBaseLayerSet(e,t){this.sessions.get(e).baseLayer=t}isSessionSupported(e){return"inline"==e}isFeatureSupported(e){switch(e){case"viewer":return!0;default:return!1}}async requestSession(e,t){if(!this.isSessionSupported(e))return Promise.reject();const i=new ft(e,t);return this.sessions.set(i.id,i),Promise.resolve(i.id)}requestAnimationFrame(e){return window.requestAnimationFrame(e)}cancelAnimationFrame(e){window.cancelAnimationFrame(e)}onFrameStart(e,t){if(ut)return;const i=this.sessions.get(e);if(i.baseLayer){const e=i.baseLayer.context.canvas;d(this.projectionMatrix,t.inlineVerticalFieldOfView,e.width/e.height,t.depthNear,t.depthFar)}}onFrameEnd(e){}async endSession(e){this.sessions.get(e).ended=!0}doesSessionSupportReferenceSpace(e,t){const i=this.sessions.get(e);return!i.ended&&i.enabledFeatures.has(t)}requestStageBounds(){return null}async requestFrameOfReferenceTransform(e,t){return null}getProjectionMatrix(e){return this.projectionMatrix}getViewport(e,t,i,r){const{width:s,height:n}=i.context.canvas;return this.sessions.get(e),r.x=r.y=0,r.width=s,r.height=n,!0}getBasePoseMatrix(){return this.identityMatrix}getBaseViewMatrix(e){return this.identityMatrix}getInputSources(){return[]}getInputPose(e,t,i){return null}onWindowResize(){}}(e)},gt={global:e,webvr:!0,cardboard:!0,cardboardConfig:null,allowCardboardOnDesktop:!1},vt=["navigator","HTMLCanvasElement","WebGLRenderingContext"];return class{constructor(e={}){this.config=Object.freeze(Object.assign({},gt,e)),this.global=this.config.global,this.nativeWebXR="xr"in this.global.navigator,this.injected=!1,this.nativeWebXR?this._injectCompatibilityShims(this.global):this._injectPolyfill(this.global)}_injectPolyfill(e){if(!vt.every(t=>!!e[t]))throw new Error(`Global must have the following attributes : ${vt}`);for(const t of Object.keys(xe))void 0!==e[t]?console.warn(`${t} already defined on global.`):e[t]=xe[t];_e(e.WebGLRenderingContext)&&(Fe(e.HTMLCanvasElement),e.OffscreenCanvas&&Fe(e.OffscreenCanvas),e.WebGL2RenderingContext&&_e(e.WebGL2RenderingContext)),this.injected=!0,this._patchNavigatorXR()}_patchNavigatorXR(){let e=mt(this.global,this.config);this.xr=new xe.XR(e),Object.defineProperty(this.global.navigator,"xr",{value:this.xr,configurable:!0})}_injectCompatibilityShims(e){if(!vt.every(t=>!!e[t]))throw new Error(`Global must have the following attributes : ${vt}`);if(e.navigator.xr&&"supportsSession"in e.navigator.xr&&!("isSessionSupported"in e.navigator.xr)){let t=e.navigator.xr.supportsSession;e.navigator.xr.isSessionSupported=function(e){return t.call(this,e).then(()=>!0).catch(()=>!1)},e.navigator.xr.supportsSession=function(e){return console.warn("navigator.xr.supportsSession() is deprecated. Please call navigator.xr.isSessionSupported() instead and check the boolean value returned when the promise resolves."),t.call(this,e)}}}}}); diff --git a/build/webxr-polyfill.module.js b/build/webxr-polyfill.module.js new file mode 100644 index 0000000..70d5d53 --- /dev/null +++ b/build/webxr-polyfill.module.js @@ -0,0 +1,6109 @@ +/** + * @license + * webxr-polyfill + * Copyright (c) 2017 Google + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @license + * cardboard-vr-display + * Copyright (c) 2015-2017 Google + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @license + * webvr-polyfill-dpdb + * Copyright (c) 2017 Google + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @license + * wglu-preserve-state + * Copyright (c) 2016, Brandon Jones. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * @license + * nosleep.js + * Copyright (c) 2017, Rich Tibbett + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +const _global = typeof global !== 'undefined' ? global : + typeof self !== 'undefined' ? self : + typeof window !== 'undefined' ? window : {}; + +const PRIVATE = Symbol('@@webxr-polyfill/EventTarget'); +class EventTarget { + constructor() { + this[PRIVATE] = { + listeners: new Map(), + }; + } + addEventListener(type, listener) { + if (typeof type !== 'string') { throw new Error('`type` must be a string'); } + if (typeof listener !== 'function') { throw new Error('`listener` must be a function'); } + const typedListeners = this[PRIVATE].listeners.get(type) || []; + typedListeners.push(listener); + this[PRIVATE].listeners.set(type, typedListeners); + } + removeEventListener(type, listener) { + if (typeof type !== 'string') { throw new Error('`type` must be a string'); } + if (typeof listener !== 'function') { throw new Error('`listener` must be a function'); } + const typedListeners = this[PRIVATE].listeners.get(type) || []; + for (let i = typedListeners.length; i >= 0; i--) { + if (typedListeners[i] === listener) { + typedListeners.pop(); + } + } + } + dispatchEvent(type, event) { + const typedListeners = this[PRIVATE].listeners.get(type) || []; + const queue = []; + for (let i = 0; i < typedListeners.length; i++) { + queue[i] = typedListeners[i]; + } + for (let listener of queue) { + listener(event); + } + if (typeof this[`on${type}`] === 'function') { + this[`on${type}`](event); + } + } +} + +const EPSILON = 0.000001; +let ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; + + +const degree = Math.PI / 180; + +function create() { + let out = new ARRAY_TYPE(16); + if(ARRAY_TYPE != Float32Array) { + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + } + out[0] = 1; + out[5] = 1; + out[10] = 1; + out[15] = 1; + return out; +} + +function copy(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +} + + +function identity(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +} + +function invert(out, a) { + let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; + let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; + let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; + let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + let b00 = a00 * a11 - a01 * a10; + let b01 = a00 * a12 - a02 * a10; + let b02 = a00 * a13 - a03 * a10; + let b03 = a01 * a12 - a02 * a11; + let b04 = a01 * a13 - a03 * a11; + let b05 = a02 * a13 - a03 * a12; + let b06 = a20 * a31 - a21 * a30; + let b07 = a20 * a32 - a22 * a30; + let b08 = a20 * a33 - a23 * a30; + let b09 = a21 * a32 - a22 * a31; + let b10 = a21 * a33 - a23 * a31; + let b11 = a22 * a33 - a23 * a32; + let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + if (!det) { + return null; + } + det = 1.0 / det; + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; + out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; + out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; + out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; + out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; + out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; + out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; + return out; +} + + +function multiply(out, a, b) { + let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; + let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; + let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; + let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; + out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; + out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; + out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + return out; +} + + + + + + + + + + + + +function fromRotationTranslation(out, q, v) { + let x = q[0], y = q[1], z = q[2], w = q[3]; + let x2 = x + x; + let y2 = y + y; + let z2 = z + z; + let xx = x * x2; + let xy = x * y2; + let xz = x * z2; + let yy = y * y2; + let yz = y * z2; + let zz = z * z2; + let wx = w * x2; + let wy = w * y2; + let wz = w * z2; + out[0] = 1 - (yy + zz); + out[1] = xy + wz; + out[2] = xz - wy; + out[3] = 0; + out[4] = xy - wz; + out[5] = 1 - (xx + zz); + out[6] = yz + wx; + out[7] = 0; + out[8] = xz + wy; + out[9] = yz - wx; + out[10] = 1 - (xx + yy); + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + return out; +} + +function getTranslation(out, mat) { + out[0] = mat[12]; + out[1] = mat[13]; + out[2] = mat[14]; + return out; +} + +function getRotation(out, mat) { + let trace = mat[0] + mat[5] + mat[10]; + let S = 0; + if (trace > 0) { + S = Math.sqrt(trace + 1.0) * 2; + out[3] = 0.25 * S; + out[0] = (mat[6] - mat[9]) / S; + out[1] = (mat[8] - mat[2]) / S; + out[2] = (mat[1] - mat[4]) / S; + } else if ((mat[0] > mat[5]) && (mat[0] > mat[10])) { + S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2; + out[3] = (mat[6] - mat[9]) / S; + out[0] = 0.25 * S; + out[1] = (mat[1] + mat[4]) / S; + out[2] = (mat[8] + mat[2]) / S; + } else if (mat[5] > mat[10]) { + S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2; + out[3] = (mat[8] - mat[2]) / S; + out[0] = (mat[1] + mat[4]) / S; + out[1] = 0.25 * S; + out[2] = (mat[6] + mat[9]) / S; + } else { + S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2; + out[3] = (mat[1] - mat[4]) / S; + out[0] = (mat[8] + mat[2]) / S; + out[1] = (mat[6] + mat[9]) / S; + out[2] = 0.25 * S; + } + return out; +} + + + + +function perspective(out, fovy, aspect, near, far) { + let f = 1.0 / Math.tan(fovy / 2), nf; + out[0] = f / aspect; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = f; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[15] = 0; + if (far != null && far !== Infinity) { + nf = 1 / (near - far); + out[10] = (far + near) * nf; + out[14] = (2 * far * near) * nf; + } else { + out[10] = -1; + out[14] = -2 * near; + } + return out; +} + +function create$1() { + let out = new ARRAY_TYPE(3); + if(ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + } + return out; +} +function clone$1(a) { + var out = new ARRAY_TYPE(3); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +} +function length(a) { + let x = a[0]; + let y = a[1]; + let z = a[2]; + return Math.sqrt(x*x + y*y + z*z); +} +function fromValues$1(x, y, z) { + let out = new ARRAY_TYPE(3); + out[0] = x; + out[1] = y; + out[2] = z; + return out; +} +function copy$1(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +} + +function add$1(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + return out; +} + + + + + + + + +function scale$1(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + return out; +} + + + + + + +function normalize(out, a) { + let x = a[0]; + let y = a[1]; + let z = a[2]; + let len = x*x + y*y + z*z; + if (len > 0) { + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + out[2] = a[2] * len; + } + return out; +} +function dot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} +function cross(out, a, b) { + let ax = a[0], ay = a[1], az = a[2]; + let bx = b[0], by = b[1], bz = b[2]; + out[0] = ay * bz - az * by; + out[1] = az * bx - ax * bz; + out[2] = ax * by - ay * bx; + return out; +} + + + + + + +function transformQuat(out, a, q) { + let qx = q[0], qy = q[1], qz = q[2], qw = q[3]; + let x = a[0], y = a[1], z = a[2]; + let uvx = qy * z - qz * y, + uvy = qz * x - qx * z, + uvz = qx * y - qy * x; + let uuvx = qy * uvz - qz * uvy, + uuvy = qz * uvx - qx * uvz, + uuvz = qx * uvy - qy * uvx; + let w2 = qw * 2; + uvx *= w2; + uvy *= w2; + uvz *= w2; + uuvx *= 2; + uuvy *= 2; + uuvz *= 2; + out[0] = x + uvx + uuvx; + out[1] = y + uvy + uuvy; + out[2] = z + uvz + uuvz; + return out; +} + + + +function angle(a, b) { + let tempA = fromValues$1(a[0], a[1], a[2]); + let tempB = fromValues$1(b[0], b[1], b[2]); + normalize(tempA, tempA); + normalize(tempB, tempB); + let cosine = dot(tempA, tempB); + if(cosine > 1.0) { + return 0; + } + else if(cosine < -1.0) { + return Math.PI; + } else { + return Math.acos(cosine); + } +} + + + + + + + + +const len = length; + +const forEach = (function() { + let vec = create$1(); + return function(a, stride, offset, count, fn, arg) { + let i, l; + if(!stride) { + stride = 3; + } + if(!offset) { + offset = 0; + } + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; + } + return a; + }; +})(); + +function create$2() { + let out = new ARRAY_TYPE(9); + if(ARRAY_TYPE != Float32Array) { + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[5] = 0; + out[6] = 0; + out[7] = 0; + } + out[0] = 1; + out[4] = 1; + out[8] = 1; + return out; +} + +function create$3() { + let out = new ARRAY_TYPE(4); + if(ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 0; + } + return out; +} +function clone$3(a) { + let out = new ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +} +function fromValues$3(x, y, z, w) { + let out = new ARRAY_TYPE(4); + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; +} +function copy$3(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +} + + + + + + + + + + + + + + + + + + +function normalize$1(out, a) { + let x = a[0]; + let y = a[1]; + let z = a[2]; + let w = a[3]; + let len = x*x + y*y + z*z + w*w; + if (len > 0) { + len = 1 / Math.sqrt(len); + out[0] = x * len; + out[1] = y * len; + out[2] = z * len; + out[3] = w * len; + } + return out; +} + + + + + + + + + + + + + + + +const forEach$1 = (function() { + let vec = create$3(); + return function(a, stride, offset, count, fn, arg) { + let i, l; + if(!stride) { + stride = 4; + } + if(!offset) { + offset = 0; + } + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3]; + } + return a; + }; +})(); + +function create$4() { + let out = new ARRAY_TYPE(4); + if(ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + } + out[3] = 1; + return out; +} + +function setAxisAngle(out, axis, rad) { + rad = rad * 0.5; + let s = Math.sin(rad); + out[0] = s * axis[0]; + out[1] = s * axis[1]; + out[2] = s * axis[2]; + out[3] = Math.cos(rad); + return out; +} + +function multiply$4(out, a, b) { + let ax = a[0], ay = a[1], az = a[2], aw = a[3]; + let bx = b[0], by = b[1], bz = b[2], bw = b[3]; + out[0] = ax * bw + aw * bx + ay * bz - az * by; + out[1] = ay * bw + aw * by + az * bx - ax * bz; + out[2] = az * bw + aw * bz + ax * by - ay * bx; + out[3] = aw * bw - ax * bx - ay * by - az * bz; + return out; +} + + + + +function slerp(out, a, b, t) { + let ax = a[0], ay = a[1], az = a[2], aw = a[3]; + let bx = b[0], by = b[1], bz = b[2], bw = b[3]; + let omega, cosom, sinom, scale0, scale1; + cosom = ax * bx + ay * by + az * bz + aw * bw; + if ( cosom < 0.0 ) { + cosom = -cosom; + bx = - bx; + by = - by; + bz = - bz; + bw = - bw; + } + if ( (1.0 - cosom) > EPSILON ) { + omega = Math.acos(cosom); + sinom = Math.sin(omega); + scale0 = Math.sin((1.0 - t) * omega) / sinom; + scale1 = Math.sin(t * omega) / sinom; + } else { + scale0 = 1.0 - t; + scale1 = t; + } + out[0] = scale0 * ax + scale1 * bx; + out[1] = scale0 * ay + scale1 * by; + out[2] = scale0 * az + scale1 * bz; + out[3] = scale0 * aw + scale1 * bw; + return out; +} + +function invert$2(out, a) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + let dot$$1 = a0*a0 + a1*a1 + a2*a2 + a3*a3; + let invDot = dot$$1 ? 1.0/dot$$1 : 0; + out[0] = -a0*invDot; + out[1] = -a1*invDot; + out[2] = -a2*invDot; + out[3] = a3*invDot; + return out; +} + +function fromMat3(out, m) { + let fTrace = m[0] + m[4] + m[8]; + let fRoot; + if ( fTrace > 0.0 ) { + fRoot = Math.sqrt(fTrace + 1.0); + out[3] = 0.5 * fRoot; + fRoot = 0.5/fRoot; + out[0] = (m[5]-m[7])*fRoot; + out[1] = (m[6]-m[2])*fRoot; + out[2] = (m[1]-m[3])*fRoot; + } else { + let i = 0; + if ( m[4] > m[0] ) + i = 1; + if ( m[8] > m[i*3+i] ) + i = 2; + let j = (i+1)%3; + let k = (i+2)%3; + fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); + out[i] = 0.5 * fRoot; + fRoot = 0.5 / fRoot; + out[3] = (m[j*3+k] - m[k*3+j]) * fRoot; + out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; + out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; + } + return out; +} +function fromEuler(out, x, y, z) { + let halfToRad = 0.5 * Math.PI / 180.0; + x *= halfToRad; + y *= halfToRad; + z *= halfToRad; + let sx = Math.sin(x); + let cx = Math.cos(x); + let sy = Math.sin(y); + let cy = Math.cos(y); + let sz = Math.sin(z); + let cz = Math.cos(z); + out[0] = sx * cy * cz - cx * sy * sz; + out[1] = cx * sy * cz + sx * cy * sz; + out[2] = cx * cy * sz - sx * sy * cz; + out[3] = cx * cy * cz + sx * sy * sz; + return out; +} + +const clone$4 = clone$3; +const fromValues$4 = fromValues$3; +const copy$4 = copy$3; + + + + + + + + + + +const normalize$2 = normalize$1; + + +const rotationTo = (function() { + let tmpvec3 = create$1(); + let xUnitVec3 = fromValues$1(1,0,0); + let yUnitVec3 = fromValues$1(0,1,0); + return function(out, a, b) { + let dot$$1 = dot(a, b); + if (dot$$1 < -0.999999) { + cross(tmpvec3, xUnitVec3, a); + if (len(tmpvec3) < 0.000001) + cross(tmpvec3, yUnitVec3, a); + normalize(tmpvec3, tmpvec3); + setAxisAngle(out, tmpvec3, Math.PI); + return out; + } else if (dot$$1 > 0.999999) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } else { + cross(tmpvec3, a, b); + out[0] = tmpvec3[0]; + out[1] = tmpvec3[1]; + out[2] = tmpvec3[2]; + out[3] = 1 + dot$$1; + return normalize$2(out, out); + } + }; +})(); +const sqlerp = (function () { + let temp1 = create$4(); + let temp2 = create$4(); + return function (out, a, b, c, d, t) { + slerp(temp1, a, d, t); + slerp(temp2, b, c, t); + slerp(out, temp1, temp2, 2 * t * (1 - t)); + return out; + }; +}()); +const setAxes = (function() { + let matr = create$2(); + return function(out, view, right, up) { + matr[0] = right[0]; + matr[3] = right[1]; + matr[6] = right[2]; + matr[1] = up[0]; + matr[4] = up[1]; + matr[7] = up[2]; + matr[2] = -view[0]; + matr[5] = -view[1]; + matr[8] = -view[2]; + return normalize$2(out, fromMat3(out, matr)); + }; +})(); + +const PRIVATE$1 = Symbol('@@webxr-polyfill/XRRigidTransform'); +class XRRigidTransform$1 { + constructor() { + this[PRIVATE$1] = { + matrix: null, + position: null, + orientation: null, + inverse: null, + }; + if (arguments.length === 0) { + this[PRIVATE$1].matrix = identity(new Float32Array(16)); + } else if (arguments.length === 1) { + if (arguments[0] instanceof Float32Array) { + this[PRIVATE$1].matrix = arguments[0]; + } else { + this[PRIVATE$1].position = this._getPoint(arguments[0]); + this[PRIVATE$1].orientation = DOMPointReadOnly.fromPoint({ + x: 0, y: 0, z: 0, w: 1 + }); + } + } else if (arguments.length === 2) { + this[PRIVATE$1].position = this._getPoint(arguments[0]); + this[PRIVATE$1].orientation = this._getPoint(arguments[1]); + } else { + throw new Error("Too many arguments!"); + } + if (this[PRIVATE$1].matrix) { + let position = create$1(); + getTranslation(position, this[PRIVATE$1].matrix); + this[PRIVATE$1].position = DOMPointReadOnly.fromPoint({ + x: position[0], + y: position[1], + z: position[2] + }); + let orientation = create$4(); + getRotation(orientation, this[PRIVATE$1].matrix); + this[PRIVATE$1].orientation = DOMPointReadOnly.fromPoint({ + x: orientation[0], + y: orientation[1], + z: orientation[2], + w: orientation[3] + }); + } else { + this[PRIVATE$1].matrix = identity(new Float32Array(16)); + fromRotationTranslation( + this[PRIVATE$1].matrix, + fromValues$4( + this[PRIVATE$1].orientation.x, + this[PRIVATE$1].orientation.y, + this[PRIVATE$1].orientation.z, + this[PRIVATE$1].orientation.w), + fromValues$1( + this[PRIVATE$1].position.x, + this[PRIVATE$1].position.y, + this[PRIVATE$1].position.z) + ); + } + } + _getPoint(arg) { + if (arg instanceof DOMPointReadOnly) { + return arg; + } + return DOMPointReadOnly.fromPoint(arg); + } + get matrix() { return this[PRIVATE$1].matrix; } + get position() { return this[PRIVATE$1].position; } + get orientation() { return this[PRIVATE$1].orientation; } + get inverse() { + if (this[PRIVATE$1].inverse === null) { + let invMatrix = identity(new Float32Array(16)); + invert(invMatrix, this[PRIVATE$1].matrix); + this[PRIVATE$1].inverse = new XRRigidTransform$1(invMatrix); + this[PRIVATE$1].inverse[PRIVATE$1].inverse = this; + } + return this[PRIVATE$1].inverse; + } +} + +const PRIVATE$2 = Symbol('@@webxr-polyfill/XRSpace'); + +class XRSpace { + constructor(specialType = null, inputSource = null) { + this[PRIVATE$2] = { + specialType, + inputSource, + baseMatrix: null, + inverseBaseMatrix: null, + lastFrameId: -1 + }; + } + get _specialType() { + return this[PRIVATE$2].specialType; + } + get _inputSource() { + return this[PRIVATE$2].inputSource; + } + _ensurePoseUpdated(device, frameId) { + if (frameId == this[PRIVATE$2].lastFrameId) return; + this[PRIVATE$2].lastFrameId = frameId; + this._onPoseUpdate(device); + } + _onPoseUpdate(device) { + if (this[PRIVATE$2].specialType == 'viewer') { + this._baseMatrix = device.getBasePoseMatrix(); + } + } + set _baseMatrix(matrix) { + this[PRIVATE$2].baseMatrix = matrix; + this[PRIVATE$2].inverseBaseMatrix = null; + } + get _baseMatrix() { + if (!this[PRIVATE$2].baseMatrix) { + if (this[PRIVATE$2].inverseBaseMatrix) { + this[PRIVATE$2].baseMatrix = new Float32Array(16); + invert(this[PRIVATE$2].baseMatrix, this[PRIVATE$2].inverseBaseMatrix); + } + } + return this[PRIVATE$2].baseMatrix; + } + set _inverseBaseMatrix(matrix) { + this[PRIVATE$2].inverseBaseMatrix = matrix; + this[PRIVATE$2].baseMatrix = null; + } + get _inverseBaseMatrix() { + if (!this[PRIVATE$2].inverseBaseMatrix) { + if (this[PRIVATE$2].baseMatrix) { + this[PRIVATE$2].inverseBaseMatrix = new Float32Array(16); + invert(this[PRIVATE$2].inverseBaseMatrix, this[PRIVATE$2].baseMatrix); + } + } + return this[PRIVATE$2].inverseBaseMatrix; + } + _getSpaceRelativeTransform(space) { + if (!this._inverseBaseMatrix || !space._baseMatrix) { + return null; + } + let out = new Float32Array(16); + multiply(out, this._inverseBaseMatrix, space._baseMatrix); + return new XRRigidTransform$1(out); + } +} + +const DEFAULT_EMULATION_HEIGHT = 1.6; +const PRIVATE$3 = Symbol('@@webxr-polyfill/XRReferenceSpace'); +const XRReferenceSpaceTypes = [ + 'viewer', + 'local', + 'local-floor', + 'bounded-floor', + 'unbounded' +]; +function isFloor(type) { + return type === 'bounded-floor' || type === 'local-floor'; +} +class XRReferenceSpace extends XRSpace { + constructor(type, transform = null) { + if (!XRReferenceSpaceTypes.includes(type)) { + throw new Error(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`); + } + super(type); + if (type === 'bounded-floor' && !transform) { + throw new Error(`XRReferenceSpace cannot use 'bounded-floor' type if the platform does not provide the floor level`); + } + if (isFloor(type) && !transform) { + transform = identity(new Float32Array(16)); + transform[13] = DEFAULT_EMULATION_HEIGHT; + } + this._inverseBaseMatrix = transform || identity(new Float32Array(16)); + this[PRIVATE$3] = { + type, + transform, + originOffset : identity(new Float32Array(16)), + }; + } + _transformBasePoseMatrix(out, pose) { + multiply(out, this._inverseBaseMatrix, pose); + } + _originOffsetMatrix() { + return this[PRIVATE$3].originOffset; + } + _adjustForOriginOffset(transformMatrix) { + let inverseOriginOffsetMatrix = new Float32Array(16); + invert(inverseOriginOffsetMatrix, this[PRIVATE$3].originOffset); + multiply(transformMatrix, inverseOriginOffsetMatrix, transformMatrix); + } + _getSpaceRelativeTransform(space) { + let transform = super._getSpaceRelativeTransform(space); + this._adjustForOriginOffset(transform.matrix); + return new XRRigidTransform(transform.matrix); + } + getOffsetReferenceSpace(additionalOffset) { + let newSpace = new XRReferenceSpace( + this[PRIVATE$3].type, + this[PRIVATE$3].transform, + this[PRIVATE$3].bounds); + multiply(newSpace[PRIVATE$3].originOffset, this[PRIVATE$3].originOffset, additionalOffset.matrix); + return newSpace; + } +} + +const PRIVATE$4 = Symbol('@@webxr-polyfill/XR'); +const XRSessionModes = ['inline', 'immersive-vr', 'immersive-ar']; +const DEFAULT_SESSION_OPTIONS = { + 'inline': { + requiredFeatures: ['viewer'], + optionalFeatures: [], + }, + 'immersive-vr': { + requiredFeatures: ['viewer', 'local'], + optionalFeatures: [], + }, + 'immersive-ar': { + requiredFeatures: ['viewer', 'local'], + optionalFeatures: [], + } +}; +const POLYFILL_REQUEST_SESSION_ERROR = +`Polyfill Error: Must call navigator.xr.isSessionSupported() with any XRSessionMode +or navigator.xr.requestSession('inline') prior to requesting an immersive +session. This is a limitation specific to the WebXR Polyfill and does not apply +to native implementations of the API.`; +class XR extends EventTarget { + constructor(devicePromise) { + super(); + this[PRIVATE$4] = { + device: null, + devicePromise, + immersiveSession: null, + inlineSessions: new Set(), + }; + devicePromise.then((device) => { this[PRIVATE$4].device = device; }); + } + async isSessionSupported(mode) { + if (!this[PRIVATE$4].device) { + await this[PRIVATE$4].devicePromise; + } + if (mode != 'inline') { + return Promise.resolve(this[PRIVATE$4].device.isSessionSupported(mode)); + } + return Promise.resolve(true); + } + async requestSession(mode, options) { + if (!this[PRIVATE$4].device) { + if (mode != 'inline') { + throw new Error(POLYFILL_REQUEST_SESSION_ERROR); + } else { + await this[PRIVATE$4].devicePromise; + } + } + if (!XRSessionModes.includes(mode)) { + throw new TypeError( + `The provided value '${mode}' is not a valid enum value of type XRSessionMode`); + } + const defaultOptions = DEFAULT_SESSION_OPTIONS[mode]; + const requiredFeatures = defaultOptions.requiredFeatures.concat( + options && options.requiredFeatures ? options.requiredFeatures : []); + const optionalFeatures = defaultOptions.optionalFeatures.concat( + options && options.optionalFeatures ? options.optionalFeatures : []); + const enabledFeatures = new Set(); + let requirementsFailed = false; + for (let feature of requiredFeatures) { + if (!this[PRIVATE$4].device.isFeatureSupported(feature)) { + console.error(`The required feature '${feature}' is not supported`); + requirementsFailed = true; + } else { + enabledFeatures.add(feature); + } + } + if (requirementsFailed) { + throw new DOMException('Session does not support some required features', 'NotSupportedError'); + } + for (let feature of optionalFeatures) { + if (!this[PRIVATE$4].device.isFeatureSupported(feature)) { + console.log(`The optional feature '${feature}' is not supported`); + } else { + enabledFeatures.add(feature); + } + } + const sessionId = await this[PRIVATE$4].device.requestSession(mode, enabledFeatures); + const session = new XRSession(this[PRIVATE$4].device, mode, sessionId); + if (mode == 'inline') { + this[PRIVATE$4].inlineSessions.add(session); + } else { + this[PRIVATE$4].immersiveSession = session; + } + const onSessionEnd = () => { + if (mode == 'inline') { + this[PRIVATE$4].inlineSessions.delete(session); + } else { + this[PRIVATE$4].immersiveSession = null; + } + session.removeEventListener('end', onSessionEnd); + }; + session.addEventListener('end', onSessionEnd); + return session; + } +} + +let now; +if ('performance' in _global === false) { + let startTime = Date.now(); + now = () => Date.now() - startTime; +} else { + now = () => performance.now(); +} +var now$1 = now; + +const PRIVATE$5 = Symbol('@@webxr-polyfill/XRPose'); +class XRPose$1 { + constructor(transform, emulatedPosition) { + this[PRIVATE$5] = { + transform, + emulatedPosition, + }; + } + get transform() { return this[PRIVATE$5].transform; } + get emulatedPosition() { return this[PRIVATE$5].emulatedPosition; } +} + +const PRIVATE$6 = Symbol('@@webxr-polyfill/XRViewerPose'); +class XRViewerPose extends XRPose$1 { + constructor(transform, views, emulatedPosition = false) { + super(transform, emulatedPosition); + this[PRIVATE$6] = { + views + }; + } + get views() { + return this[PRIVATE$6].views; + } +} + +const PRIVATE$7 = Symbol('@@webxr-polyfill/XRViewport'); +class XRViewport { + constructor(target) { + this[PRIVATE$7] = { target }; + } + get x() { return this[PRIVATE$7].target.x; } + get y() { return this[PRIVATE$7].target.y; } + get width() { return this[PRIVATE$7].target.width; } + get height() { return this[PRIVATE$7].target.height; } +} + +const XREyes = ['left', 'right', 'none']; +const PRIVATE$8 = Symbol('@@webxr-polyfill/XRView'); +class XRView { + constructor(device, transform, eye, sessionId) { + if (!XREyes.includes(eye)) { + throw new Error(`XREye must be one of: ${XREyes}`); + } + const temp = Object.create(null); + const viewport = new XRViewport(temp); + this[PRIVATE$8] = { + device, + eye, + viewport, + temp, + sessionId, + transform, + }; + } + get eye() { return this[PRIVATE$8].eye; } + get projectionMatrix() { return this[PRIVATE$8].device.getProjectionMatrix(this.eye); } + get transform() { return this[PRIVATE$8].transform; } + _getViewport(layer) { + if (this[PRIVATE$8].device.getViewport(this[PRIVATE$8].sessionId, + this.eye, + layer, + this[PRIVATE$8].temp)) { + return this[PRIVATE$8].viewport; + } + return undefined; + } +} + +const PRIVATE$9 = Symbol('@@webxr-polyfill/XRFrame'); +const NON_ACTIVE_MSG = "XRFrame access outside the callback that produced it is invalid."; +const NON_ANIMFRAME_MSG = "getViewerPose can only be called on XRFrame objects passed to XRSession.requestAnimationFrame callbacks."; +let NEXT_FRAME_ID = 0; +class XRFrame { + constructor(device, session, sessionId) { + this[PRIVATE$9] = { + id: ++NEXT_FRAME_ID, + active: false, + animationFrame: false, + device, + session, + sessionId + }; + } + get session() { return this[PRIVATE$9].session; } + getViewerPose(referenceSpace) { + if (!this[PRIVATE$9].animationFrame) { + throw new DOMException(NON_ANIMFRAME_MSG, 'InvalidStateError'); + } + if (!this[PRIVATE$9].active) { + throw new DOMException(NON_ACTIVE_MSG, 'InvalidStateError'); + } + const device = this[PRIVATE$9].device; + const session = this[PRIVATE$9].session; + session[PRIVATE$15].viewerSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); + referenceSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); + let viewerTransform = referenceSpace._getSpaceRelativeTransform(session[PRIVATE$15].viewerSpace); + const views = []; + for (let viewSpace of session[PRIVATE$15].viewSpaces) { + viewSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); + let viewTransform = referenceSpace._getSpaceRelativeTransform(viewSpace); + let view = new XRView(device, viewTransform, viewSpace.eye, this[PRIVATE$9].sessionId); + views.push(view); + } + let viewerPose = new XRViewerPose(viewerTransform, views, false ); + return viewerPose; + } + getPose(space, baseSpace) { + if (!this[PRIVATE$9].active) { + throw new DOMException(NON_ACTIVE_MSG, 'InvalidStateError'); + } + const device = this[PRIVATE$9].device; + if (space._specialType === "target-ray" || space._specialType === "grip") { + return device.getInputPose( + space._inputSource, baseSpace, space._specialType); + } else { + space._ensurePoseUpdated(device, this[PRIVATE$9].id); + baseSpace._ensurePoseUpdated(device, this[PRIVATE$9].id); + let transform = baseSpace._getSpaceRelativeTransform(space); + if (!transform) { return null; } + return new XRPose(transform, false ); + } + return null; + } +} + +const PRIVATE$10 = Symbol('@@webxr-polyfill/XRRenderState'); +const XRRenderStateInit = Object.freeze({ + depthNear: 0.1, + depthFar: 1000.0, + inlineVerticalFieldOfView: null, + baseLayer: null +}); +class XRRenderState { + constructor(stateInit = {}) { + const config = Object.assign({}, XRRenderStateInit, stateInit); + this[PRIVATE$10] = { config }; + } + get depthNear() { return this[PRIVATE$10].config.depthNear; } + get depthFar() { return this[PRIVATE$10].config.depthFar; } + get inlineVerticalFieldOfView() { return this[PRIVATE$10].config.inlineVerticalFieldOfView; } + get baseLayer() { return this[PRIVATE$10].config.baseLayer; } +} + +const POLYFILLED_XR_COMPATIBLE = Symbol('@@webxr-polyfill/polyfilled-xr-compatible'); +const XR_COMPATIBLE = Symbol('@@webxr-polyfill/xr-compatible'); + +const PRIVATE$11 = Symbol('@@webxr-polyfill/XRWebGLLayer'); +const XRWebGLLayerInit = Object.freeze({ + antialias: true, + depth: false, + stencil: false, + alpha: true, + multiview: false, + ignoreDepthValues: false, + framebufferScaleFactor: 1.0, +}); +class XRWebGLLayer { + constructor(session, context, layerInit={}) { + const config = Object.assign({}, XRWebGLLayerInit, layerInit); + if (!(session instanceof XRSession$1)) { + throw new Error('session must be a XRSession'); + } + if (session.ended) { + throw new Error(`InvalidStateError`); + } + if (context[POLYFILLED_XR_COMPATIBLE]) { + if (context[XR_COMPATIBLE] !== true) { + throw new Error(`InvalidStateError`); + } + } + const framebuffer = context.getParameter(context.FRAMEBUFFER_BINDING); + this[PRIVATE$11] = { + context, + config, + framebuffer, + session, + }; + } + get context() { return this[PRIVATE$11].context; } + get antialias() { return this[PRIVATE$11].config.antialias; } + get ignoreDepthValues() { return true; } + get framebuffer() { return this[PRIVATE$11].framebuffer; } + get framebufferWidth() { return this[PRIVATE$11].context.drawingBufferWidth; } + get framebufferHeight() { return this[PRIVATE$11].context.drawingBufferHeight; } + get _session() { return this[PRIVATE$11].session; } + getViewport(view) { + return view._getViewport(this); + } + static getNativeFramebufferScaleFactor(session) { + if (!session) { + throw new TypeError('getNativeFramebufferScaleFactor must be passed a session.') + } + if (session[PRIVATE$15].ended) { return 0.0; } + return 1.0; + } +} + +const PRIVATE$12 = Symbol('@@webxr-polyfill/XRInputSourceEvent'); +class XRInputSourceEvent extends Event { + constructor(type, eventInitDict) { + super(type, eventInitDict); + this[PRIVATE$12] = { + frame: eventInitDict.frame, + inputSource: eventInitDict.inputSource + }; + } + get frame() { return this[PRIVATE$12].frame; } + get inputSource() { return this[PRIVATE$12].inputSource; } +} + +const PRIVATE$13 = Symbol('@@webxr-polyfill/XRSessionEvent'); +class XRSessionEvent extends Event { + constructor(type, eventInitDict) { + super(type, eventInitDict); + this[PRIVATE$13] = { + session: eventInitDict.session + }; + } + get session() { return this[PRIVATE$13].session; } +} + +const PRIVATE$14 = Symbol('@@webxr-polyfill/XRInputSourcesChangeEvent'); +class XRInputSourcesChangeEvent extends Event { + constructor(type, eventInitDict) { + super(type, eventInitDict); + this[PRIVATE$14] = { + session: eventInitDict.session, + added: eventInitDict.added, + removed: eventInitDict.removed + }; + } + get session() { return this[PRIVATE$14].session; } + get added() { return this[PRIVATE$14].added; } + get removed() { return this[PRIVATE$14].removed; } +} + +const PRIVATE$15 = Symbol('@@webxr-polyfill/XRSession'); +class XRViewSpace extends XRSpace { + constructor(eye) { + super(eye); + } + get eye() { + return this._specialType; + } + _onPoseUpdate(device) { + this._inverseBaseMatrix = device.getBaseViewMatrix(this._specialType); + } +} +class XRSession$1 extends EventTarget { + constructor(device, mode, id) { + super(); + let immersive = mode != 'inline'; + let initialRenderState = new XRRenderState({ + inlineVerticalFieldOfView: immersive ? null : Math.PI * 0.5 + }); + this[PRIVATE$15] = { + device, + mode, + immersive, + ended: false, + suspended: false, + frameCallbacks: [], + currentFrameCallbacks: null, + frameHandle: 0, + deviceFrameHandle: null, + id, + activeRenderState: initialRenderState, + pendingRenderState: null, + viewerSpace: new XRReferenceSpace("viewer"), + viewSpaces: [], + currentInputSources: [] + }; + if (immersive) { + this[PRIVATE$15].viewSpaces.push(new XRViewSpace('left'), + new XRViewSpace('right')); + } else { + this[PRIVATE$15].viewSpaces.push(new XRViewSpace('none')); + } + this[PRIVATE$15].onDeviceFrame = () => { + if (this[PRIVATE$15].ended || this[PRIVATE$15].suspended) { + return; + } + this[PRIVATE$15].deviceFrameHandle = null; + this[PRIVATE$15].startDeviceFrameLoop(); + if (this[PRIVATE$15].pendingRenderState !== null) { + this[PRIVATE$15].activeRenderState = new XRRenderState(this[PRIVATE$15].pendingRenderState); + this[PRIVATE$15].pendingRenderState = null; + if (this[PRIVATE$15].activeRenderState.baseLayer) { + this[PRIVATE$15].device.onBaseLayerSet( + this[PRIVATE$15].id, + this[PRIVATE$15].activeRenderState.baseLayer); + } + } + if (this[PRIVATE$15].activeRenderState.baseLayer === null) { + return; + } + const frame = new XRFrame(device, this, this[PRIVATE$15].id); + const callbacks = this[PRIVATE$15].currentFrameCallbacks = this[PRIVATE$15].frameCallbacks; + this[PRIVATE$15].frameCallbacks = []; + frame[PRIVATE$9].active = true; + frame[PRIVATE$9].animationFrame = true; + this[PRIVATE$15].device.onFrameStart(this[PRIVATE$15].id, this[PRIVATE$15].activeRenderState); + this._checkInputSourcesChange(); + const rightNow = now$1(); + for (let i = 0; i < callbacks.length; i++) { + try { + if (!callbacks[i].cancelled && typeof callbacks[i].callback === 'function') { + callbacks[i].callback(rightNow, frame); + } + } catch(err) { + console.error(err); + } + } + this[PRIVATE$15].currentFrameCallbacks = null; + frame[PRIVATE$9].active = false; + this[PRIVATE$15].device.onFrameEnd(this[PRIVATE$15].id); + }; + this[PRIVATE$15].startDeviceFrameLoop = () => { + if (this[PRIVATE$15].deviceFrameHandle === null) { + this[PRIVATE$15].deviceFrameHandle = this[PRIVATE$15].device.requestAnimationFrame( + this[PRIVATE$15].onDeviceFrame + ); + } + }; + this[PRIVATE$15].stopDeviceFrameLoop = () => { + const handle = this[PRIVATE$15].deviceFrameHandle; + if (handle !== null) { + this[PRIVATE$15].device.cancelAnimationFrame(handle); + this[PRIVATE$15].deviceFrameHandle = null; + } + }; + this[PRIVATE$15].onPresentationEnd = sessionId => { + if (sessionId !== this[PRIVATE$15].id) { + this[PRIVATE$15].suspended = false; + this[PRIVATE$15].startDeviceFrameLoop(); + this.dispatchEvent('focus', { session: this }); + return; + } + this[PRIVATE$15].ended = true; + this[PRIVATE$15].stopDeviceFrameLoop(); + device.removeEventListener('@webvr-polyfill/vr-present-end', this[PRIVATE$15].onPresentationEnd); + device.removeEventListener('@webvr-polyfill/vr-present-start', this[PRIVATE$15].onPresentationStart); + device.removeEventListener('@@webvr-polyfill/input-select-start', this[PRIVATE$15].onSelectStart); + device.removeEventListener('@@webvr-polyfill/input-select-end', this[PRIVATE$15].onSelectEnd); + this.dispatchEvent('end', new XRSessionEvent('end', { session: this })); + }; + device.addEventListener('@@webxr-polyfill/vr-present-end', this[PRIVATE$15].onPresentationEnd); + this[PRIVATE$15].onPresentationStart = sessionId => { + if (sessionId === this[PRIVATE$15].id) { + return; + } + this[PRIVATE$15].suspended = true; + this[PRIVATE$15].stopDeviceFrameLoop(); + this.dispatchEvent('blur', { session: this }); + }; + device.addEventListener('@@webxr-polyfill/vr-present-start', this[PRIVATE$15].onPresentationStart); + this[PRIVATE$15].onSelectStart = evt => { + if (evt.sessionId !== this[PRIVATE$15].id) { + return; + } + this[PRIVATE$15].dispatchInputSourceEvent('selectstart', evt.inputSource); + }; + device.addEventListener('@@webxr-polyfill/input-select-start', this[PRIVATE$15].onSelectStart); + this[PRIVATE$15].onSelectEnd = evt => { + if (evt.sessionId !== this[PRIVATE$15].id) { + return; + } + this[PRIVATE$15].dispatchInputSourceEvent('selectend', evt.inputSource); + this[PRIVATE$15].dispatchInputSourceEvent('select', evt.inputSource); + }; + device.addEventListener('@@webxr-polyfill/input-select-end', this[PRIVATE$15].onSelectEnd); + this[PRIVATE$15].onSqueezeStart = evt => { + if (evt.sessionId !== this[PRIVATE$15].id) { + return; + } + this[PRIVATE$15].dispatchInputSourceEvent('squeezestart', evt.inputSource); + }; + device.addEventListener('@@webxr-polyfill/input-squeeze-start', this[PRIVATE$15].onSqueezeStart); + this[PRIVATE$15].onSqueezeEnd = evt => { + if (evt.sessionId !== this[PRIVATE$15].id) { + return; + } + this[PRIVATE$15].dispatchInputSourceEvent('squeezeend', evt.inputSource); + this[PRIVATE$15].dispatchInputSourceEvent('squeeze', evt.inputSource); + }; + device.addEventListener('@@webxr-polyfill/input-squeeze-end', this[PRIVATE$15].onSqueezeEnd); + this[PRIVATE$15].dispatchInputSourceEvent = (type, inputSource) => { + const frame = new XRFrame(device, this, this[PRIVATE$15].id); + const event = new XRInputSourceEvent(type, { frame, inputSource }); + frame[PRIVATE$9].active = true; + this.dispatchEvent(type, event); + frame[PRIVATE$9].active = false; + }; + this[PRIVATE$15].startDeviceFrameLoop(); + this.onblur = undefined; + this.onfocus = undefined; + this.onresetpose = undefined; + this.onend = undefined; + this.onselect = undefined; + this.onselectstart = undefined; + this.onselectend = undefined; + } + get renderState() { return this[PRIVATE$15].activeRenderState; } + get environmentBlendMode() { + return this[PRIVATE$15].device.environmentBlendMode || 'opaque'; + } + async requestReferenceSpace(type) { + if (this[PRIVATE$15].ended) { + return; + } + if (!XRReferenceSpaceTypes.includes(type)) { + throw new TypeError(`XRReferenceSpaceType must be one of ${XRReferenceSpaceTypes}`); + } + if (!this[PRIVATE$15].device.doesSessionSupportReferenceSpace(this[PRIVATE$15].id, type)) { + throw new DOMException(`The ${type} reference space is not supported by this session.`, 'NotSupportedError'); + } + if (type === 'viewer') { + return this[PRIVATE$15].viewerSpace; + } + let transform = await this[PRIVATE$15].device.requestFrameOfReferenceTransform(type); + if (type === 'bounded-floor') { + if (!transform) { + throw new DOMException(`${type} XRReferenceSpace not supported by this device.`, 'NotSupportedError'); + } + let bounds = this[PRIVATE$15].device.requestStageBounds(); + if (!bounds) { + throw new DOMException(`${type} XRReferenceSpace not supported by this device.`, 'NotSupportedError'); + } + throw new DOMException(`The WebXR polyfill does not support the ${type} reference space yet.`, 'NotSupportedError'); + } + return new XRReferenceSpace(type, transform); + } + requestAnimationFrame(callback) { + if (this[PRIVATE$15].ended) { + return; + } + const handle = ++this[PRIVATE$15].frameHandle; + this[PRIVATE$15].frameCallbacks.push({ + handle, + callback, + cancelled: false + }); + return handle; + } + cancelAnimationFrame(handle) { + let callbacks = this[PRIVATE$15].frameCallbacks; + let index = callbacks.findIndex(d => d && d.handle === handle); + if (index > -1) { + callbacks[index].cancelled = true; + callbacks.splice(index, 1); + } + callbacks = this[PRIVATE$15].currentFrameCallbacks; + if (callbacks) { + index = callbacks.findIndex(d => d && d.handle === handle); + if (index > -1) { + callbacks[index].cancelled = true; + } + } + } + get inputSources() { + return this[PRIVATE$15].device.getInputSources(); + } + async end() { + if (this[PRIVATE$15].ended) { + return; + } + if (this.immersive) { + this[PRIVATE$15].ended = true; + this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/vr-present-start', + this[PRIVATE$15].onPresentationStart); + this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/vr-present-end', + this[PRIVATE$15].onPresentationEnd); + this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/input-select-start', + this[PRIVATE$15].onSelectStart); + this[PRIVATE$15].device.removeEventListener('@@webvr-polyfill/input-select-end', + this[PRIVATE$15].onSelectEnd); + this.dispatchEvent('end', new XRSessionEvent('end', { session: this })); + } + this[PRIVATE$15].stopDeviceFrameLoop(); + return this[PRIVATE$15].device.endSession(this[PRIVATE$15].id); + } + updateRenderState(newState) { + if (this[PRIVATE$15].ended) { + const message = "Can't call updateRenderState on an XRSession " + + "that has already ended."; + throw new Error(message); + } + if (newState.baseLayer && (newState.baseLayer._session !== this)) { + const message = "Called updateRenderState with a base layer that was " + + "created by a different session."; + throw new Error(message); + } + const fovSet = (newState.inlineVerticalFieldOfView !== null) && + (newState.inlineVerticalFieldOfView !== undefined); + if (fovSet) { + if (this[PRIVATE$15].immersive) { + const message = "inlineVerticalFieldOfView must not be set for an " + + "XRRenderState passed to updateRenderState for an " + + "immersive session."; + throw new Error(message); + } else { + newState.inlineVerticalFieldOfView = Math.min( + 3.13, Math.max(0.01, newState.inlineVerticalFieldOfView)); + } + } + if (this[PRIVATE$15].pendingRenderState === null) { + const activeRenderState = this[PRIVATE$15].activeRenderState; + this[PRIVATE$15].pendingRenderState = { + depthNear: activeRenderState.depthNear, + depthFar: activeRenderState.depthFar, + inlineVerticalFieldOfView: activeRenderState.inlineVerticalFieldOfView, + baseLayer: activeRenderState.baseLayer + }; + } + Object.assign(this[PRIVATE$15].pendingRenderState, newState); + } + _checkInputSourcesChange() { + const added = []; + const removed = []; + const newInputSources = this.inputSources; + const oldInputSources = this[PRIVATE$15].currentInputSources; + for (const newInputSource of newInputSources) { + if (!oldInputSources.includes(newInputSource)) { + added.push(newInputSource); + } + } + for (const oldInputSource of oldInputSources) { + if (!newInputSources.includes(oldInputSource)) { + removed.push(oldInputSource); + } + } + if (added.length > 0 || removed.length > 0) { + this.dispatchEvent('inputsourceschange', new XRInputSourcesChangeEvent('inputsourceschange', { + session: this, + added: added, + removed: removed + })); + } + this[PRIVATE$15].currentInputSources.length = 0; + for (const newInputSource of newInputSources) { + this[PRIVATE$15].currentInputSources.push(newInputSource); + } + } +} + +const PRIVATE$16 = Symbol('@@webxr-polyfill/XRInputSource'); +class XRInputSource { + constructor(impl) { + this[PRIVATE$16] = { + impl, + gripSpace: new XRSpace("grip", this), + targetRaySpace: new XRSpace("target-ray", this) + }; + } + get handedness() { return this[PRIVATE$16].impl.handedness; } + get targetRayMode() { return this[PRIVATE$16].impl.targetRayMode; } + get gripSpace() { + let mode = this[PRIVATE$16].impl.targetRayMode; + if (mode === "gaze" || mode === "screen") { + return null; + } + return this[PRIVATE$16].gripSpace; + } + get targetRaySpace() { return this[PRIVATE$16].targetRaySpace; } + get profiles() { return this[PRIVATE$16].impl.profiles; } + get gamepad() { return this[PRIVATE$16].impl.gamepad; } +} + +const PRIVATE$17 = Symbol('@@webxr-polyfill/XRReferenceSpaceEvent'); +class XRReferenceSpaceEvent extends Event { + constructor(type, eventInitDict) { + super(type, eventInitDict); + this[PRIVATE$17] = { + referenceSpace: eventInitDict.referenceSpace, + transform: eventInitDict.transform || null + }; + } + get referenceSpace() { return this[PRIVATE$17].referenceSpace; } + get transform() { return this[PRIVATE$17].transform; } +} + +var API = { + XR, + XRSession: XRSession$1, + XRSessionEvent, + XRFrame, + XRView, + XRViewport, + XRViewerPose, + XRWebGLLayer, + XRSpace, + XRReferenceSpace, + XRReferenceSpaceEvent, + XRInputSource, + XRInputSourceEvent, + XRInputSourcesChangeEvent, + XRRenderState, + XRRigidTransform: XRRigidTransform$1, + XRPose: XRPose$1, +}; + +const polyfillMakeXRCompatible = Context => { + if (typeof Context.prototype.makeXRCompatible === 'function') { + return false; + } + Context.prototype.makeXRCompatible = function () { + this[XR_COMPATIBLE] = true; + return Promise.resolve(); + }; + return true; +}; +const polyfillGetContext = (Canvas) => { + const getContext = Canvas.prototype.getContext; + Canvas.prototype.getContext = function (contextType, glAttribs) { + const ctx = getContext.call(this, contextType, glAttribs); + if (ctx) { + ctx[POLYFILLED_XR_COMPATIBLE] = true; + if (glAttribs && ('xrCompatible' in glAttribs)) { + ctx[XR_COMPATIBLE] = glAttribs.xrCompatible; + } + } + return ctx; + }; +}; + +const isImageBitmapSupported = global => + !!(global.ImageBitmapRenderingContext && + global.createImageBitmap); +const isMobile = global => { + var check = false; + (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true;})(global.navigator.userAgent||global.navigator.vendor||global.opera); + return check; +}; +const applyCanvasStylesForMinimalRendering = canvas => { + canvas.style.display = 'block'; + canvas.style.position = 'absolute'; + canvas.style.width = canvas.style.height = '1px'; + canvas.style.top = canvas.style.left = '0px'; +}; + +var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + + +function unwrapExports (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; +} + +function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; +} + +var cardboardVrDisplay = createCommonjsModule(function (module, exports) { +(function (global, factory) { + module.exports = factory(); +}(commonjsGlobal, (function () { var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +}; +var createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; +}(); +var slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + return _arr; + } + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; +}(); +var MIN_TIMESTEP = 0.001; +var MAX_TIMESTEP = 1; +var dataUri = function dataUri(mimeType, svg) { + return 'data:' + mimeType + ',' + encodeURIComponent(svg); +}; +var lerp = function lerp(a, b, t) { + return a + (b - a) * t; +}; +var isIOS = function () { + var isIOS = /iPad|iPhone|iPod/.test(navigator.platform); + return function () { + return isIOS; + }; +}(); +var isWebViewAndroid = function () { + var isWebViewAndroid = navigator.userAgent.indexOf('Version') !== -1 && navigator.userAgent.indexOf('Android') !== -1 && navigator.userAgent.indexOf('Chrome') !== -1; + return function () { + return isWebViewAndroid; + }; +}(); +var isSafari = function () { + var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); + return function () { + return isSafari; + }; +}(); +var isFirefoxAndroid = function () { + var isFirefoxAndroid = navigator.userAgent.indexOf('Firefox') !== -1 && navigator.userAgent.indexOf('Android') !== -1; + return function () { + return isFirefoxAndroid; + }; +}(); +var getChromeVersion = function () { + var match = navigator.userAgent.match(/.*Chrome\/([0-9]+)/); + var value = match ? parseInt(match[1], 10) : null; + return function () { + return value; + }; +}(); +var isChromeWithoutDeviceMotion = function () { + var value = false; + if (getChromeVersion() === 65) { + var match = navigator.userAgent.match(/.*Chrome\/([0-9\.]*)/); + if (match) { + var _match$1$split = match[1].split('.'), + _match$1$split2 = slicedToArray(_match$1$split, 4), + major = _match$1$split2[0], + minor = _match$1$split2[1], + branch = _match$1$split2[2], + build = _match$1$split2[3]; + value = parseInt(branch, 10) === 3325 && parseInt(build, 10) < 148; + } + } + return function () { + return value; + }; +}(); +var isR7 = function () { + var isR7 = navigator.userAgent.indexOf('R7 Build') !== -1; + return function () { + return isR7; + }; +}(); +var isLandscapeMode = function isLandscapeMode() { + var rtn = window.orientation == 90 || window.orientation == -90; + return isR7() ? !rtn : rtn; +}; +var isTimestampDeltaValid = function isTimestampDeltaValid(timestampDeltaS) { + if (isNaN(timestampDeltaS)) { + return false; + } + if (timestampDeltaS <= MIN_TIMESTEP) { + return false; + } + if (timestampDeltaS > MAX_TIMESTEP) { + return false; + } + return true; +}; +var getScreenWidth = function getScreenWidth() { + return Math.max(window.screen.width, window.screen.height) * window.devicePixelRatio; +}; +var getScreenHeight = function getScreenHeight() { + return Math.min(window.screen.width, window.screen.height) * window.devicePixelRatio; +}; +var requestFullscreen = function requestFullscreen(element) { + if (isWebViewAndroid()) { + return false; + } + if (element.requestFullscreen) { + element.requestFullscreen(); + } else if (element.webkitRequestFullscreen) { + element.webkitRequestFullscreen(); + } else if (element.mozRequestFullScreen) { + element.mozRequestFullScreen(); + } else if (element.msRequestFullscreen) { + element.msRequestFullscreen(); + } else { + return false; + } + return true; +}; +var exitFullscreen = function exitFullscreen() { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); + } else { + return false; + } + return true; +}; +var getFullscreenElement = function getFullscreenElement() { + return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement; +}; +var linkProgram = function linkProgram(gl, vertexSource, fragmentSource, attribLocationMap) { + var vertexShader = gl.createShader(gl.VERTEX_SHADER); + gl.shaderSource(vertexShader, vertexSource); + gl.compileShader(vertexShader); + var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); + gl.shaderSource(fragmentShader, fragmentSource); + gl.compileShader(fragmentShader); + var program = gl.createProgram(); + gl.attachShader(program, vertexShader); + gl.attachShader(program, fragmentShader); + for (var attribName in attribLocationMap) { + gl.bindAttribLocation(program, attribLocationMap[attribName], attribName); + }gl.linkProgram(program); + gl.deleteShader(vertexShader); + gl.deleteShader(fragmentShader); + return program; +}; +var getProgramUniforms = function getProgramUniforms(gl, program) { + var uniforms = {}; + var uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); + var uniformName = ''; + for (var i = 0; i < uniformCount; i++) { + var uniformInfo = gl.getActiveUniform(program, i); + uniformName = uniformInfo.name.replace('[0]', ''); + uniforms[uniformName] = gl.getUniformLocation(program, uniformName); + } + return uniforms; +}; +var orthoMatrix = function orthoMatrix(out, left, right, bottom, top, near, far) { + var lr = 1 / (left - right), + bt = 1 / (bottom - top), + nf = 1 / (near - far); + out[0] = -2 * lr; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = -2 * bt; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 2 * nf; + out[11] = 0; + out[12] = (left + right) * lr; + out[13] = (top + bottom) * bt; + out[14] = (far + near) * nf; + out[15] = 1; + return out; +}; +var isMobile = function isMobile() { + var check = false; + (function (a) { + if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true; + })(navigator.userAgent || navigator.vendor || window.opera); + return check; +}; +var extend = function extend(dest, src) { + for (var key in src) { + if (src.hasOwnProperty(key)) { + dest[key] = src[key]; + } + } + return dest; +}; +var safariCssSizeWorkaround = function safariCssSizeWorkaround(canvas) { + if (isIOS()) { + var width = canvas.style.width; + var height = canvas.style.height; + canvas.style.width = parseInt(width) + 1 + 'px'; + canvas.style.height = parseInt(height) + 'px'; + setTimeout(function () { + canvas.style.width = width; + canvas.style.height = height; + }, 100); + } + window.canvas = canvas; +}; +var frameDataFromPose = function () { + var piOver180 = Math.PI / 180.0; + var rad45 = Math.PI * 0.25; + function mat4_perspectiveFromFieldOfView(out, fov, near, far) { + var upTan = Math.tan(fov ? fov.upDegrees * piOver180 : rad45), + downTan = Math.tan(fov ? fov.downDegrees * piOver180 : rad45), + leftTan = Math.tan(fov ? fov.leftDegrees * piOver180 : rad45), + rightTan = Math.tan(fov ? fov.rightDegrees * piOver180 : rad45), + xScale = 2.0 / (leftTan + rightTan), + yScale = 2.0 / (upTan + downTan); + out[0] = xScale; + out[1] = 0.0; + out[2] = 0.0; + out[3] = 0.0; + out[4] = 0.0; + out[5] = yScale; + out[6] = 0.0; + out[7] = 0.0; + out[8] = -((leftTan - rightTan) * xScale * 0.5); + out[9] = (upTan - downTan) * yScale * 0.5; + out[10] = far / (near - far); + out[11] = -1.0; + out[12] = 0.0; + out[13] = 0.0; + out[14] = far * near / (near - far); + out[15] = 0.0; + return out; + } + function mat4_fromRotationTranslation(out, q, v) { + var x = q[0], + y = q[1], + z = q[2], + w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + out[0] = 1 - (yy + zz); + out[1] = xy + wz; + out[2] = xz - wy; + out[3] = 0; + out[4] = xy - wz; + out[5] = 1 - (xx + zz); + out[6] = yz + wx; + out[7] = 0; + out[8] = xz + wy; + out[9] = yz - wx; + out[10] = 1 - (xx + yy); + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + return out; + } + function mat4_translate(out, a, v) { + var x = v[0], + y = v[1], + z = v[2], + a00, + a01, + a02, + a03, + a10, + a11, + a12, + a13, + a20, + a21, + a22, + a23; + if (a === out) { + out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; + out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; + out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; + out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; + } else { + a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3]; + a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7]; + a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11]; + out[0] = a00;out[1] = a01;out[2] = a02;out[3] = a03; + out[4] = a10;out[5] = a11;out[6] = a12;out[7] = a13; + out[8] = a20;out[9] = a21;out[10] = a22;out[11] = a23; + out[12] = a00 * x + a10 * y + a20 * z + a[12]; + out[13] = a01 * x + a11 * y + a21 * z + a[13]; + out[14] = a02 * x + a12 * y + a22 * z + a[14]; + out[15] = a03 * x + a13 * y + a23 * z + a[15]; + } + return out; + } + function mat4_invert(out, a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3], + a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7], + a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11], + a30 = a[12], + a31 = a[13], + a32 = a[14], + a33 = a[15], + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + if (!det) { + return null; + } + det = 1.0 / det; + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; + out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; + out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; + out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; + out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; + out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; + out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; + return out; + } + var defaultOrientation = new Float32Array([0, 0, 0, 1]); + var defaultPosition = new Float32Array([0, 0, 0]); + function updateEyeMatrices(projection, view, pose, fov, offset, vrDisplay) { + mat4_perspectiveFromFieldOfView(projection, fov || null, vrDisplay.depthNear, vrDisplay.depthFar); + var orientation = pose.orientation || defaultOrientation; + var position = pose.position || defaultPosition; + mat4_fromRotationTranslation(view, orientation, position); + if (offset) mat4_translate(view, view, offset); + mat4_invert(view, view); + } + return function (frameData, pose, vrDisplay) { + if (!frameData || !pose) return false; + frameData.pose = pose; + frameData.timestamp = pose.timestamp; + updateEyeMatrices(frameData.leftProjectionMatrix, frameData.leftViewMatrix, pose, vrDisplay._getFieldOfView("left"), vrDisplay._getEyeOffset("left"), vrDisplay); + updateEyeMatrices(frameData.rightProjectionMatrix, frameData.rightViewMatrix, pose, vrDisplay._getFieldOfView("right"), vrDisplay._getEyeOffset("right"), vrDisplay); + return true; + }; +}(); +var isInsideCrossOriginIFrame = function isInsideCrossOriginIFrame() { + var isFramed = window.self !== window.top; + var refOrigin = getOriginFromUrl(document.referrer); + var thisOrigin = getOriginFromUrl(window.location.href); + return isFramed && refOrigin !== thisOrigin; +}; +var getOriginFromUrl = function getOriginFromUrl(url) { + var domainIdx; + var protoSepIdx = url.indexOf("://"); + if (protoSepIdx !== -1) { + domainIdx = protoSepIdx + 3; + } else { + domainIdx = 0; + } + var domainEndIdx = url.indexOf('/', domainIdx); + if (domainEndIdx === -1) { + domainEndIdx = url.length; + } + return url.substring(0, domainEndIdx); +}; +var getQuaternionAngle = function getQuaternionAngle(quat) { + if (quat.w > 1) { + console.warn('getQuaternionAngle: w > 1'); + return 0; + } + var angle = 2 * Math.acos(quat.w); + return angle; +}; +var warnOnce = function () { + var observedWarnings = {}; + return function (key, message) { + if (observedWarnings[key] === undefined) { + console.warn('webvr-polyfill: ' + message); + observedWarnings[key] = true; + } + }; +}(); +var deprecateWarning = function deprecateWarning(deprecated, suggested) { + var alternative = suggested ? 'Please use ' + suggested + ' instead.' : ''; + warnOnce(deprecated, deprecated + ' has been deprecated. ' + 'This may not work on native WebVR displays. ' + alternative); +}; +function WGLUPreserveGLState(gl, bindings, callback) { + if (!bindings) { + callback(gl); + return; + } + var boundValues = []; + var activeTexture = null; + for (var i = 0; i < bindings.length; ++i) { + var binding = bindings[i]; + switch (binding) { + case gl.TEXTURE_BINDING_2D: + case gl.TEXTURE_BINDING_CUBE_MAP: + var textureUnit = bindings[++i]; + if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) { + console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit"); + boundValues.push(null, null); + break; + } + if (!activeTexture) { + activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE); + } + gl.activeTexture(textureUnit); + boundValues.push(gl.getParameter(binding), null); + break; + case gl.ACTIVE_TEXTURE: + activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE); + boundValues.push(null); + break; + default: + boundValues.push(gl.getParameter(binding)); + break; + } + } + callback(gl); + for (var i = 0; i < bindings.length; ++i) { + var binding = bindings[i]; + var boundValue = boundValues[i]; + switch (binding) { + case gl.ACTIVE_TEXTURE: + break; + case gl.ARRAY_BUFFER_BINDING: + gl.bindBuffer(gl.ARRAY_BUFFER, boundValue); + break; + case gl.COLOR_CLEAR_VALUE: + gl.clearColor(boundValue[0], boundValue[1], boundValue[2], boundValue[3]); + break; + case gl.COLOR_WRITEMASK: + gl.colorMask(boundValue[0], boundValue[1], boundValue[2], boundValue[3]); + break; + case gl.CURRENT_PROGRAM: + gl.useProgram(boundValue); + break; + case gl.ELEMENT_ARRAY_BUFFER_BINDING: + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boundValue); + break; + case gl.FRAMEBUFFER_BINDING: + gl.bindFramebuffer(gl.FRAMEBUFFER, boundValue); + break; + case gl.RENDERBUFFER_BINDING: + gl.bindRenderbuffer(gl.RENDERBUFFER, boundValue); + break; + case gl.TEXTURE_BINDING_2D: + var textureUnit = bindings[++i]; + if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) + break; + gl.activeTexture(textureUnit); + gl.bindTexture(gl.TEXTURE_2D, boundValue); + break; + case gl.TEXTURE_BINDING_CUBE_MAP: + var textureUnit = bindings[++i]; + if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) + break; + gl.activeTexture(textureUnit); + gl.bindTexture(gl.TEXTURE_CUBE_MAP, boundValue); + break; + case gl.VIEWPORT: + gl.viewport(boundValue[0], boundValue[1], boundValue[2], boundValue[3]); + break; + case gl.BLEND: + case gl.CULL_FACE: + case gl.DEPTH_TEST: + case gl.SCISSOR_TEST: + case gl.STENCIL_TEST: + if (boundValue) { + gl.enable(binding); + } else { + gl.disable(binding); + } + break; + default: + console.log("No GL restore behavior for 0x" + binding.toString(16)); + break; + } + if (activeTexture) { + gl.activeTexture(activeTexture); + } + } +} +var glPreserveState = WGLUPreserveGLState; +var distortionVS = ['attribute vec2 position;', 'attribute vec3 texCoord;', 'varying vec2 vTexCoord;', 'uniform vec4 viewportOffsetScale[2];', 'void main() {', ' vec4 viewport = viewportOffsetScale[int(texCoord.z)];', ' vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;', ' gl_Position = vec4( position, 1.0, 1.0 );', '}'].join('\n'); +var distortionFS = ['precision mediump float;', 'uniform sampler2D diffuse;', 'varying vec2 vTexCoord;', 'void main() {', ' gl_FragColor = texture2D(diffuse, vTexCoord);', '}'].join('\n'); +function CardboardDistorter(gl, cardboardUI, bufferScale, dirtySubmitFrameBindings) { + this.gl = gl; + this.cardboardUI = cardboardUI; + this.bufferScale = bufferScale; + this.dirtySubmitFrameBindings = dirtySubmitFrameBindings; + this.ctxAttribs = gl.getContextAttributes(); + this.meshWidth = 20; + this.meshHeight = 20; + this.bufferWidth = gl.drawingBufferWidth; + this.bufferHeight = gl.drawingBufferHeight; + this.realBindFramebuffer = gl.bindFramebuffer; + this.realEnable = gl.enable; + this.realDisable = gl.disable; + this.realColorMask = gl.colorMask; + this.realClearColor = gl.clearColor; + this.realViewport = gl.viewport; + if (!isIOS()) { + this.realCanvasWidth = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'width'); + this.realCanvasHeight = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'height'); + } + this.isPatched = false; + this.lastBoundFramebuffer = null; + this.cullFace = false; + this.depthTest = false; + this.blend = false; + this.scissorTest = false; + this.stencilTest = false; + this.viewport = [0, 0, 0, 0]; + this.colorMask = [true, true, true, true]; + this.clearColor = [0, 0, 0, 0]; + this.attribs = { + position: 0, + texCoord: 1 + }; + this.program = linkProgram(gl, distortionVS, distortionFS, this.attribs); + this.uniforms = getProgramUniforms(gl, this.program); + this.viewportOffsetScale = new Float32Array(8); + this.setTextureBounds(); + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + this.indexCount = 0; + this.renderTarget = gl.createTexture(); + this.framebuffer = gl.createFramebuffer(); + this.depthStencilBuffer = null; + this.depthBuffer = null; + this.stencilBuffer = null; + if (this.ctxAttribs.depth && this.ctxAttribs.stencil) { + this.depthStencilBuffer = gl.createRenderbuffer(); + } else if (this.ctxAttribs.depth) { + this.depthBuffer = gl.createRenderbuffer(); + } else if (this.ctxAttribs.stencil) { + this.stencilBuffer = gl.createRenderbuffer(); + } + this.patch(); + this.onResize(); +} +CardboardDistorter.prototype.destroy = function () { + var gl = this.gl; + this.unpatch(); + gl.deleteProgram(this.program); + gl.deleteBuffer(this.vertexBuffer); + gl.deleteBuffer(this.indexBuffer); + gl.deleteTexture(this.renderTarget); + gl.deleteFramebuffer(this.framebuffer); + if (this.depthStencilBuffer) { + gl.deleteRenderbuffer(this.depthStencilBuffer); + } + if (this.depthBuffer) { + gl.deleteRenderbuffer(this.depthBuffer); + } + if (this.stencilBuffer) { + gl.deleteRenderbuffer(this.stencilBuffer); + } + if (this.cardboardUI) { + this.cardboardUI.destroy(); + } +}; +CardboardDistorter.prototype.onResize = function () { + var gl = this.gl; + var self = this; + var glState = [gl.RENDERBUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0]; + glPreserveState(gl, glState, function (gl) { + self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null); + if (self.scissorTest) { + self.realDisable.call(gl, gl.SCISSOR_TEST); + } + self.realColorMask.call(gl, true, true, true, true); + self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + self.realClearColor.call(gl, 0, 0, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.framebuffer); + gl.bindTexture(gl.TEXTURE_2D, self.renderTarget); + gl.texImage2D(gl.TEXTURE_2D, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, self.bufferWidth, self.bufferHeight, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, self.renderTarget, 0); + if (self.ctxAttribs.depth && self.ctxAttribs.stencil) { + gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthStencilBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, self.bufferWidth, self.bufferHeight); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.depthStencilBuffer); + } else if (self.ctxAttribs.depth) { + gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, self.bufferWidth, self.bufferHeight); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, self.depthBuffer); + } else if (self.ctxAttribs.stencil) { + gl.bindRenderbuffer(gl.RENDERBUFFER, self.stencilBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, self.bufferWidth, self.bufferHeight); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.stencilBuffer); + } + if (!gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) { + console.error('Framebuffer incomplete!'); + } + self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer); + if (self.scissorTest) { + self.realEnable.call(gl, gl.SCISSOR_TEST); + } + self.realColorMask.apply(gl, self.colorMask); + self.realViewport.apply(gl, self.viewport); + self.realClearColor.apply(gl, self.clearColor); + }); + if (this.cardboardUI) { + this.cardboardUI.onResize(); + } +}; +CardboardDistorter.prototype.patch = function () { + if (this.isPatched) { + return; + } + var self = this; + var canvas = this.gl.canvas; + var gl = this.gl; + if (!isIOS()) { + canvas.width = getScreenWidth() * this.bufferScale; + canvas.height = getScreenHeight() * this.bufferScale; + Object.defineProperty(canvas, 'width', { + configurable: true, + enumerable: true, + get: function get() { + return self.bufferWidth; + }, + set: function set(value) { + self.bufferWidth = value; + self.realCanvasWidth.set.call(canvas, value); + self.onResize(); + } + }); + Object.defineProperty(canvas, 'height', { + configurable: true, + enumerable: true, + get: function get() { + return self.bufferHeight; + }, + set: function set(value) { + self.bufferHeight = value; + self.realCanvasHeight.set.call(canvas, value); + self.onResize(); + } + }); + } + this.lastBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING); + if (this.lastBoundFramebuffer == null) { + this.lastBoundFramebuffer = this.framebuffer; + this.gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer); + } + this.gl.bindFramebuffer = function (target, framebuffer) { + self.lastBoundFramebuffer = framebuffer ? framebuffer : self.framebuffer; + self.realBindFramebuffer.call(gl, target, self.lastBoundFramebuffer); + }; + this.cullFace = gl.getParameter(gl.CULL_FACE); + this.depthTest = gl.getParameter(gl.DEPTH_TEST); + this.blend = gl.getParameter(gl.BLEND); + this.scissorTest = gl.getParameter(gl.SCISSOR_TEST); + this.stencilTest = gl.getParameter(gl.STENCIL_TEST); + gl.enable = function (pname) { + switch (pname) { + case gl.CULL_FACE: + self.cullFace = true;break; + case gl.DEPTH_TEST: + self.depthTest = true;break; + case gl.BLEND: + self.blend = true;break; + case gl.SCISSOR_TEST: + self.scissorTest = true;break; + case gl.STENCIL_TEST: + self.stencilTest = true;break; + } + self.realEnable.call(gl, pname); + }; + gl.disable = function (pname) { + switch (pname) { + case gl.CULL_FACE: + self.cullFace = false;break; + case gl.DEPTH_TEST: + self.depthTest = false;break; + case gl.BLEND: + self.blend = false;break; + case gl.SCISSOR_TEST: + self.scissorTest = false;break; + case gl.STENCIL_TEST: + self.stencilTest = false;break; + } + self.realDisable.call(gl, pname); + }; + this.colorMask = gl.getParameter(gl.COLOR_WRITEMASK); + gl.colorMask = function (r, g, b, a) { + self.colorMask[0] = r; + self.colorMask[1] = g; + self.colorMask[2] = b; + self.colorMask[3] = a; + self.realColorMask.call(gl, r, g, b, a); + }; + this.clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE); + gl.clearColor = function (r, g, b, a) { + self.clearColor[0] = r; + self.clearColor[1] = g; + self.clearColor[2] = b; + self.clearColor[3] = a; + self.realClearColor.call(gl, r, g, b, a); + }; + this.viewport = gl.getParameter(gl.VIEWPORT); + gl.viewport = function (x, y, w, h) { + self.viewport[0] = x; + self.viewport[1] = y; + self.viewport[2] = w; + self.viewport[3] = h; + self.realViewport.call(gl, x, y, w, h); + }; + this.isPatched = true; + safariCssSizeWorkaround(canvas); +}; +CardboardDistorter.prototype.unpatch = function () { + if (!this.isPatched) { + return; + } + var gl = this.gl; + var canvas = this.gl.canvas; + if (!isIOS()) { + Object.defineProperty(canvas, 'width', this.realCanvasWidth); + Object.defineProperty(canvas, 'height', this.realCanvasHeight); + } + canvas.width = this.bufferWidth; + canvas.height = this.bufferHeight; + gl.bindFramebuffer = this.realBindFramebuffer; + gl.enable = this.realEnable; + gl.disable = this.realDisable; + gl.colorMask = this.realColorMask; + gl.clearColor = this.realClearColor; + gl.viewport = this.realViewport; + if (this.lastBoundFramebuffer == this.framebuffer) { + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + } + this.isPatched = false; + setTimeout(function () { + safariCssSizeWorkaround(canvas); + }, 1); +}; +CardboardDistorter.prototype.setTextureBounds = function (leftBounds, rightBounds) { + if (!leftBounds) { + leftBounds = [0, 0, 0.5, 1]; + } + if (!rightBounds) { + rightBounds = [0.5, 0, 0.5, 1]; + } + this.viewportOffsetScale[0] = leftBounds[0]; + this.viewportOffsetScale[1] = leftBounds[1]; + this.viewportOffsetScale[2] = leftBounds[2]; + this.viewportOffsetScale[3] = leftBounds[3]; + this.viewportOffsetScale[4] = rightBounds[0]; + this.viewportOffsetScale[5] = rightBounds[1]; + this.viewportOffsetScale[6] = rightBounds[2]; + this.viewportOffsetScale[7] = rightBounds[3]; +}; +CardboardDistorter.prototype.submitFrame = function () { + var gl = this.gl; + var self = this; + var glState = []; + if (!this.dirtySubmitFrameBindings) { + glState.push(gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0); + } + glPreserveState(gl, glState, function (gl) { + self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null); + if (self.cullFace) { + self.realDisable.call(gl, gl.CULL_FACE); + } + if (self.depthTest) { + self.realDisable.call(gl, gl.DEPTH_TEST); + } + if (self.blend) { + self.realDisable.call(gl, gl.BLEND); + } + if (self.scissorTest) { + self.realDisable.call(gl, gl.SCISSOR_TEST); + } + if (self.stencilTest) { + self.realDisable.call(gl, gl.STENCIL_TEST); + } + self.realColorMask.call(gl, true, true, true, true); + self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + if (self.ctxAttribs.alpha || isIOS()) { + self.realClearColor.call(gl, 0, 0, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + } + gl.useProgram(self.program); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer); + gl.enableVertexAttribArray(self.attribs.position); + gl.enableVertexAttribArray(self.attribs.texCoord); + gl.vertexAttribPointer(self.attribs.position, 2, gl.FLOAT, false, 20, 0); + gl.vertexAttribPointer(self.attribs.texCoord, 3, gl.FLOAT, false, 20, 8); + gl.activeTexture(gl.TEXTURE0); + gl.uniform1i(self.uniforms.diffuse, 0); + gl.bindTexture(gl.TEXTURE_2D, self.renderTarget); + gl.uniform4fv(self.uniforms.viewportOffsetScale, self.viewportOffsetScale); + gl.drawElements(gl.TRIANGLES, self.indexCount, gl.UNSIGNED_SHORT, 0); + if (self.cardboardUI) { + self.cardboardUI.renderNoState(); + } + self.realBindFramebuffer.call(self.gl, gl.FRAMEBUFFER, self.framebuffer); + if (!self.ctxAttribs.preserveDrawingBuffer) { + self.realClearColor.call(gl, 0, 0, 0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + } + if (!self.dirtySubmitFrameBindings) { + self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer); + } + if (self.cullFace) { + self.realEnable.call(gl, gl.CULL_FACE); + } + if (self.depthTest) { + self.realEnable.call(gl, gl.DEPTH_TEST); + } + if (self.blend) { + self.realEnable.call(gl, gl.BLEND); + } + if (self.scissorTest) { + self.realEnable.call(gl, gl.SCISSOR_TEST); + } + if (self.stencilTest) { + self.realEnable.call(gl, gl.STENCIL_TEST); + } + self.realColorMask.apply(gl, self.colorMask); + self.realViewport.apply(gl, self.viewport); + if (self.ctxAttribs.alpha || !self.ctxAttribs.preserveDrawingBuffer) { + self.realClearColor.apply(gl, self.clearColor); + } + }); + if (isIOS()) { + var canvas = gl.canvas; + if (canvas.width != self.bufferWidth || canvas.height != self.bufferHeight) { + self.bufferWidth = canvas.width; + self.bufferHeight = canvas.height; + self.onResize(); + } + } +}; +CardboardDistorter.prototype.updateDeviceInfo = function (deviceInfo) { + var gl = this.gl; + var self = this; + var glState = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING]; + glPreserveState(gl, glState, function (gl) { + var vertices = self.computeMeshVertices_(self.meshWidth, self.meshHeight, deviceInfo); + gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); + if (!self.indexCount) { + var indices = self.computeMeshIndices_(self.meshWidth, self.meshHeight); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); + self.indexCount = indices.length; + } + }); +}; +CardboardDistorter.prototype.computeMeshVertices_ = function (width, height, deviceInfo) { + var vertices = new Float32Array(2 * width * height * 5); + var lensFrustum = deviceInfo.getLeftEyeVisibleTanAngles(); + var noLensFrustum = deviceInfo.getLeftEyeNoLensTanAngles(); + var viewport = deviceInfo.getLeftEyeVisibleScreenRect(noLensFrustum); + var vidx = 0; + for (var e = 0; e < 2; e++) { + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++, vidx++) { + var u = i / (width - 1); + var v = j / (height - 1); + var s = u; + var t = v; + var x = lerp(lensFrustum[0], lensFrustum[2], u); + var y = lerp(lensFrustum[3], lensFrustum[1], v); + var d = Math.sqrt(x * x + y * y); + var r = deviceInfo.distortion.distortInverse(d); + var p = x * r / d; + var q = y * r / d; + u = (p - noLensFrustum[0]) / (noLensFrustum[2] - noLensFrustum[0]); + v = (q - noLensFrustum[3]) / (noLensFrustum[1] - noLensFrustum[3]); + u = (viewport.x + u * viewport.width - 0.5) * 2.0; + v = (viewport.y + v * viewport.height - 0.5) * 2.0; + vertices[vidx * 5 + 0] = u; + vertices[vidx * 5 + 1] = v; + vertices[vidx * 5 + 2] = s; + vertices[vidx * 5 + 3] = t; + vertices[vidx * 5 + 4] = e; + } + } + var w = lensFrustum[2] - lensFrustum[0]; + lensFrustum[0] = -(w + lensFrustum[0]); + lensFrustum[2] = w - lensFrustum[2]; + w = noLensFrustum[2] - noLensFrustum[0]; + noLensFrustum[0] = -(w + noLensFrustum[0]); + noLensFrustum[2] = w - noLensFrustum[2]; + viewport.x = 1 - (viewport.x + viewport.width); + } + return vertices; +}; +CardboardDistorter.prototype.computeMeshIndices_ = function (width, height) { + var indices = new Uint16Array(2 * (width - 1) * (height - 1) * 6); + var halfwidth = width / 2; + var halfheight = height / 2; + var vidx = 0; + var iidx = 0; + for (var e = 0; e < 2; e++) { + for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++, vidx++) { + if (i == 0 || j == 0) continue; + if (i <= halfwidth == j <= halfheight) { + indices[iidx++] = vidx; + indices[iidx++] = vidx - width - 1; + indices[iidx++] = vidx - width; + indices[iidx++] = vidx - width - 1; + indices[iidx++] = vidx; + indices[iidx++] = vidx - 1; + } else { + indices[iidx++] = vidx - 1; + indices[iidx++] = vidx - width; + indices[iidx++] = vidx; + indices[iidx++] = vidx - width; + indices[iidx++] = vidx - 1; + indices[iidx++] = vidx - width - 1; + } + } + } + } + return indices; +}; +CardboardDistorter.prototype.getOwnPropertyDescriptor_ = function (proto, attrName) { + var descriptor = Object.getOwnPropertyDescriptor(proto, attrName); + if (descriptor.get === undefined || descriptor.set === undefined) { + descriptor.configurable = true; + descriptor.enumerable = true; + descriptor.get = function () { + return this.getAttribute(attrName); + }; + descriptor.set = function (val) { + this.setAttribute(attrName, val); + }; + } + return descriptor; +}; +var uiVS = ['attribute vec2 position;', 'uniform mat4 projectionMat;', 'void main() {', ' gl_Position = projectionMat * vec4( position, -1.0, 1.0 );', '}'].join('\n'); +var uiFS = ['precision mediump float;', 'uniform vec4 color;', 'void main() {', ' gl_FragColor = color;', '}'].join('\n'); +var DEG2RAD = Math.PI / 180.0; +var kAnglePerGearSection = 60; +var kOuterRimEndAngle = 12; +var kInnerRimBeginAngle = 20; +var kOuterRadius = 1; +var kMiddleRadius = 0.75; +var kInnerRadius = 0.3125; +var kCenterLineThicknessDp = 4; +var kButtonWidthDp = 28; +var kTouchSlopFactor = 1.5; +function CardboardUI(gl) { + this.gl = gl; + this.attribs = { + position: 0 + }; + this.program = linkProgram(gl, uiVS, uiFS, this.attribs); + this.uniforms = getProgramUniforms(gl, this.program); + this.vertexBuffer = gl.createBuffer(); + this.gearOffset = 0; + this.gearVertexCount = 0; + this.arrowOffset = 0; + this.arrowVertexCount = 0; + this.projMat = new Float32Array(16); + this.listener = null; + this.onResize(); +} +CardboardUI.prototype.destroy = function () { + var gl = this.gl; + if (this.listener) { + gl.canvas.removeEventListener('click', this.listener, false); + } + gl.deleteProgram(this.program); + gl.deleteBuffer(this.vertexBuffer); +}; +CardboardUI.prototype.listen = function (optionsCallback, backCallback) { + var canvas = this.gl.canvas; + this.listener = function (event) { + var midline = canvas.clientWidth / 2; + var buttonSize = kButtonWidthDp * kTouchSlopFactor; + if (event.clientX > midline - buttonSize && event.clientX < midline + buttonSize && event.clientY > canvas.clientHeight - buttonSize) { + optionsCallback(event); + } + else if (event.clientX < buttonSize && event.clientY < buttonSize) { + backCallback(event); + } + }; + canvas.addEventListener('click', this.listener, false); +}; +CardboardUI.prototype.onResize = function () { + var gl = this.gl; + var self = this; + var glState = [gl.ARRAY_BUFFER_BINDING]; + glPreserveState(gl, glState, function (gl) { + var vertices = []; + var midline = gl.drawingBufferWidth / 2; + var physicalPixels = Math.max(screen.width, screen.height) * window.devicePixelRatio; + var scalingRatio = gl.drawingBufferWidth / physicalPixels; + var dps = scalingRatio * window.devicePixelRatio; + var lineWidth = kCenterLineThicknessDp * dps / 2; + var buttonSize = kButtonWidthDp * kTouchSlopFactor * dps; + var buttonScale = kButtonWidthDp * dps / 2; + var buttonBorder = (kButtonWidthDp * kTouchSlopFactor - kButtonWidthDp) * dps; + vertices.push(midline - lineWidth, buttonSize); + vertices.push(midline - lineWidth, gl.drawingBufferHeight); + vertices.push(midline + lineWidth, buttonSize); + vertices.push(midline + lineWidth, gl.drawingBufferHeight); + self.gearOffset = vertices.length / 2; + function addGearSegment(theta, r) { + var angle = (90 - theta) * DEG2RAD; + var x = Math.cos(angle); + var y = Math.sin(angle); + vertices.push(kInnerRadius * x * buttonScale + midline, kInnerRadius * y * buttonScale + buttonScale); + vertices.push(r * x * buttonScale + midline, r * y * buttonScale + buttonScale); + } + for (var i = 0; i <= 6; i++) { + var segmentTheta = i * kAnglePerGearSection; + addGearSegment(segmentTheta, kOuterRadius); + addGearSegment(segmentTheta + kOuterRimEndAngle, kOuterRadius); + addGearSegment(segmentTheta + kInnerRimBeginAngle, kMiddleRadius); + addGearSegment(segmentTheta + (kAnglePerGearSection - kInnerRimBeginAngle), kMiddleRadius); + addGearSegment(segmentTheta + (kAnglePerGearSection - kOuterRimEndAngle), kOuterRadius); + } + self.gearVertexCount = vertices.length / 2 - self.gearOffset; + self.arrowOffset = vertices.length / 2; + function addArrowVertex(x, y) { + vertices.push(buttonBorder + x, gl.drawingBufferHeight - buttonBorder - y); + } + var angledLineWidth = lineWidth / Math.sin(45 * DEG2RAD); + addArrowVertex(0, buttonScale); + addArrowVertex(buttonScale, 0); + addArrowVertex(buttonScale + angledLineWidth, angledLineWidth); + addArrowVertex(angledLineWidth, buttonScale + angledLineWidth); + addArrowVertex(angledLineWidth, buttonScale - angledLineWidth); + addArrowVertex(0, buttonScale); + addArrowVertex(buttonScale, buttonScale * 2); + addArrowVertex(buttonScale + angledLineWidth, buttonScale * 2 - angledLineWidth); + addArrowVertex(angledLineWidth, buttonScale - angledLineWidth); + addArrowVertex(0, buttonScale); + addArrowVertex(angledLineWidth, buttonScale - lineWidth); + addArrowVertex(kButtonWidthDp * dps, buttonScale - lineWidth); + addArrowVertex(angledLineWidth, buttonScale + lineWidth); + addArrowVertex(kButtonWidthDp * dps, buttonScale + lineWidth); + self.arrowVertexCount = vertices.length / 2 - self.arrowOffset; + gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); + }); +}; +CardboardUI.prototype.render = function () { + var gl = this.gl; + var self = this; + var glState = [gl.CULL_FACE, gl.DEPTH_TEST, gl.BLEND, gl.SCISSOR_TEST, gl.STENCIL_TEST, gl.COLOR_WRITEMASK, gl.VIEWPORT, gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING]; + glPreserveState(gl, glState, function (gl) { + gl.disable(gl.CULL_FACE); + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.BLEND); + gl.disable(gl.SCISSOR_TEST); + gl.disable(gl.STENCIL_TEST); + gl.colorMask(true, true, true, true); + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + self.renderNoState(); + }); +}; +CardboardUI.prototype.renderNoState = function () { + var gl = this.gl; + gl.useProgram(this.program); + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.enableVertexAttribArray(this.attribs.position); + gl.vertexAttribPointer(this.attribs.position, 2, gl.FLOAT, false, 8, 0); + gl.uniform4f(this.uniforms.color, 1.0, 1.0, 1.0, 1.0); + orthoMatrix(this.projMat, 0, gl.drawingBufferWidth, 0, gl.drawingBufferHeight, 0.1, 1024.0); + gl.uniformMatrix4fv(this.uniforms.projectionMat, false, this.projMat); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + gl.drawArrays(gl.TRIANGLE_STRIP, this.gearOffset, this.gearVertexCount); + gl.drawArrays(gl.TRIANGLE_STRIP, this.arrowOffset, this.arrowVertexCount); +}; +function Distortion(coefficients) { + this.coefficients = coefficients; +} +Distortion.prototype.distortInverse = function (radius) { + var r0 = 0; + var r1 = 1; + var dr0 = radius - this.distort(r0); + while (Math.abs(r1 - r0) > 0.0001 ) { + var dr1 = radius - this.distort(r1); + var r2 = r1 - dr1 * ((r1 - r0) / (dr1 - dr0)); + r0 = r1; + r1 = r2; + dr0 = dr1; + } + return r1; +}; +Distortion.prototype.distort = function (radius) { + var r2 = radius * radius; + var ret = 0; + for (var i = 0; i < this.coefficients.length; i++) { + ret = r2 * (ret + this.coefficients[i]); + } + return (ret + 1) * radius; +}; +var degToRad = Math.PI / 180; +var radToDeg = 180 / Math.PI; +var Vector3 = function Vector3(x, y, z) { + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; +}; +Vector3.prototype = { + constructor: Vector3, + set: function set(x, y, z) { + this.x = x; + this.y = y; + this.z = z; + return this; + }, + copy: function copy(v) { + this.x = v.x; + this.y = v.y; + this.z = v.z; + return this; + }, + length: function length() { + return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); + }, + normalize: function normalize() { + var scalar = this.length(); + if (scalar !== 0) { + var invScalar = 1 / scalar; + this.multiplyScalar(invScalar); + } else { + this.x = 0; + this.y = 0; + this.z = 0; + } + return this; + }, + multiplyScalar: function multiplyScalar(scalar) { + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + }, + applyQuaternion: function applyQuaternion(q) { + var x = this.x; + var y = this.y; + var z = this.z; + var qx = q.x; + var qy = q.y; + var qz = q.z; + var qw = q.w; + var ix = qw * x + qy * z - qz * y; + var iy = qw * y + qz * x - qx * z; + var iz = qw * z + qx * y - qy * x; + var iw = -qx * x - qy * y - qz * z; + this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + return this; + }, + dot: function dot(v) { + return this.x * v.x + this.y * v.y + this.z * v.z; + }, + crossVectors: function crossVectors(a, b) { + var ax = a.x, + ay = a.y, + az = a.z; + var bx = b.x, + by = b.y, + bz = b.z; + this.x = ay * bz - az * by; + this.y = az * bx - ax * bz; + this.z = ax * by - ay * bx; + return this; + } +}; +var Quaternion = function Quaternion(x, y, z, w) { + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + this.w = w !== undefined ? w : 1; +}; +Quaternion.prototype = { + constructor: Quaternion, + set: function set(x, y, z, w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + return this; + }, + copy: function copy(quaternion) { + this.x = quaternion.x; + this.y = quaternion.y; + this.z = quaternion.z; + this.w = quaternion.w; + return this; + }, + setFromEulerXYZ: function setFromEulerXYZ(x, y, z) { + var c1 = Math.cos(x / 2); + var c2 = Math.cos(y / 2); + var c3 = Math.cos(z / 2); + var s1 = Math.sin(x / 2); + var s2 = Math.sin(y / 2); + var s3 = Math.sin(z / 2); + this.x = s1 * c2 * c3 + c1 * s2 * s3; + this.y = c1 * s2 * c3 - s1 * c2 * s3; + this.z = c1 * c2 * s3 + s1 * s2 * c3; + this.w = c1 * c2 * c3 - s1 * s2 * s3; + return this; + }, + setFromEulerYXZ: function setFromEulerYXZ(x, y, z) { + var c1 = Math.cos(x / 2); + var c2 = Math.cos(y / 2); + var c3 = Math.cos(z / 2); + var s1 = Math.sin(x / 2); + var s2 = Math.sin(y / 2); + var s3 = Math.sin(z / 2); + this.x = s1 * c2 * c3 + c1 * s2 * s3; + this.y = c1 * s2 * c3 - s1 * c2 * s3; + this.z = c1 * c2 * s3 - s1 * s2 * c3; + this.w = c1 * c2 * c3 + s1 * s2 * s3; + return this; + }, + setFromAxisAngle: function setFromAxisAngle(axis, angle) { + var halfAngle = angle / 2, + s = Math.sin(halfAngle); + this.x = axis.x * s; + this.y = axis.y * s; + this.z = axis.z * s; + this.w = Math.cos(halfAngle); + return this; + }, + multiply: function multiply(q) { + return this.multiplyQuaternions(this, q); + }, + multiplyQuaternions: function multiplyQuaternions(a, b) { + var qax = a.x, + qay = a.y, + qaz = a.z, + qaw = a.w; + var qbx = b.x, + qby = b.y, + qbz = b.z, + qbw = b.w; + this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + return this; + }, + inverse: function inverse() { + this.x *= -1; + this.y *= -1; + this.z *= -1; + this.normalize(); + return this; + }, + normalize: function normalize() { + var l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); + if (l === 0) { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 1; + } else { + l = 1 / l; + this.x = this.x * l; + this.y = this.y * l; + this.z = this.z * l; + this.w = this.w * l; + } + return this; + }, + slerp: function slerp(qb, t) { + if (t === 0) return this; + if (t === 1) return this.copy(qb); + var x = this.x, + y = this.y, + z = this.z, + w = this.w; + var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z; + if (cosHalfTheta < 0) { + this.w = -qb.w; + this.x = -qb.x; + this.y = -qb.y; + this.z = -qb.z; + cosHalfTheta = -cosHalfTheta; + } else { + this.copy(qb); + } + if (cosHalfTheta >= 1.0) { + this.w = w; + this.x = x; + this.y = y; + this.z = z; + return this; + } + var halfTheta = Math.acos(cosHalfTheta); + var sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); + if (Math.abs(sinHalfTheta) < 0.001) { + this.w = 0.5 * (w + this.w); + this.x = 0.5 * (x + this.x); + this.y = 0.5 * (y + this.y); + this.z = 0.5 * (z + this.z); + return this; + } + var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta, + ratioB = Math.sin(t * halfTheta) / sinHalfTheta; + this.w = w * ratioA + this.w * ratioB; + this.x = x * ratioA + this.x * ratioB; + this.y = y * ratioA + this.y * ratioB; + this.z = z * ratioA + this.z * ratioB; + return this; + }, + setFromUnitVectors: function () { + var v1, r; + var EPS = 0.000001; + return function (vFrom, vTo) { + if (v1 === undefined) v1 = new Vector3(); + r = vFrom.dot(vTo) + 1; + if (r < EPS) { + r = 0; + if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) { + v1.set(-vFrom.y, vFrom.x, 0); + } else { + v1.set(0, -vFrom.z, vFrom.y); + } + } else { + v1.crossVectors(vFrom, vTo); + } + this.x = v1.x; + this.y = v1.y; + this.z = v1.z; + this.w = r; + this.normalize(); + return this; + }; + }() +}; +function Device(params) { + this.width = params.width || getScreenWidth(); + this.height = params.height || getScreenHeight(); + this.widthMeters = params.widthMeters; + this.heightMeters = params.heightMeters; + this.bevelMeters = params.bevelMeters; +} +var DEFAULT_ANDROID = new Device({ + widthMeters: 0.110, + heightMeters: 0.062, + bevelMeters: 0.004 +}); +var DEFAULT_IOS = new Device({ + widthMeters: 0.1038, + heightMeters: 0.0584, + bevelMeters: 0.004 +}); +var Viewers = { + CardboardV1: new CardboardViewer({ + id: 'CardboardV1', + label: 'Cardboard I/O 2014', + fov: 40, + interLensDistance: 0.060, + baselineLensDistance: 0.035, + screenLensDistance: 0.042, + distortionCoefficients: [0.441, 0.156], + inverseCoefficients: [-0.4410035, 0.42756155, -0.4804439, 0.5460139, -0.58821183, 0.5733938, -0.48303202, 0.33299083, -0.17573841, 0.0651772, -0.01488963, 0.001559834] + }), + CardboardV2: new CardboardViewer({ + id: 'CardboardV2', + label: 'Cardboard I/O 2015', + fov: 60, + interLensDistance: 0.064, + baselineLensDistance: 0.035, + screenLensDistance: 0.039, + distortionCoefficients: [0.34, 0.55], + inverseCoefficients: [-0.33836704, -0.18162185, 0.862655, -1.2462051, 1.0560602, -0.58208317, 0.21609078, -0.05444823, 0.009177956, -9.904169E-4, 6.183535E-5, -1.6981803E-6] + }) +}; +function DeviceInfo(deviceParams, additionalViewers) { + this.viewer = Viewers.CardboardV2; + this.updateDeviceParams(deviceParams); + this.distortion = new Distortion(this.viewer.distortionCoefficients); + for (var i = 0; i < additionalViewers.length; i++) { + var viewer = additionalViewers[i]; + Viewers[viewer.id] = new CardboardViewer(viewer); + } +} +DeviceInfo.prototype.updateDeviceParams = function (deviceParams) { + this.device = this.determineDevice_(deviceParams) || this.device; +}; +DeviceInfo.prototype.getDevice = function () { + return this.device; +}; +DeviceInfo.prototype.setViewer = function (viewer) { + this.viewer = viewer; + this.distortion = new Distortion(this.viewer.distortionCoefficients); +}; +DeviceInfo.prototype.determineDevice_ = function (deviceParams) { + if (!deviceParams) { + if (isIOS()) { + console.warn('Using fallback iOS device measurements.'); + return DEFAULT_IOS; + } else { + console.warn('Using fallback Android device measurements.'); + return DEFAULT_ANDROID; + } + } + var METERS_PER_INCH = 0.0254; + var metersPerPixelX = METERS_PER_INCH / deviceParams.xdpi; + var metersPerPixelY = METERS_PER_INCH / deviceParams.ydpi; + var width = getScreenWidth(); + var height = getScreenHeight(); + return new Device({ + widthMeters: metersPerPixelX * width, + heightMeters: metersPerPixelY * height, + bevelMeters: deviceParams.bevelMm * 0.001 + }); +}; +DeviceInfo.prototype.getDistortedFieldOfViewLeftEye = function () { + var viewer = this.viewer; + var device = this.device; + var distortion = this.distortion; + var eyeToScreenDistance = viewer.screenLensDistance; + var outerDist = (device.widthMeters - viewer.interLensDistance) / 2; + var innerDist = viewer.interLensDistance / 2; + var bottomDist = viewer.baselineLensDistance - device.bevelMeters; + var topDist = device.heightMeters - bottomDist; + var outerAngle = radToDeg * Math.atan(distortion.distort(outerDist / eyeToScreenDistance)); + var innerAngle = radToDeg * Math.atan(distortion.distort(innerDist / eyeToScreenDistance)); + var bottomAngle = radToDeg * Math.atan(distortion.distort(bottomDist / eyeToScreenDistance)); + var topAngle = radToDeg * Math.atan(distortion.distort(topDist / eyeToScreenDistance)); + return { + leftDegrees: Math.min(outerAngle, viewer.fov), + rightDegrees: Math.min(innerAngle, viewer.fov), + downDegrees: Math.min(bottomAngle, viewer.fov), + upDegrees: Math.min(topAngle, viewer.fov) + }; +}; +DeviceInfo.prototype.getLeftEyeVisibleTanAngles = function () { + var viewer = this.viewer; + var device = this.device; + var distortion = this.distortion; + var fovLeft = Math.tan(-degToRad * viewer.fov); + var fovTop = Math.tan(degToRad * viewer.fov); + var fovRight = Math.tan(degToRad * viewer.fov); + var fovBottom = Math.tan(-degToRad * viewer.fov); + var halfWidth = device.widthMeters / 4; + var halfHeight = device.heightMeters / 2; + var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight; + var centerX = viewer.interLensDistance / 2 - halfWidth; + var centerY = -verticalLensOffset; + var centerZ = viewer.screenLensDistance; + var screenLeft = distortion.distort((centerX - halfWidth) / centerZ); + var screenTop = distortion.distort((centerY + halfHeight) / centerZ); + var screenRight = distortion.distort((centerX + halfWidth) / centerZ); + var screenBottom = distortion.distort((centerY - halfHeight) / centerZ); + var result = new Float32Array(4); + result[0] = Math.max(fovLeft, screenLeft); + result[1] = Math.min(fovTop, screenTop); + result[2] = Math.min(fovRight, screenRight); + result[3] = Math.max(fovBottom, screenBottom); + return result; +}; +DeviceInfo.prototype.getLeftEyeNoLensTanAngles = function () { + var viewer = this.viewer; + var device = this.device; + var distortion = this.distortion; + var result = new Float32Array(4); + var fovLeft = distortion.distortInverse(Math.tan(-degToRad * viewer.fov)); + var fovTop = distortion.distortInverse(Math.tan(degToRad * viewer.fov)); + var fovRight = distortion.distortInverse(Math.tan(degToRad * viewer.fov)); + var fovBottom = distortion.distortInverse(Math.tan(-degToRad * viewer.fov)); + var halfWidth = device.widthMeters / 4; + var halfHeight = device.heightMeters / 2; + var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight; + var centerX = viewer.interLensDistance / 2 - halfWidth; + var centerY = -verticalLensOffset; + var centerZ = viewer.screenLensDistance; + var screenLeft = (centerX - halfWidth) / centerZ; + var screenTop = (centerY + halfHeight) / centerZ; + var screenRight = (centerX + halfWidth) / centerZ; + var screenBottom = (centerY - halfHeight) / centerZ; + result[0] = Math.max(fovLeft, screenLeft); + result[1] = Math.min(fovTop, screenTop); + result[2] = Math.min(fovRight, screenRight); + result[3] = Math.max(fovBottom, screenBottom); + return result; +}; +DeviceInfo.prototype.getLeftEyeVisibleScreenRect = function (undistortedFrustum) { + var viewer = this.viewer; + var device = this.device; + var dist = viewer.screenLensDistance; + var eyeX = (device.widthMeters - viewer.interLensDistance) / 2; + var eyeY = viewer.baselineLensDistance - device.bevelMeters; + var left = (undistortedFrustum[0] * dist + eyeX) / device.widthMeters; + var top = (undistortedFrustum[1] * dist + eyeY) / device.heightMeters; + var right = (undistortedFrustum[2] * dist + eyeX) / device.widthMeters; + var bottom = (undistortedFrustum[3] * dist + eyeY) / device.heightMeters; + return { + x: left, + y: bottom, + width: right - left, + height: top - bottom + }; +}; +DeviceInfo.prototype.getFieldOfViewLeftEye = function (opt_isUndistorted) { + return opt_isUndistorted ? this.getUndistortedFieldOfViewLeftEye() : this.getDistortedFieldOfViewLeftEye(); +}; +DeviceInfo.prototype.getFieldOfViewRightEye = function (opt_isUndistorted) { + var fov = this.getFieldOfViewLeftEye(opt_isUndistorted); + return { + leftDegrees: fov.rightDegrees, + rightDegrees: fov.leftDegrees, + upDegrees: fov.upDegrees, + downDegrees: fov.downDegrees + }; +}; +DeviceInfo.prototype.getUndistortedFieldOfViewLeftEye = function () { + var p = this.getUndistortedParams_(); + return { + leftDegrees: radToDeg * Math.atan(p.outerDist), + rightDegrees: radToDeg * Math.atan(p.innerDist), + downDegrees: radToDeg * Math.atan(p.bottomDist), + upDegrees: radToDeg * Math.atan(p.topDist) + }; +}; +DeviceInfo.prototype.getUndistortedViewportLeftEye = function () { + var p = this.getUndistortedParams_(); + var viewer = this.viewer; + var device = this.device; + var eyeToScreenDistance = viewer.screenLensDistance; + var screenWidth = device.widthMeters / eyeToScreenDistance; + var screenHeight = device.heightMeters / eyeToScreenDistance; + var xPxPerTanAngle = device.width / screenWidth; + var yPxPerTanAngle = device.height / screenHeight; + var x = Math.round((p.eyePosX - p.outerDist) * xPxPerTanAngle); + var y = Math.round((p.eyePosY - p.bottomDist) * yPxPerTanAngle); + return { + x: x, + y: y, + width: Math.round((p.eyePosX + p.innerDist) * xPxPerTanAngle) - x, + height: Math.round((p.eyePosY + p.topDist) * yPxPerTanAngle) - y + }; +}; +DeviceInfo.prototype.getUndistortedParams_ = function () { + var viewer = this.viewer; + var device = this.device; + var distortion = this.distortion; + var eyeToScreenDistance = viewer.screenLensDistance; + var halfLensDistance = viewer.interLensDistance / 2 / eyeToScreenDistance; + var screenWidth = device.widthMeters / eyeToScreenDistance; + var screenHeight = device.heightMeters / eyeToScreenDistance; + var eyePosX = screenWidth / 2 - halfLensDistance; + var eyePosY = (viewer.baselineLensDistance - device.bevelMeters) / eyeToScreenDistance; + var maxFov = viewer.fov; + var viewerMax = distortion.distortInverse(Math.tan(degToRad * maxFov)); + var outerDist = Math.min(eyePosX, viewerMax); + var innerDist = Math.min(halfLensDistance, viewerMax); + var bottomDist = Math.min(eyePosY, viewerMax); + var topDist = Math.min(screenHeight - eyePosY, viewerMax); + return { + outerDist: outerDist, + innerDist: innerDist, + topDist: topDist, + bottomDist: bottomDist, + eyePosX: eyePosX, + eyePosY: eyePosY + }; +}; +function CardboardViewer(params) { + this.id = params.id; + this.label = params.label; + this.fov = params.fov; + this.interLensDistance = params.interLensDistance; + this.baselineLensDistance = params.baselineLensDistance; + this.screenLensDistance = params.screenLensDistance; + this.distortionCoefficients = params.distortionCoefficients; + this.inverseCoefficients = params.inverseCoefficients; +} +DeviceInfo.Viewers = Viewers; +var format = 1; +var last_updated = "2018-12-10T17:01:42Z"; +var devices = [{"type":"android","rules":[{"mdmh":"asus/*/Nexus 7/*"},{"ua":"Nexus 7"}],"dpi":[320.8,323],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_Z00AD/*"},{"ua":"ASUS_Z00AD"}],"dpi":[403,404.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2 XL/*"},{"ua":"Pixel 2 XL"}],"dpi":537.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3 XL/*"},{"ua":"Pixel 3 XL"}],"dpi":[558.5,553.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel XL/*"},{"ua":"Pixel XL"}],"dpi":[537.9,533],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 3/*"},{"ua":"Pixel 3"}],"dpi":442.4,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel 2/*"},{"ua":"Pixel 2"}],"dpi":441,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Google/*/Pixel/*"},{"ua":"Pixel"}],"dpi":[432.6,436.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC6435LVW/*"},{"ua":"HTC6435LVW"}],"dpi":[449.7,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One XL/*"},{"ua":"HTC One XL"}],"dpi":[315.3,314.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"htc/*/Nexus 9/*"},{"ua":"Nexus 9"}],"dpi":289,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One M9/*"},{"ua":"HTC One M9"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One_M8/*"},{"ua":"HTC One_M8"}],"dpi":[449.7,447.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One/*"},{"ua":"HTC One"}],"dpi":472.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/Nexus 6P/*"},{"ua":"Nexus 6P"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/BLN-L24/*"},{"ua":"HONORBLN-L24"}],"dpi":480,"bw":4,"ac":500},{"type":"android","rules":[{"mdmh":"Huawei/*/BKL-L09/*"},{"ua":"BKL-L09"}],"dpi":403,"bw":3.47,"ac":500},{"type":"android","rules":[{"mdmh":"LENOVO/*/Lenovo PB2-690Y/*"},{"ua":"Lenovo PB2-690Y"}],"dpi":[457.2,454.713],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5X/*"},{"ua":"Nexus 5X"}],"dpi":[422,419.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS345/*"},{"ua":"LGMS345"}],"dpi":[221.7,219.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D800/*"},{"ua":"LG-D800"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D850/*"},{"ua":"LG-D850"}],"dpi":[537.9,541.9],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/VS985 4G/*"},{"ua":"VS985 4G"}],"dpi":[537.9,535.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5/*"},{"ua":"Nexus 5 B"}],"dpi":[442.4,444.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 4/*"},{"ua":"Nexus 4"}],"dpi":[319.8,318.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LG-P769/*"},{"ua":"LG-P769"}],"dpi":[240.6,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS323/*"},{"ua":"LGMS323"}],"dpi":[206.6,204.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGLS996/*"},{"ua":"LGLS996"}],"dpi":[403.4,401.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/4560MMX/*"},{"ua":"4560MMX"}],"dpi":[240,219.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/A250/*"},{"ua":"Micromax A250"}],"dpi":[480,446.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/Micromax AQ4501/*"},{"ua":"Micromax AQ4501"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/G5/*"},{"ua":"Moto G (5) Plus"}],"dpi":[403.4,403],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/DROID RAZR/*"},{"ua":"DROID RAZR"}],"dpi":[368.1,256.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT830C/*"},{"ua":"XT830C"}],"dpi":[254,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1021/*"},{"ua":"XT1021"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1023/*"},{"ua":"XT1023"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1028/*"},{"ua":"XT1028"}],"dpi":[326.6,327.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1034/*"},{"ua":"XT1034"}],"dpi":[326.6,328.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1053/*"},{"ua":"XT1053"}],"dpi":[315.3,316.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1562/*"},{"ua":"XT1562"}],"dpi":[403.4,402.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/Nexus 6/*"},{"ua":"Nexus 6 B"}],"dpi":[494.3,489.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1063/*"},{"ua":"XT1063"}],"dpi":[295,296.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1064/*"},{"ua":"XT1064"}],"dpi":[295,295.6],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1092/*"},{"ua":"XT1092"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1095/*"},{"ua":"XT1095"}],"dpi":[422,423.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/G4/*"},{"ua":"Moto G (4)"}],"dpi":401,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/A0001/*"},{"ua":"A0001"}],"dpi":[403.4,401],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1005/*"},{"ua":"ONE E1005"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2005/*"},{"ua":"ONE A2005"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A5000/*"},{"ua":"ONEPLUS A5000 "}],"dpi":[403.411,399.737],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A5010/*"},{"ua":"ONEPLUS A5010"}],"dpi":[403,400],"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"OPPO/*/X909/*"},{"ua":"X909"}],"dpi":[442.4,444.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9082/*"},{"ua":"GT-I9082"}],"dpi":[184.7,185.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G360P/*"},{"ua":"SM-G360P"}],"dpi":[196.7,205.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Nexus S/*"},{"ua":"Nexus S"}],"dpi":[234.5,229.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[304.8,303.9],"bw":5,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T230NU/*"},{"ua":"SM-T230NU"}],"dpi":216,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-T399/*"},{"ua":"SGH-T399"}],"dpi":[217.7,231.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-M919/*"},{"ua":"SGH-M919"}],"dpi":[440.8,437.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N9005/*"},{"ua":"SM-N9005"}],"dpi":[386.4,387],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SM-N900A/*"},{"ua":"SAMSUNG-SM-N900A"}],"dpi":[386.4,387.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9500/*"},{"ua":"GT-I9500"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9505/*"},{"ua":"GT-I9505"}],"dpi":439.4,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900F/*"},{"ua":"SM-G900F"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900M/*"},{"ua":"SM-G900M"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G800F/*"},{"ua":"SM-G800F"}],"dpi":326.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G906S/*"},{"ua":"SM-G906S"}],"dpi":[562.7,572.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[306.7,304.8],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T535/*"},{"ua":"SM-T535"}],"dpi":[142.6,136.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920C/*"},{"ua":"SM-N920C"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920P/*"},{"ua":"SM-N920P"}],"dpi":[386.3655,390.144],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920W8/*"},{"ua":"SM-N920W8"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300I/*"},{"ua":"GT-I9300I"}],"dpi":[304.8,305.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9195/*"},{"ua":"GT-I9195"}],"dpi":[249.4,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-L520/*"},{"ua":"SPH-L520"}],"dpi":[249.4,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SGH-I717/*"},{"ua":"SAMSUNG-SGH-I717"}],"dpi":285.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-D710/*"},{"ua":"SPH-D710"}],"dpi":[217.7,204.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-N7100/*"},{"ua":"GT-N7100"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SCH-I605/*"},{"ua":"SCH-I605"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Galaxy Nexus/*"},{"ua":"Galaxy Nexus"}],"dpi":[315.3,314.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910H/*"},{"ua":"SM-N910H"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910C/*"},{"ua":"SM-N910C"}],"dpi":[515.2,520.2],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G130M/*"},{"ua":"SM-G130M"}],"dpi":[165.9,164.8],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G928I/*"},{"ua":"SM-G928I"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920F/*"},{"ua":"SM-G920F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920P/*"},{"ua":"SM-G920P"}],"dpi":[522.5,577],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925F/*"},{"ua":"SM-G925F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925V/*"},{"ua":"SM-G925V"}],"dpi":[522.5,576.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G930F/*"},{"ua":"SM-G930F"}],"dpi":576.6,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G935F/*"},{"ua":"SM-G935F"}],"dpi":533,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G950F/*"},{"ua":"SM-G950F"}],"dpi":[562.707,565.293],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955U/*"},{"ua":"SM-G955U"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955F/*"},{"ua":"SM-G955F"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/C6903/*"},{"ua":"C6903"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/D6653/*"},{"ua":"D6653"}],"dpi":[428.6,427.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6653/*"},{"ua":"E6653"}],"dpi":[428.6,425.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6853/*"},{"ua":"E6853"}],"dpi":[403.4,401.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/SGP321/*"},{"ua":"SGP321"}],"dpi":[224.7,224.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{"ua":"ALCATEL ONE TOUCH Fierce"}],"dpi":[240,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"THL/*/thl 5000/*"},{"ua":"thl 5000"}],"dpi":[480,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Fly/*/IQ4412/*"},{"ua":"IQ4412"}],"dpi":307.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"ZTE/*/ZTE Blade L2/*"},{"ua":"ZTE Blade L2"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"BENEVE/*/VR518/*"},{"ua":"VR518"}],"dpi":480,"bw":3,"ac":500},{"type":"ios","rules":[{"res":[640,960]}],"dpi":[325.1,328.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[640,1136]}],"dpi":[317.1,320.2],"bw":3,"ac":1000},{"type":"ios","rules":[{"res":[750,1334]}],"dpi":326.4,"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1242,2208]}],"dpi":[453.6,458.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2001]}],"dpi":[410.9,415.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2436]}],"dpi":458,"bw":4,"ac":1000}]; +var DPDB_CACHE = { + format: format, + last_updated: last_updated, + devices: devices +}; +function Dpdb(url, onDeviceParamsUpdated) { + this.dpdb = DPDB_CACHE; + this.recalculateDeviceParams_(); + if (url) { + this.onDeviceParamsUpdated = onDeviceParamsUpdated; + var xhr = new XMLHttpRequest(); + var obj = this; + xhr.open('GET', url, true); + xhr.addEventListener('load', function () { + obj.loading = false; + if (xhr.status >= 200 && xhr.status <= 299) { + obj.dpdb = JSON.parse(xhr.response); + obj.recalculateDeviceParams_(); + } else { + console.error('Error loading online DPDB!'); + } + }); + xhr.send(); + } +} +Dpdb.prototype.getDeviceParams = function () { + return this.deviceParams; +}; +Dpdb.prototype.recalculateDeviceParams_ = function () { + var newDeviceParams = this.calcDeviceParams_(); + if (newDeviceParams) { + this.deviceParams = newDeviceParams; + if (this.onDeviceParamsUpdated) { + this.onDeviceParamsUpdated(this.deviceParams); + } + } else { + console.error('Failed to recalculate device parameters.'); + } +}; +Dpdb.prototype.calcDeviceParams_ = function () { + var db = this.dpdb; + if (!db) { + console.error('DPDB not available.'); + return null; + } + if (db.format != 1) { + console.error('DPDB has unexpected format version.'); + return null; + } + if (!db.devices || !db.devices.length) { + console.error('DPDB does not have a devices section.'); + return null; + } + var userAgent = navigator.userAgent || navigator.vendor || window.opera; + var width = getScreenWidth(); + var height = getScreenHeight(); + if (!db.devices) { + console.error('DPDB has no devices section.'); + return null; + } + for (var i = 0; i < db.devices.length; i++) { + var device = db.devices[i]; + if (!device.rules) { + console.warn('Device[' + i + '] has no rules section.'); + continue; + } + if (device.type != 'ios' && device.type != 'android') { + console.warn('Device[' + i + '] has invalid type.'); + continue; + } + if (isIOS() != (device.type == 'ios')) continue; + var matched = false; + for (var j = 0; j < device.rules.length; j++) { + var rule = device.rules[j]; + if (this.ruleMatches_(rule, userAgent, width, height)) { + matched = true; + break; + } + } + if (!matched) continue; + var xdpi = device.dpi[0] || device.dpi; + var ydpi = device.dpi[1] || device.dpi; + return new DeviceParams({ xdpi: xdpi, ydpi: ydpi, bevelMm: device.bw }); + } + console.warn('No DPDB device match.'); + return null; +}; +Dpdb.prototype.ruleMatches_ = function (rule, ua, screenWidth, screenHeight) { + if (!rule.ua && !rule.res) return false; + if (rule.ua && rule.ua.substring(0, 2) === 'SM') rule.ua = rule.ua.substring(0, 7); + if (rule.ua && ua.indexOf(rule.ua) < 0) return false; + if (rule.res) { + if (!rule.res[0] || !rule.res[1]) return false; + var resX = rule.res[0]; + var resY = rule.res[1]; + if (Math.min(screenWidth, screenHeight) != Math.min(resX, resY) || Math.max(screenWidth, screenHeight) != Math.max(resX, resY)) { + return false; + } + } + return true; +}; +function DeviceParams(params) { + this.xdpi = params.xdpi; + this.ydpi = params.ydpi; + this.bevelMm = params.bevelMm; +} +function SensorSample(sample, timestampS) { + this.set(sample, timestampS); +} +SensorSample.prototype.set = function (sample, timestampS) { + this.sample = sample; + this.timestampS = timestampS; +}; +SensorSample.prototype.copy = function (sensorSample) { + this.set(sensorSample.sample, sensorSample.timestampS); +}; +function ComplementaryFilter(kFilter, isDebug) { + this.kFilter = kFilter; + this.isDebug = isDebug; + this.currentAccelMeasurement = new SensorSample(); + this.currentGyroMeasurement = new SensorSample(); + this.previousGyroMeasurement = new SensorSample(); + if (isIOS()) { + this.filterQ = new Quaternion(-1, 0, 0, 1); + } else { + this.filterQ = new Quaternion(1, 0, 0, 1); + } + this.previousFilterQ = new Quaternion(); + this.previousFilterQ.copy(this.filterQ); + this.accelQ = new Quaternion(); + this.isOrientationInitialized = false; + this.estimatedGravity = new Vector3(); + this.measuredGravity = new Vector3(); + this.gyroIntegralQ = new Quaternion(); +} +ComplementaryFilter.prototype.addAccelMeasurement = function (vector, timestampS) { + this.currentAccelMeasurement.set(vector, timestampS); +}; +ComplementaryFilter.prototype.addGyroMeasurement = function (vector, timestampS) { + this.currentGyroMeasurement.set(vector, timestampS); + var deltaT = timestampS - this.previousGyroMeasurement.timestampS; + if (isTimestampDeltaValid(deltaT)) { + this.run_(); + } + this.previousGyroMeasurement.copy(this.currentGyroMeasurement); +}; +ComplementaryFilter.prototype.run_ = function () { + if (!this.isOrientationInitialized) { + this.accelQ = this.accelToQuaternion_(this.currentAccelMeasurement.sample); + this.previousFilterQ.copy(this.accelQ); + this.isOrientationInitialized = true; + return; + } + var deltaT = this.currentGyroMeasurement.timestampS - this.previousGyroMeasurement.timestampS; + var gyroDeltaQ = this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample, deltaT); + this.gyroIntegralQ.multiply(gyroDeltaQ); + this.filterQ.copy(this.previousFilterQ); + this.filterQ.multiply(gyroDeltaQ); + var invFilterQ = new Quaternion(); + invFilterQ.copy(this.filterQ); + invFilterQ.inverse(); + this.estimatedGravity.set(0, 0, -1); + this.estimatedGravity.applyQuaternion(invFilterQ); + this.estimatedGravity.normalize(); + this.measuredGravity.copy(this.currentAccelMeasurement.sample); + this.measuredGravity.normalize(); + var deltaQ = new Quaternion(); + deltaQ.setFromUnitVectors(this.estimatedGravity, this.measuredGravity); + deltaQ.inverse(); + if (this.isDebug) { + console.log('Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)', radToDeg * getQuaternionAngle(deltaQ), this.estimatedGravity.x.toFixed(1), this.estimatedGravity.y.toFixed(1), this.estimatedGravity.z.toFixed(1), this.measuredGravity.x.toFixed(1), this.measuredGravity.y.toFixed(1), this.measuredGravity.z.toFixed(1)); + } + var targetQ = new Quaternion(); + targetQ.copy(this.filterQ); + targetQ.multiply(deltaQ); + this.filterQ.slerp(targetQ, 1 - this.kFilter); + this.previousFilterQ.copy(this.filterQ); +}; +ComplementaryFilter.prototype.getOrientation = function () { + return this.filterQ; +}; +ComplementaryFilter.prototype.accelToQuaternion_ = function (accel) { + var normAccel = new Vector3(); + normAccel.copy(accel); + normAccel.normalize(); + var quat = new Quaternion(); + quat.setFromUnitVectors(new Vector3(0, 0, -1), normAccel); + quat.inverse(); + return quat; +}; +ComplementaryFilter.prototype.gyroToQuaternionDelta_ = function (gyro, dt) { + var quat = new Quaternion(); + var axis = new Vector3(); + axis.copy(gyro); + axis.normalize(); + quat.setFromAxisAngle(axis, gyro.length() * dt); + return quat; +}; +function PosePredictor(predictionTimeS, isDebug) { + this.predictionTimeS = predictionTimeS; + this.isDebug = isDebug; + this.previousQ = new Quaternion(); + this.previousTimestampS = null; + this.deltaQ = new Quaternion(); + this.outQ = new Quaternion(); +} +PosePredictor.prototype.getPrediction = function (currentQ, gyro, timestampS) { + if (!this.previousTimestampS) { + this.previousQ.copy(currentQ); + this.previousTimestampS = timestampS; + return currentQ; + } + var axis = new Vector3(); + axis.copy(gyro); + axis.normalize(); + var angularSpeed = gyro.length(); + if (angularSpeed < degToRad * 20) { + if (this.isDebug) { + console.log('Moving slowly, at %s deg/s: no prediction', (radToDeg * angularSpeed).toFixed(1)); + } + this.outQ.copy(currentQ); + this.previousQ.copy(currentQ); + return this.outQ; + } + var predictAngle = angularSpeed * this.predictionTimeS; + this.deltaQ.setFromAxisAngle(axis, predictAngle); + this.outQ.copy(this.previousQ); + this.outQ.multiply(this.deltaQ); + this.previousQ.copy(currentQ); + this.previousTimestampS = timestampS; + return this.outQ; +}; +function FusionPoseSensor(kFilter, predictionTime, yawOnly, isDebug) { + this.yawOnly = yawOnly; + this.accelerometer = new Vector3(); + this.gyroscope = new Vector3(); + this.filter = new ComplementaryFilter(kFilter, isDebug); + this.posePredictor = new PosePredictor(predictionTime, isDebug); + this.isFirefoxAndroid = isFirefoxAndroid(); + this.isIOS = isIOS(); + var chromeVersion = getChromeVersion(); + this.isDeviceMotionInRadians = !this.isIOS && chromeVersion && chromeVersion < 66; + this.isWithoutDeviceMotion = isChromeWithoutDeviceMotion(); + this.filterToWorldQ = new Quaternion(); + if (isIOS()) { + this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2); + } else { + this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2); + } + this.inverseWorldToScreenQ = new Quaternion(); + this.worldToScreenQ = new Quaternion(); + this.originalPoseAdjustQ = new Quaternion(); + this.originalPoseAdjustQ.setFromAxisAngle(new Vector3(0, 0, 1), -window.orientation * Math.PI / 180); + this.setScreenTransform_(); + if (isLandscapeMode()) { + this.filterToWorldQ.multiply(this.inverseWorldToScreenQ); + } + this.resetQ = new Quaternion(); + this.orientationOut_ = new Float32Array(4); + this.start(); +} +FusionPoseSensor.prototype.getPosition = function () { + return null; +}; +FusionPoseSensor.prototype.getOrientation = function () { + var orientation = void 0; + if (this.isWithoutDeviceMotion && this._deviceOrientationQ) { + this.deviceOrientationFixQ = this.deviceOrientationFixQ || function () { + var z = new Quaternion().setFromAxisAngle(new Vector3(0, 0, -1), 0); + var y = new Quaternion(); + if (window.orientation === -90) { + y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / -2); + } else { + y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 2); + } + return z.multiply(y); + }(); + this.deviceOrientationFilterToWorldQ = this.deviceOrientationFilterToWorldQ || function () { + var q = new Quaternion(); + q.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2); + return q; + }(); + orientation = this._deviceOrientationQ; + var out = new Quaternion(); + out.copy(orientation); + out.multiply(this.deviceOrientationFilterToWorldQ); + out.multiply(this.resetQ); + out.multiply(this.worldToScreenQ); + out.multiplyQuaternions(this.deviceOrientationFixQ, out); + if (this.yawOnly) { + out.x = 0; + out.z = 0; + out.normalize(); + } + this.orientationOut_[0] = out.x; + this.orientationOut_[1] = out.y; + this.orientationOut_[2] = out.z; + this.orientationOut_[3] = out.w; + return this.orientationOut_; + } else { + var filterOrientation = this.filter.getOrientation(); + orientation = this.posePredictor.getPrediction(filterOrientation, this.gyroscope, this.previousTimestampS); + } + var out = new Quaternion(); + out.copy(this.filterToWorldQ); + out.multiply(this.resetQ); + out.multiply(orientation); + out.multiply(this.worldToScreenQ); + if (this.yawOnly) { + out.x = 0; + out.z = 0; + out.normalize(); + } + this.orientationOut_[0] = out.x; + this.orientationOut_[1] = out.y; + this.orientationOut_[2] = out.z; + this.orientationOut_[3] = out.w; + return this.orientationOut_; +}; +FusionPoseSensor.prototype.resetPose = function () { + this.resetQ.copy(this.filter.getOrientation()); + this.resetQ.x = 0; + this.resetQ.y = 0; + this.resetQ.z *= -1; + this.resetQ.normalize(); + if (isLandscapeMode()) { + this.resetQ.multiply(this.inverseWorldToScreenQ); + } + this.resetQ.multiply(this.originalPoseAdjustQ); +}; +FusionPoseSensor.prototype.onDeviceOrientation_ = function (e) { + this._deviceOrientationQ = this._deviceOrientationQ || new Quaternion(); + var alpha = e.alpha, + beta = e.beta, + gamma = e.gamma; + alpha = (alpha || 0) * Math.PI / 180; + beta = (beta || 0) * Math.PI / 180; + gamma = (gamma || 0) * Math.PI / 180; + this._deviceOrientationQ.setFromEulerYXZ(beta, alpha, -gamma); +}; +FusionPoseSensor.prototype.onDeviceMotion_ = function (deviceMotion) { + this.updateDeviceMotion_(deviceMotion); +}; +FusionPoseSensor.prototype.updateDeviceMotion_ = function (deviceMotion) { + var accGravity = deviceMotion.accelerationIncludingGravity; + var rotRate = deviceMotion.rotationRate; + var timestampS = deviceMotion.timeStamp / 1000; + var deltaS = timestampS - this.previousTimestampS; + if (deltaS < 0) { + warnOnce('fusion-pose-sensor:invalid:non-monotonic', 'Invalid timestamps detected: non-monotonic timestamp from devicemotion'); + this.previousTimestampS = timestampS; + return; + } else if (deltaS <= MIN_TIMESTEP || deltaS > MAX_TIMESTEP) { + warnOnce('fusion-pose-sensor:invalid:outside-threshold', 'Invalid timestamps detected: Timestamp from devicemotion outside expected range.'); + this.previousTimestampS = timestampS; + return; + } + this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z); + if (isR7()) { + this.gyroscope.set(-rotRate.beta, rotRate.alpha, rotRate.gamma); + } else { + this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma); + } + if (!this.isDeviceMotionInRadians) { + this.gyroscope.multiplyScalar(Math.PI / 180); + } + this.filter.addAccelMeasurement(this.accelerometer, timestampS); + this.filter.addGyroMeasurement(this.gyroscope, timestampS); + this.previousTimestampS = timestampS; +}; +FusionPoseSensor.prototype.onOrientationChange_ = function (screenOrientation) { + this.setScreenTransform_(); +}; +FusionPoseSensor.prototype.onMessage_ = function (event) { + var message = event.data; + if (!message || !message.type) { + return; + } + var type = message.type.toLowerCase(); + if (type !== 'devicemotion') { + return; + } + this.updateDeviceMotion_(message.deviceMotionEvent); +}; +FusionPoseSensor.prototype.setScreenTransform_ = function () { + this.worldToScreenQ.set(0, 0, 0, 1); + switch (window.orientation) { + case 0: + break; + case 90: + this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), -Math.PI / 2); + break; + case -90: + this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), Math.PI / 2); + break; + case 180: + break; + } + this.inverseWorldToScreenQ.copy(this.worldToScreenQ); + this.inverseWorldToScreenQ.inverse(); +}; +FusionPoseSensor.prototype.start = function () { + this.onDeviceMotionCallback_ = this.onDeviceMotion_.bind(this); + this.onOrientationChangeCallback_ = this.onOrientationChange_.bind(this); + this.onMessageCallback_ = this.onMessage_.bind(this); + this.onDeviceOrientationCallback_ = this.onDeviceOrientation_.bind(this); + if (isIOS() && isInsideCrossOriginIFrame()) { + window.addEventListener('message', this.onMessageCallback_); + } + window.addEventListener('orientationchange', this.onOrientationChangeCallback_); + if (this.isWithoutDeviceMotion) { + window.addEventListener('deviceorientation', this.onDeviceOrientationCallback_); + } else { + window.addEventListener('devicemotion', this.onDeviceMotionCallback_); + } +}; +FusionPoseSensor.prototype.stop = function () { + window.removeEventListener('devicemotion', this.onDeviceMotionCallback_); + window.removeEventListener('deviceorientation', this.onDeviceOrientationCallback_); + window.removeEventListener('orientationchange', this.onOrientationChangeCallback_); + window.removeEventListener('message', this.onMessageCallback_); +}; +var SENSOR_FREQUENCY = 60; +var X_AXIS = new Vector3(1, 0, 0); +var Z_AXIS = new Vector3(0, 0, 1); +var SENSOR_TO_VR = new Quaternion(); +SENSOR_TO_VR.setFromAxisAngle(X_AXIS, -Math.PI / 2); +SENSOR_TO_VR.multiply(new Quaternion().setFromAxisAngle(Z_AXIS, Math.PI / 2)); +var PoseSensor = function () { + function PoseSensor(config) { + classCallCheck(this, PoseSensor); + this.config = config; + this.sensor = null; + this.fusionSensor = null; + this._out = new Float32Array(4); + this.api = null; + this.errors = []; + this._sensorQ = new Quaternion(); + this._outQ = new Quaternion(); + this._onSensorRead = this._onSensorRead.bind(this); + this._onSensorError = this._onSensorError.bind(this); + this.init(); + } + createClass(PoseSensor, [{ + key: 'init', + value: function init() { + var sensor = null; + try { + sensor = new RelativeOrientationSensor({ + frequency: SENSOR_FREQUENCY, + referenceFrame: 'screen' + }); + sensor.addEventListener('error', this._onSensorError); + } catch (error) { + this.errors.push(error); + if (error.name === 'SecurityError') { + console.error('Cannot construct sensors due to the Feature Policy'); + console.warn('Attempting to fall back using "devicemotion"; however this will ' + 'fail in the future without correct permissions.'); + this.useDeviceMotion(); + } else if (error.name === 'ReferenceError') { + this.useDeviceMotion(); + } else { + console.error(error); + } + } + if (sensor) { + this.api = 'sensor'; + this.sensor = sensor; + this.sensor.addEventListener('reading', this._onSensorRead); + this.sensor.start(); + } + } + }, { + key: 'useDeviceMotion', + value: function useDeviceMotion() { + this.api = 'devicemotion'; + this.fusionSensor = new FusionPoseSensor(this.config.K_FILTER, this.config.PREDICTION_TIME_S, this.config.YAW_ONLY, this.config.DEBUG); + if (this.sensor) { + this.sensor.removeEventListener('reading', this._onSensorRead); + this.sensor.removeEventListener('error', this._onSensorError); + this.sensor = null; + } + } + }, { + key: 'getOrientation', + value: function getOrientation() { + if (this.fusionSensor) { + return this.fusionSensor.getOrientation(); + } + if (!this.sensor || !this.sensor.quaternion) { + this._out[0] = this._out[1] = this._out[2] = 0; + this._out[3] = 1; + return this._out; + } + var q = this.sensor.quaternion; + this._sensorQ.set(q[0], q[1], q[2], q[3]); + var out = this._outQ; + out.copy(SENSOR_TO_VR); + out.multiply(this._sensorQ); + if (this.config.YAW_ONLY) { + out.x = out.z = 0; + out.normalize(); + } + this._out[0] = out.x; + this._out[1] = out.y; + this._out[2] = out.z; + this._out[3] = out.w; + return this._out; + } + }, { + key: '_onSensorError', + value: function _onSensorError(event) { + this.errors.push(event.error); + if (event.error.name === 'NotAllowedError') { + console.error('Permission to access sensor was denied'); + } else if (event.error.name === 'NotReadableError') { + console.error('Sensor could not be read'); + } else { + console.error(event.error); + } + this.useDeviceMotion(); + } + }, { + key: '_onSensorRead', + value: function _onSensorRead() {} + }]); + return PoseSensor; +}(); +var rotateInstructionsAsset = ""; +function RotateInstructions() { + this.loadIcon_(); + var overlay = document.createElement('div'); + var s = overlay.style; + s.position = 'fixed'; + s.top = 0; + s.right = 0; + s.bottom = 0; + s.left = 0; + s.backgroundColor = 'gray'; + s.fontFamily = 'sans-serif'; + s.zIndex = 1000000; + var img = document.createElement('img'); + img.src = this.icon; + var s = img.style; + s.marginLeft = '25%'; + s.marginTop = '25%'; + s.width = '50%'; + overlay.appendChild(img); + var text = document.createElement('div'); + var s = text.style; + s.textAlign = 'center'; + s.fontSize = '16px'; + s.lineHeight = '24px'; + s.margin = '24px 25%'; + s.width = '50%'; + text.innerHTML = 'Place your phone into your Cardboard viewer.'; + overlay.appendChild(text); + var snackbar = document.createElement('div'); + var s = snackbar.style; + s.backgroundColor = '#CFD8DC'; + s.position = 'fixed'; + s.bottom = 0; + s.width = '100%'; + s.height = '48px'; + s.padding = '14px 24px'; + s.boxSizing = 'border-box'; + s.color = '#656A6B'; + overlay.appendChild(snackbar); + var snackbarText = document.createElement('div'); + snackbarText.style.float = 'left'; + snackbarText.innerHTML = 'No Cardboard viewer?'; + var snackbarButton = document.createElement('a'); + snackbarButton.href = 'https://www.google.com/get/cardboard/get-cardboard/'; + snackbarButton.innerHTML = 'get one'; + snackbarButton.target = '_blank'; + var s = snackbarButton.style; + s.float = 'right'; + s.fontWeight = 600; + s.textTransform = 'uppercase'; + s.borderLeft = '1px solid gray'; + s.paddingLeft = '24px'; + s.textDecoration = 'none'; + s.color = '#656A6B'; + snackbar.appendChild(snackbarText); + snackbar.appendChild(snackbarButton); + this.overlay = overlay; + this.text = text; + this.hide(); +} +RotateInstructions.prototype.show = function (parent) { + if (!parent && !this.overlay.parentElement) { + document.body.appendChild(this.overlay); + } else if (parent) { + if (this.overlay.parentElement && this.overlay.parentElement != parent) this.overlay.parentElement.removeChild(this.overlay); + parent.appendChild(this.overlay); + } + this.overlay.style.display = 'block'; + var img = this.overlay.querySelector('img'); + var s = img.style; + if (isLandscapeMode()) { + s.width = '20%'; + s.marginLeft = '40%'; + s.marginTop = '3%'; + } else { + s.width = '50%'; + s.marginLeft = '25%'; + s.marginTop = '25%'; + } +}; +RotateInstructions.prototype.hide = function () { + this.overlay.style.display = 'none'; +}; +RotateInstructions.prototype.showTemporarily = function (ms, parent) { + this.show(parent); + this.timer = setTimeout(this.hide.bind(this), ms); +}; +RotateInstructions.prototype.disableShowTemporarily = function () { + clearTimeout(this.timer); +}; +RotateInstructions.prototype.update = function () { + this.disableShowTemporarily(); + if (!isLandscapeMode() && isMobile()) { + this.show(); + } else { + this.hide(); + } +}; +RotateInstructions.prototype.loadIcon_ = function () { + this.icon = dataUri('image/svg+xml', rotateInstructionsAsset); +}; +var DEFAULT_VIEWER = 'CardboardV1'; +var VIEWER_KEY = 'WEBVR_CARDBOARD_VIEWER'; +var CLASS_NAME = 'webvr-polyfill-viewer-selector'; +function ViewerSelector(defaultViewer) { + try { + this.selectedKey = localStorage.getItem(VIEWER_KEY); + } catch (error) { + console.error('Failed to load viewer profile: %s', error); + } + if (!this.selectedKey) { + this.selectedKey = defaultViewer || DEFAULT_VIEWER; + } + this.dialog = this.createDialog_(DeviceInfo.Viewers); + this.root = null; + this.onChangeCallbacks_ = []; +} +ViewerSelector.prototype.show = function (root) { + this.root = root; + root.appendChild(this.dialog); + var selected = this.dialog.querySelector('#' + this.selectedKey); + selected.checked = true; + this.dialog.style.display = 'block'; +}; +ViewerSelector.prototype.hide = function () { + if (this.root && this.root.contains(this.dialog)) { + this.root.removeChild(this.dialog); + } + this.dialog.style.display = 'none'; +}; +ViewerSelector.prototype.getCurrentViewer = function () { + return DeviceInfo.Viewers[this.selectedKey]; +}; +ViewerSelector.prototype.getSelectedKey_ = function () { + var input = this.dialog.querySelector('input[name=field]:checked'); + if (input) { + return input.id; + } + return null; +}; +ViewerSelector.prototype.onChange = function (cb) { + this.onChangeCallbacks_.push(cb); +}; +ViewerSelector.prototype.fireOnChange_ = function (viewer) { + for (var i = 0; i < this.onChangeCallbacks_.length; i++) { + this.onChangeCallbacks_[i](viewer); + } +}; +ViewerSelector.prototype.onSave_ = function () { + this.selectedKey = this.getSelectedKey_(); + if (!this.selectedKey || !DeviceInfo.Viewers[this.selectedKey]) { + console.error('ViewerSelector.onSave_: this should never happen!'); + return; + } + this.fireOnChange_(DeviceInfo.Viewers[this.selectedKey]); + try { + localStorage.setItem(VIEWER_KEY, this.selectedKey); + } catch (error) { + console.error('Failed to save viewer profile: %s', error); + } + this.hide(); +}; +ViewerSelector.prototype.createDialog_ = function (options) { + var container = document.createElement('div'); + container.classList.add(CLASS_NAME); + container.style.display = 'none'; + var overlay = document.createElement('div'); + var s = overlay.style; + s.position = 'fixed'; + s.left = 0; + s.top = 0; + s.width = '100%'; + s.height = '100%'; + s.background = 'rgba(0, 0, 0, 0.3)'; + overlay.addEventListener('click', this.hide.bind(this)); + var width = 280; + var dialog = document.createElement('div'); + var s = dialog.style; + s.boxSizing = 'border-box'; + s.position = 'fixed'; + s.top = '24px'; + s.left = '50%'; + s.marginLeft = -width / 2 + 'px'; + s.width = width + 'px'; + s.padding = '24px'; + s.overflow = 'hidden'; + s.background = '#fafafa'; + s.fontFamily = "'Roboto', sans-serif"; + s.boxShadow = '0px 5px 20px #666'; + dialog.appendChild(this.createH1_('Select your viewer')); + for (var id in options) { + dialog.appendChild(this.createChoice_(id, options[id].label)); + } + dialog.appendChild(this.createButton_('Save', this.onSave_.bind(this))); + container.appendChild(overlay); + container.appendChild(dialog); + return container; +}; +ViewerSelector.prototype.createH1_ = function (name) { + var h1 = document.createElement('h1'); + var s = h1.style; + s.color = 'black'; + s.fontSize = '20px'; + s.fontWeight = 'bold'; + s.marginTop = 0; + s.marginBottom = '24px'; + h1.innerHTML = name; + return h1; +}; +ViewerSelector.prototype.createChoice_ = function (id, name) { + var div = document.createElement('div'); + div.style.marginTop = '8px'; + div.style.color = 'black'; + var input = document.createElement('input'); + input.style.fontSize = '30px'; + input.setAttribute('id', id); + input.setAttribute('type', 'radio'); + input.setAttribute('value', id); + input.setAttribute('name', 'field'); + var label = document.createElement('label'); + label.style.marginLeft = '4px'; + label.setAttribute('for', id); + label.innerHTML = name; + div.appendChild(input); + div.appendChild(label); + return div; +}; +ViewerSelector.prototype.createButton_ = function (label, onclick) { + var button = document.createElement('button'); + button.innerHTML = label; + var s = button.style; + s.float = 'right'; + s.textTransform = 'uppercase'; + s.color = '#1094f7'; + s.fontSize = '14px'; + s.letterSpacing = 0; + s.border = 0; + s.background = 'none'; + s.marginTop = '16px'; + button.addEventListener('click', onclick); + return button; +}; +var commonjsGlobal$$1 = typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {}; +function unwrapExports$$1 (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; +} +function createCommonjsModule$$1(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; +} +var NoSleep = createCommonjsModule$$1(function (module, exports) { +(function webpackUniversalModuleDefinition(root, factory) { + module.exports = factory(); +})(commonjsGlobal$$1, function() { +return (function(modules) { + var installedModules = {}; + function __webpack_require__(moduleId) { + if(installedModules[moduleId]) { + return installedModules[moduleId].exports; + } + var module = installedModules[moduleId] = { + i: moduleId, + l: false, + exports: {} + }; + modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + module.l = true; + return module.exports; + } + __webpack_require__.m = modules; + __webpack_require__.c = installedModules; + __webpack_require__.d = function(exports, name, getter) { + if(!__webpack_require__.o(exports, name)) { + Object.defineProperty(exports, name, { + configurable: false, + enumerable: true, + get: getter + }); + } + }; + __webpack_require__.n = function(module) { + var getter = module && module.__esModule ? + function getDefault() { return module['default']; } : + function getModuleExports() { return module; }; + __webpack_require__.d(getter, 'a', getter); + return getter; + }; + __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; + __webpack_require__.p = ""; + return __webpack_require__(__webpack_require__.s = 0); + }) + ([ + (function(module, exports, __webpack_require__) { +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +var mediaFile = __webpack_require__(1); +var oldIOS = typeof navigator !== 'undefined' && parseFloat(('' + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ''])[1]).replace('undefined', '3_2').replace('_', '.').replace('_', '')) < 10 && !window.MSStream; +var NoSleep = function () { + function NoSleep() { + _classCallCheck(this, NoSleep); + if (oldIOS) { + this.noSleepTimer = null; + } else { + this.noSleepVideo = document.createElement('video'); + this.noSleepVideo.setAttribute('playsinline', ''); + this.noSleepVideo.setAttribute('src', mediaFile); + this.noSleepVideo.addEventListener('timeupdate', function (e) { + if (this.noSleepVideo.currentTime > 0.5) { + this.noSleepVideo.currentTime = Math.random(); + } + }.bind(this)); + } + } + _createClass(NoSleep, [{ + key: 'enable', + value: function enable() { + if (oldIOS) { + this.disable(); + this.noSleepTimer = window.setInterval(function () { + window.location.href = '/'; + window.setTimeout(window.stop, 0); + }, 15000); + } else { + this.noSleepVideo.play(); + } + } + }, { + key: 'disable', + value: function disable() { + if (oldIOS) { + if (this.noSleepTimer) { + window.clearInterval(this.noSleepTimer); + this.noSleepTimer = null; + } + } else { + this.noSleepVideo.pause(); + } + } + }]); + return NoSleep; +}(); +module.exports = NoSleep; + }), + (function(module, exports, __webpack_require__) { +module.exports = 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA='; + }) + ]); +}); +}); +var NoSleep$1 = unwrapExports$$1(NoSleep); +var nextDisplayId = 1000; +var defaultLeftBounds = [0, 0, 0.5, 1]; +var defaultRightBounds = [0.5, 0, 0.5, 1]; +var raf = window.requestAnimationFrame; +var caf = window.cancelAnimationFrame; +function VRFrameData() { + this.leftProjectionMatrix = new Float32Array(16); + this.leftViewMatrix = new Float32Array(16); + this.rightProjectionMatrix = new Float32Array(16); + this.rightViewMatrix = new Float32Array(16); + this.pose = null; +} +function VRDisplayCapabilities(config) { + Object.defineProperties(this, { + hasPosition: { + writable: false, enumerable: true, value: config.hasPosition + }, + hasExternalDisplay: { + writable: false, enumerable: true, value: config.hasExternalDisplay + }, + canPresent: { + writable: false, enumerable: true, value: config.canPresent + }, + maxLayers: { + writable: false, enumerable: true, value: config.maxLayers + }, + hasOrientation: { + enumerable: true, get: function get() { + deprecateWarning('VRDisplayCapabilities.prototype.hasOrientation', 'VRDisplay.prototype.getFrameData'); + return config.hasOrientation; + } + } + }); +} +function VRDisplay(config) { + config = config || {}; + var USE_WAKELOCK = 'wakelock' in config ? config.wakelock : true; + this.isPolyfilled = true; + this.displayId = nextDisplayId++; + this.displayName = ''; + this.depthNear = 0.01; + this.depthFar = 10000.0; + this.isPresenting = false; + Object.defineProperty(this, 'isConnected', { + get: function get() { + deprecateWarning('VRDisplay.prototype.isConnected', 'VRDisplayCapabilities.prototype.hasExternalDisplay'); + return false; + } + }); + this.capabilities = new VRDisplayCapabilities({ + hasPosition: false, + hasOrientation: false, + hasExternalDisplay: false, + canPresent: false, + maxLayers: 1 + }); + this.stageParameters = null; + this.waitingForPresent_ = false; + this.layer_ = null; + this.originalParent_ = null; + this.fullscreenElement_ = null; + this.fullscreenWrapper_ = null; + this.fullscreenElementCachedStyle_ = null; + this.fullscreenEventTarget_ = null; + this.fullscreenChangeHandler_ = null; + this.fullscreenErrorHandler_ = null; + if (USE_WAKELOCK && isMobile()) { + this.wakelock_ = new NoSleep$1(); + } +} +VRDisplay.prototype.getFrameData = function (frameData) { + return frameDataFromPose(frameData, this._getPose(), this); +}; +VRDisplay.prototype.getPose = function () { + deprecateWarning('VRDisplay.prototype.getPose', 'VRDisplay.prototype.getFrameData'); + return this._getPose(); +}; +VRDisplay.prototype.resetPose = function () { + deprecateWarning('VRDisplay.prototype.resetPose'); + return this._resetPose(); +}; +VRDisplay.prototype.getImmediatePose = function () { + deprecateWarning('VRDisplay.prototype.getImmediatePose', 'VRDisplay.prototype.getFrameData'); + return this._getPose(); +}; +VRDisplay.prototype.requestAnimationFrame = function (callback) { + return raf(callback); +}; +VRDisplay.prototype.cancelAnimationFrame = function (id) { + return caf(id); +}; +VRDisplay.prototype.wrapForFullscreen = function (element) { + if (isIOS()) { + return element; + } + if (!this.fullscreenWrapper_) { + this.fullscreenWrapper_ = document.createElement('div'); + var cssProperties = ['height: ' + Math.min(screen.height, screen.width) + 'px !important', 'top: 0 !important', 'left: 0 !important', 'right: 0 !important', 'border: 0', 'margin: 0', 'padding: 0', 'z-index: 999999 !important', 'position: fixed']; + this.fullscreenWrapper_.setAttribute('style', cssProperties.join('; ') + ';'); + this.fullscreenWrapper_.classList.add('webvr-polyfill-fullscreen-wrapper'); + } + if (this.fullscreenElement_ == element) { + return this.fullscreenWrapper_; + } + if (this.fullscreenElement_) { + if (this.originalParent_) { + this.originalParent_.appendChild(this.fullscreenElement_); + } else { + this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_); + } + } + this.fullscreenElement_ = element; + this.originalParent_ = element.parentElement; + if (!this.originalParent_) { + document.body.appendChild(element); + } + if (!this.fullscreenWrapper_.parentElement) { + var parent = this.fullscreenElement_.parentElement; + parent.insertBefore(this.fullscreenWrapper_, this.fullscreenElement_); + parent.removeChild(this.fullscreenElement_); + } + this.fullscreenWrapper_.insertBefore(this.fullscreenElement_, this.fullscreenWrapper_.firstChild); + this.fullscreenElementCachedStyle_ = this.fullscreenElement_.getAttribute('style'); + var self = this; + function applyFullscreenElementStyle() { + if (!self.fullscreenElement_) { + return; + } + var cssProperties = ['position: absolute', 'top: 0', 'left: 0', 'width: ' + Math.max(screen.width, screen.height) + 'px', 'height: ' + Math.min(screen.height, screen.width) + 'px', 'border: 0', 'margin: 0', 'padding: 0']; + self.fullscreenElement_.setAttribute('style', cssProperties.join('; ') + ';'); + } + applyFullscreenElementStyle(); + return this.fullscreenWrapper_; +}; +VRDisplay.prototype.removeFullscreenWrapper = function () { + if (!this.fullscreenElement_) { + return; + } + var element = this.fullscreenElement_; + if (this.fullscreenElementCachedStyle_) { + element.setAttribute('style', this.fullscreenElementCachedStyle_); + } else { + element.removeAttribute('style'); + } + this.fullscreenElement_ = null; + this.fullscreenElementCachedStyle_ = null; + var parent = this.fullscreenWrapper_.parentElement; + this.fullscreenWrapper_.removeChild(element); + if (this.originalParent_ === parent) { + parent.insertBefore(element, this.fullscreenWrapper_); + } + else if (this.originalParent_) { + this.originalParent_.appendChild(element); + } + parent.removeChild(this.fullscreenWrapper_); + return element; +}; +VRDisplay.prototype.requestPresent = function (layers) { + var wasPresenting = this.isPresenting; + var self = this; + if (!(layers instanceof Array)) { + deprecateWarning('VRDisplay.prototype.requestPresent with non-array argument', 'an array of VRLayers as the first argument'); + layers = [layers]; + } + return new Promise(function (resolve, reject) { + if (!self.capabilities.canPresent) { + reject(new Error('VRDisplay is not capable of presenting.')); + return; + } + if (layers.length == 0 || layers.length > self.capabilities.maxLayers) { + reject(new Error('Invalid number of layers.')); + return; + } + var incomingLayer = layers[0]; + if (!incomingLayer.source) { + resolve(); + return; + } + var leftBounds = incomingLayer.leftBounds || defaultLeftBounds; + var rightBounds = incomingLayer.rightBounds || defaultRightBounds; + if (wasPresenting) { + var layer = self.layer_; + if (layer.source !== incomingLayer.source) { + layer.source = incomingLayer.source; + } + for (var i = 0; i < 4; i++) { + layer.leftBounds[i] = leftBounds[i]; + layer.rightBounds[i] = rightBounds[i]; + } + self.wrapForFullscreen(self.layer_.source); + self.updatePresent_(); + resolve(); + return; + } + self.layer_ = { + predistorted: incomingLayer.predistorted, + source: incomingLayer.source, + leftBounds: leftBounds.slice(0), + rightBounds: rightBounds.slice(0) + }; + self.waitingForPresent_ = false; + if (self.layer_ && self.layer_.source) { + var fullscreenElement = self.wrapForFullscreen(self.layer_.source); + var onFullscreenChange = function onFullscreenChange() { + var actualFullscreenElement = getFullscreenElement(); + self.isPresenting = fullscreenElement === actualFullscreenElement; + if (self.isPresenting) { + if (screen.orientation && screen.orientation.lock) { + screen.orientation.lock('landscape-primary').catch(function (error) { + console.error('screen.orientation.lock() failed due to', error.message); + }); + } + self.waitingForPresent_ = false; + self.beginPresent_(); + resolve(); + } else { + if (screen.orientation && screen.orientation.unlock) { + screen.orientation.unlock(); + } + self.removeFullscreenWrapper(); + self.disableWakeLock(); + self.endPresent_(); + self.removeFullscreenListeners_(); + } + self.fireVRDisplayPresentChange_(); + }; + var onFullscreenError = function onFullscreenError() { + if (!self.waitingForPresent_) { + return; + } + self.removeFullscreenWrapper(); + self.removeFullscreenListeners_(); + self.disableWakeLock(); + self.waitingForPresent_ = false; + self.isPresenting = false; + reject(new Error('Unable to present.')); + }; + self.addFullscreenListeners_(fullscreenElement, onFullscreenChange, onFullscreenError); + if (requestFullscreen(fullscreenElement)) { + self.enableWakeLock(); + self.waitingForPresent_ = true; + } else if (isIOS() || isWebViewAndroid()) { + self.enableWakeLock(); + self.isPresenting = true; + self.beginPresent_(); + self.fireVRDisplayPresentChange_(); + resolve(); + } + } + if (!self.waitingForPresent_ && !isIOS()) { + exitFullscreen(); + reject(new Error('Unable to present.')); + } + }); +}; +VRDisplay.prototype.exitPresent = function () { + var wasPresenting = this.isPresenting; + var self = this; + this.isPresenting = false; + this.layer_ = null; + this.disableWakeLock(); + return new Promise(function (resolve, reject) { + if (wasPresenting) { + if (!exitFullscreen() && isIOS()) { + self.endPresent_(); + self.fireVRDisplayPresentChange_(); + } + if (isWebViewAndroid()) { + self.removeFullscreenWrapper(); + self.removeFullscreenListeners_(); + self.endPresent_(); + self.fireVRDisplayPresentChange_(); + } + resolve(); + } else { + reject(new Error('Was not presenting to VRDisplay.')); + } + }); +}; +VRDisplay.prototype.getLayers = function () { + if (this.layer_) { + return [this.layer_]; + } + return []; +}; +VRDisplay.prototype.fireVRDisplayPresentChange_ = function () { + var event = new CustomEvent('vrdisplaypresentchange', { detail: { display: this } }); + window.dispatchEvent(event); +}; +VRDisplay.prototype.fireVRDisplayConnect_ = function () { + var event = new CustomEvent('vrdisplayconnect', { detail: { display: this } }); + window.dispatchEvent(event); +}; +VRDisplay.prototype.addFullscreenListeners_ = function (element, changeHandler, errorHandler) { + this.removeFullscreenListeners_(); + this.fullscreenEventTarget_ = element; + this.fullscreenChangeHandler_ = changeHandler; + this.fullscreenErrorHandler_ = errorHandler; + if (changeHandler) { + if (document.fullscreenEnabled) { + element.addEventListener('fullscreenchange', changeHandler, false); + } else if (document.webkitFullscreenEnabled) { + element.addEventListener('webkitfullscreenchange', changeHandler, false); + } else if (document.mozFullScreenEnabled) { + document.addEventListener('mozfullscreenchange', changeHandler, false); + } else if (document.msFullscreenEnabled) { + element.addEventListener('msfullscreenchange', changeHandler, false); + } + } + if (errorHandler) { + if (document.fullscreenEnabled) { + element.addEventListener('fullscreenerror', errorHandler, false); + } else if (document.webkitFullscreenEnabled) { + element.addEventListener('webkitfullscreenerror', errorHandler, false); + } else if (document.mozFullScreenEnabled) { + document.addEventListener('mozfullscreenerror', errorHandler, false); + } else if (document.msFullscreenEnabled) { + element.addEventListener('msfullscreenerror', errorHandler, false); + } + } +}; +VRDisplay.prototype.removeFullscreenListeners_ = function () { + if (!this.fullscreenEventTarget_) return; + var element = this.fullscreenEventTarget_; + if (this.fullscreenChangeHandler_) { + var changeHandler = this.fullscreenChangeHandler_; + element.removeEventListener('fullscreenchange', changeHandler, false); + element.removeEventListener('webkitfullscreenchange', changeHandler, false); + document.removeEventListener('mozfullscreenchange', changeHandler, false); + element.removeEventListener('msfullscreenchange', changeHandler, false); + } + if (this.fullscreenErrorHandler_) { + var errorHandler = this.fullscreenErrorHandler_; + element.removeEventListener('fullscreenerror', errorHandler, false); + element.removeEventListener('webkitfullscreenerror', errorHandler, false); + document.removeEventListener('mozfullscreenerror', errorHandler, false); + element.removeEventListener('msfullscreenerror', errorHandler, false); + } + this.fullscreenEventTarget_ = null; + this.fullscreenChangeHandler_ = null; + this.fullscreenErrorHandler_ = null; +}; +VRDisplay.prototype.enableWakeLock = function () { + if (this.wakelock_) { + this.wakelock_.enable(); + } +}; +VRDisplay.prototype.disableWakeLock = function () { + if (this.wakelock_) { + this.wakelock_.disable(); + } +}; +VRDisplay.prototype.beginPresent_ = function () { +}; +VRDisplay.prototype.endPresent_ = function () { +}; +VRDisplay.prototype.submitFrame = function (pose) { +}; +VRDisplay.prototype.getEyeParameters = function (whichEye) { + return null; +}; +var config = { + ADDITIONAL_VIEWERS: [], + DEFAULT_VIEWER: '', + MOBILE_WAKE_LOCK: true, + DEBUG: false, + DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json', + K_FILTER: 0.98, + PREDICTION_TIME_S: 0.040, + CARDBOARD_UI_DISABLED: false, + ROTATE_INSTRUCTIONS_DISABLED: false, + YAW_ONLY: false, + BUFFER_SCALE: 0.5, + DIRTY_SUBMIT_FRAME_BINDINGS: false +}; +var Eye = { + LEFT: 'left', + RIGHT: 'right' +}; +function CardboardVRDisplay(config$$1) { + var defaults = extend({}, config); + config$$1 = extend(defaults, config$$1 || {}); + VRDisplay.call(this, { + wakelock: config$$1.MOBILE_WAKE_LOCK + }); + this.config = config$$1; + this.displayName = 'Cardboard VRDisplay'; + this.capabilities = new VRDisplayCapabilities({ + hasPosition: false, + hasOrientation: true, + hasExternalDisplay: false, + canPresent: true, + maxLayers: 1 + }); + this.stageParameters = null; + this.bufferScale_ = this.config.BUFFER_SCALE; + this.poseSensor_ = new PoseSensor(this.config); + this.distorter_ = null; + this.cardboardUI_ = null; + this.dpdb_ = new Dpdb(this.config.DPDB_URL, this.onDeviceParamsUpdated_.bind(this)); + this.deviceInfo_ = new DeviceInfo(this.dpdb_.getDeviceParams(), config$$1.ADDITIONAL_VIEWERS); + this.viewerSelector_ = new ViewerSelector(config$$1.DEFAULT_VIEWER); + this.viewerSelector_.onChange(this.onViewerChanged_.bind(this)); + this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer()); + if (!this.config.ROTATE_INSTRUCTIONS_DISABLED) { + this.rotateInstructions_ = new RotateInstructions(); + } + if (isIOS()) { + window.addEventListener('resize', this.onResize_.bind(this)); + } +} +CardboardVRDisplay.prototype = Object.create(VRDisplay.prototype); +CardboardVRDisplay.prototype._getPose = function () { + return { + position: null, + orientation: this.poseSensor_.getOrientation(), + linearVelocity: null, + linearAcceleration: null, + angularVelocity: null, + angularAcceleration: null + }; +}; +CardboardVRDisplay.prototype._resetPose = function () { + if (this.poseSensor_.resetPose) { + this.poseSensor_.resetPose(); + } +}; +CardboardVRDisplay.prototype._getFieldOfView = function (whichEye) { + var fieldOfView; + if (whichEye == Eye.LEFT) { + fieldOfView = this.deviceInfo_.getFieldOfViewLeftEye(); + } else if (whichEye == Eye.RIGHT) { + fieldOfView = this.deviceInfo_.getFieldOfViewRightEye(); + } else { + console.error('Invalid eye provided: %s', whichEye); + return null; + } + return fieldOfView; +}; +CardboardVRDisplay.prototype._getEyeOffset = function (whichEye) { + var offset; + if (whichEye == Eye.LEFT) { + offset = [-this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0]; + } else if (whichEye == Eye.RIGHT) { + offset = [this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0]; + } else { + console.error('Invalid eye provided: %s', whichEye); + return null; + } + return offset; +}; +CardboardVRDisplay.prototype.getEyeParameters = function (whichEye) { + var offset = this._getEyeOffset(whichEye); + var fieldOfView = this._getFieldOfView(whichEye); + var eyeParams = { + offset: offset, + renderWidth: this.deviceInfo_.device.width * 0.5 * this.bufferScale_, + renderHeight: this.deviceInfo_.device.height * this.bufferScale_ + }; + Object.defineProperty(eyeParams, 'fieldOfView', { + enumerable: true, + get: function get() { + deprecateWarning('VRFieldOfView', 'VRFrameData\'s projection matrices'); + return fieldOfView; + } + }); + return eyeParams; +}; +CardboardVRDisplay.prototype.onDeviceParamsUpdated_ = function (newParams) { + if (this.config.DEBUG) { + console.log('DPDB reported that device params were updated.'); + } + this.deviceInfo_.updateDeviceParams(newParams); + if (this.distorter_) { + this.distorter_.updateDeviceInfo(this.deviceInfo_); + } +}; +CardboardVRDisplay.prototype.updateBounds_ = function () { + if (this.layer_ && this.distorter_ && (this.layer_.leftBounds || this.layer_.rightBounds)) { + this.distorter_.setTextureBounds(this.layer_.leftBounds, this.layer_.rightBounds); + } +}; +CardboardVRDisplay.prototype.beginPresent_ = function () { + var gl = this.layer_.source.getContext('webgl'); + if (!gl) gl = this.layer_.source.getContext('experimental-webgl'); + if (!gl) gl = this.layer_.source.getContext('webgl2'); + if (!gl) return; + if (this.layer_.predistorted) { + if (!this.config.CARDBOARD_UI_DISABLED) { + gl.canvas.width = getScreenWidth() * this.bufferScale_; + gl.canvas.height = getScreenHeight() * this.bufferScale_; + this.cardboardUI_ = new CardboardUI(gl); + } + } else { + if (!this.config.CARDBOARD_UI_DISABLED) { + this.cardboardUI_ = new CardboardUI(gl); + } + this.distorter_ = new CardboardDistorter(gl, this.cardboardUI_, this.config.BUFFER_SCALE, this.config.DIRTY_SUBMIT_FRAME_BINDINGS); + this.distorter_.updateDeviceInfo(this.deviceInfo_); + } + if (this.cardboardUI_) { + this.cardboardUI_.listen(function (e) { + this.viewerSelector_.show(this.layer_.source.parentElement); + e.stopPropagation(); + e.preventDefault(); + }.bind(this), function (e) { + this.exitPresent(); + e.stopPropagation(); + e.preventDefault(); + }.bind(this)); + } + if (this.rotateInstructions_) { + if (isLandscapeMode() && isMobile()) { + this.rotateInstructions_.showTemporarily(3000, this.layer_.source.parentElement); + } else { + this.rotateInstructions_.update(); + } + } + this.orientationHandler = this.onOrientationChange_.bind(this); + window.addEventListener('orientationchange', this.orientationHandler); + this.vrdisplaypresentchangeHandler = this.updateBounds_.bind(this); + window.addEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler); + this.fireVRDisplayDeviceParamsChange_(); +}; +CardboardVRDisplay.prototype.endPresent_ = function () { + if (this.distorter_) { + this.distorter_.destroy(); + this.distorter_ = null; + } + if (this.cardboardUI_) { + this.cardboardUI_.destroy(); + this.cardboardUI_ = null; + } + if (this.rotateInstructions_) { + this.rotateInstructions_.hide(); + } + this.viewerSelector_.hide(); + window.removeEventListener('orientationchange', this.orientationHandler); + window.removeEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler); +}; +CardboardVRDisplay.prototype.updatePresent_ = function () { + this.endPresent_(); + this.beginPresent_(); +}; +CardboardVRDisplay.prototype.submitFrame = function (pose) { + if (this.distorter_) { + this.updateBounds_(); + this.distorter_.submitFrame(); + } else if (this.cardboardUI_ && this.layer_) { + var canvas = this.layer_.source.getContext('webgl').canvas; + if (canvas.width != this.lastWidth || canvas.height != this.lastHeight) { + this.cardboardUI_.onResize(); + } + this.lastWidth = canvas.width; + this.lastHeight = canvas.height; + this.cardboardUI_.render(); + } +}; +CardboardVRDisplay.prototype.onOrientationChange_ = function (e) { + this.viewerSelector_.hide(); + if (this.rotateInstructions_) { + this.rotateInstructions_.update(); + } + this.onResize_(); +}; +CardboardVRDisplay.prototype.onResize_ = function (e) { + if (this.layer_) { + var gl = this.layer_.source.getContext('webgl'); + var cssProperties = ['position: absolute', 'top: 0', 'left: 0', + 'width: 100vw', 'height: 100vh', 'border: 0', 'margin: 0', + 'padding: 0px', 'box-sizing: content-box']; + gl.canvas.setAttribute('style', cssProperties.join('; ') + ';'); + safariCssSizeWorkaround(gl.canvas); + } +}; +CardboardVRDisplay.prototype.onViewerChanged_ = function (viewer) { + this.deviceInfo_.setViewer(viewer); + if (this.distorter_) { + this.distorter_.updateDeviceInfo(this.deviceInfo_); + } + this.fireVRDisplayDeviceParamsChange_(); +}; +CardboardVRDisplay.prototype.fireVRDisplayDeviceParamsChange_ = function () { + var event = new CustomEvent('vrdisplaydeviceparamschange', { + detail: { + vrdisplay: this, + deviceInfo: this.deviceInfo_ + } + }); + window.dispatchEvent(event); +}; +CardboardVRDisplay.VRFrameData = VRFrameData; +CardboardVRDisplay.VRDisplay = VRDisplay; +return CardboardVRDisplay; +}))); +}); +var CardboardVRDisplay = unwrapExports(cardboardVrDisplay); + +class XRDevice extends EventTarget { + constructor(global) { + super(); + this.global = global; + this.onWindowResize = this.onWindowResize.bind(this); + this.global.window.addEventListener('resize', this.onWindowResize); + this.environmentBlendMode = 'opaque'; + } + onBaseLayerSet(sessionId, layer) { throw new Error('Not implemented'); } + isSessionSupported(mode) { throw new Error('Not implemented'); } + isFeatureSupported(featureDescriptor) { throw new Error('Not implemented'); } + async requestSession(mode, enabledFeatures) { throw new Error('Not implemented'); } + requestAnimationFrame(callback) { throw new Error('Not implemented'); } + onFrameStart(sessionId) { throw new Error('Not implemented'); } + onFrameEnd(sessionId) { throw new Error('Not implemented'); } + doesSessionSupportReferenceSpace(sessionId, type) { throw new Error('Not implemented'); } + requestStageBounds() { throw new Error('Not implemented'); } + async requestFrameOfReferenceTransform(type, options) { + return undefined; + } + cancelAnimationFrame(handle) { throw new Error('Not implemented'); } + endSession(sessionId) { throw new Error('Not implemented'); } + getViewport(sessionId, eye, layer, target) { throw new Error('Not implemented'); } + getProjectionMatrix(eye) { throw new Error('Not implemented'); } + getBasePoseMatrix() { throw new Error('Not implemented'); } + getBaseViewMatrix(eye) { throw new Error('Not implemented'); } + getInputSources() { throw new Error('Not implemented'); } + getInputPose(inputSource, coordinateSystem, poseType) { throw new Error('Not implemented'); } + onWindowResize() { + this.onWindowResize(); + } +} + +let daydream = { + mapping: '', + profiles: ['google-daydream', 'generic-trigger-touchpad'], + buttons: { + length: 3, + 0: null, + 1: null, + 2: 0 + }, +}; +let viveFocus = { + mapping: 'xr-standard', + profiles: ['htc-vive-focus', 'generic-trigger-touchpad'], + buttons: { + length: 3, + 0: 1, + 1: null, + 2: 0 + }, +}; +let oculusGo = { + mapping: 'xr-standard', + profiles: ['oculus-go', 'generic-trigger-touchpad'], + buttons: { + length: 3, + 0: 1, + 1: null, + 2: 0 + }, + gripTransform: { + orientation: [Math.PI * 0.11, 0, 0, 1] + } +}; +let oculusTouch = { + mapping: 'xr-standard', + displayProfiles: { + 'Oculus Quest': ['oculus-touch-v2', 'oculus-touch', 'generic-trigger-squeeze-thumbstick'] + }, + profiles: ['oculus-touch', 'generic-trigger-squeeze-thumbstick'], + axes: { + length: 4, + 0: null, + 1: null, + 2: 0, + 3: 1 + }, + buttons: { + length: 7, + 0: 1, + 1: 2, + 2: null, + 3: 0, + 4: 3, + 5: 4, + 6: null + }, + gripTransform: { + position: [0, -0.02, 0.04, 1], + orientation: [Math.PI * 0.11, 0, 0, 1] + } +}; +let openVr = { + mapping: 'xr-standard', + profiles: ['htc-vive', 'generic-trigger-squeeze-touchpad'], + displayProfiles: { + 'HTC Vive': ['htc-vive', 'generic-trigger-squeeze-touchpad'], + 'HTC Vive DVT': ['htc-vive', 'generic-trigger-squeeze-touchpad'], + 'Valve Index': ['valve-index', 'generic-trigger-squeeze-touchpad-thumbstick'] + }, + buttons: { + length: 3, + 0: 1, + 1: 2, + 2: 0 + }, + gripTransform: { + position: [0, 0, 0.05, 1], + }, + targetRayTransform: { + orientation: [Math.PI * -0.08, 0, 0, 1] + }, + userAgentOverrides: { + "Firefox": { + axes: { + invert: [1, 3] + } + } + } +}; +let samsungGearVR = { + mapping: 'xr-standard', + profiles: ['samsung-gearvr', 'generic-trigger-touchpad'], + buttons: { + length: 3, + 0: 1, + 1: null, + 2: 0 + }, + gripTransform: { + orientation: [Math.PI * 0.11, 0, 0, 1] + } +}; +let samsungOdyssey = { + mapping: 'xr-standard', + profiles: ['samsung-odyssey', 'microsoft-mixed-reality', 'generic-trigger-squeeze-touchpad-thumbstick'], + buttons: { + length: 4, + 0: 1, + 1: 0, + 2: 2, + 3: 4, + }, + gripTransform: { + position: [0, -0.02, 0.04, 1], + orientation: [Math.PI * 0.11, 0, 0, 1] + } +}; +let windowsMixedReality = { + mapping: 'xr-standard', + profiles: ['microsoft-mixed-reality', 'generic-trigger-squeeze-touchpad-thumbstick'], + buttons: { + length: 4, + 0: 1, + 1: 0, + 2: 2, + 3: 4, + }, + gripTransform: { + position: [0, -0.02, 0.04, 1], + orientation: [Math.PI * 0.11, 0, 0, 1] + } +}; +let GamepadMappings = { + 'Daydream Controller': daydream, + 'Gear VR Controller': samsungGearVR, + 'HTC Vive Focus Controller': viveFocus, + 'Oculus Go Controller': oculusGo, + 'Oculus Touch (Right)': oculusTouch, + 'Oculus Touch (Left)': oculusTouch, + 'OpenVR Gamepad': openVr, + 'Spatial Controller (Spatial Interaction Source) 045E-065A': windowsMixedReality, + 'Spatial Controller (Spatial Interaction Source) 045E-065D': samsungOdyssey, + 'Windows Mixed Reality (Right)': windowsMixedReality, + 'Windows Mixed Reality (Left)': windowsMixedReality, +}; + +const HEAD_ELBOW_OFFSET_RIGHTHANDED = fromValues$1(0.155, -0.465, -0.15); +const HEAD_ELBOW_OFFSET_LEFTHANDED = fromValues$1(-0.155, -0.465, -0.15); +const ELBOW_WRIST_OFFSET = fromValues$1(0, 0, -0.25); +const WRIST_CONTROLLER_OFFSET = fromValues$1(0, 0, 0.05); +const ARM_EXTENSION_OFFSET = fromValues$1(-0.08, 0.14, 0.08); +const ELBOW_BEND_RATIO = 0.4; +const EXTENSION_RATIO_WEIGHT = 0.4; +const MIN_ANGULAR_SPEED = 0.61; +const MIN_ANGLE_DELTA = 0.175; +const MIN_EXTENSION_COS = 0.12; +const MAX_EXTENSION_COS = 0.87; +const RAD_TO_DEG = 180 / Math.PI; +function eulerFromQuaternion(out, q, order) { + function clamp(value, min$$1, max$$1) { + return (value < min$$1 ? min$$1 : (value > max$$1 ? max$$1 : value)); + } + var sqx = q[0] * q[0]; + var sqy = q[1] * q[1]; + var sqz = q[2] * q[2]; + var sqw = q[3] * q[3]; + if ( order === 'XYZ' ) { + out[0] = Math.atan2( 2 * ( q[0] * q[3] - q[1] * q[2] ), ( sqw - sqx - sqy + sqz ) ); + out[1] = Math.asin( clamp( 2 * ( q[0] * q[2] + q[1] * q[3] ), -1, 1 ) ); + out[2] = Math.atan2( 2 * ( q[2] * q[3] - q[0] * q[1] ), ( sqw + sqx - sqy - sqz ) ); + } else if ( order === 'YXZ' ) { + out[0] = Math.asin( clamp( 2 * ( q[0] * q[3] - q[1] * q[2] ), -1, 1 ) ); + out[1] = Math.atan2( 2 * ( q[0] * q[2] + q[1] * q[3] ), ( sqw - sqx - sqy + sqz ) ); + out[2] = Math.atan2( 2 * ( q[0] * q[1] + q[2] * q[3] ), ( sqw - sqx + sqy - sqz ) ); + } else if ( order === 'ZXY' ) { + out[0] = Math.asin( clamp( 2 * ( q[0] * q[3] + q[1] * q[2] ), -1, 1 ) ); + out[1] = Math.atan2( 2 * ( q[1] * q[3] - q[2] * q[0] ), ( sqw - sqx - sqy + sqz ) ); + out[2] = Math.atan2( 2 * ( q[2] * q[3] - q[0] * q[1] ), ( sqw - sqx + sqy - sqz ) ); + } else if ( order === 'ZYX' ) { + out[0] = Math.atan2( 2 * ( q[0] * q[3] + q[2] * q[1] ), ( sqw - sqx - sqy + sqz ) ); + out[1] = Math.asin( clamp( 2 * ( q[1] * q[3] - q[0] * q[2] ), -1, 1 ) ); + out[2] = Math.atan2( 2 * ( q[0] * q[1] + q[2] * q[3] ), ( sqw + sqx - sqy - sqz ) ); + } else if ( order === 'YZX' ) { + out[0] = Math.atan2( 2 * ( q[0] * q[3] - q[2] * q[1] ), ( sqw - sqx + sqy - sqz ) ); + out[1] = Math.atan2( 2 * ( q[1] * q[3] - q[0] * q[2] ), ( sqw + sqx - sqy - sqz ) ); + out[2] = Math.asin( clamp( 2 * ( q[0] * q[1] + q[2] * q[3] ), -1, 1 ) ); + } else if ( order === 'XZY' ) { + out[0] = Math.atan2( 2 * ( q[0] * q[3] + q[1] * q[2] ), ( sqw - sqx + sqy - sqz ) ); + out[1] = Math.atan2( 2 * ( q[0] * q[2] + q[1] * q[3] ), ( sqw + sqx - sqy - sqz ) ); + out[2] = Math.asin( clamp( 2 * ( q[2] * q[3] - q[0] * q[1] ), -1, 1 ) ); + } else { + console.log('No order given for quaternion to euler conversion.'); + return; + } +} +class OrientationArmModel { + constructor() { + this.hand = 'right'; + this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED; + this.controllerQ = create$4(); + this.lastControllerQ = create$4(); + this.headQ = create$4(); + this.headPos = create$1(); + this.elbowPos = create$1(); + this.wristPos = create$1(); + this.time = null; + this.lastTime = null; + this.rootQ = create$4(); + this.position = create$1(); + } + setHandedness(hand) { + if (this.hand != hand) { + this.hand = hand; + if (this.hand == 'left') { + this.headElbowOffset = HEAD_ELBOW_OFFSET_LEFTHANDED; + } else { + this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED; + } + } + } + update(controllerOrientation, headPoseMatrix) { + this.time = now$1(); + if (controllerOrientation) { + copy$4(this.lastControllerQ, this.controllerQ); + copy$4(this.controllerQ, controllerOrientation); + } + if (headPoseMatrix) { + getTranslation(this.headPos, headPoseMatrix); + getRotation(this.headQ, headPoseMatrix); + } + let headYawQ = this.getHeadYawOrientation_(); + let angleDelta = this.quatAngle_(this.lastControllerQ, this.controllerQ); + let timeDelta = (this.time - this.lastTime) / 1000; + let controllerAngularSpeed = angleDelta / timeDelta; + if (controllerAngularSpeed > MIN_ANGULAR_SPEED) { + slerp(this.rootQ, this.rootQ, headYawQ, + Math.min(angleDelta / MIN_ANGLE_DELTA, 1.0)); + } else { + copy$4(this.rootQ, headYawQ); + } + let controllerForward = fromValues$1(0, 0, -1.0); + transformQuat(controllerForward, controllerForward, this.controllerQ); + let controllerDotY = dot(controllerForward, [0, 1, 0]); + let extensionRatio = this.clamp_( + (controllerDotY - MIN_EXTENSION_COS) / MAX_EXTENSION_COS, 0.0, 1.0); + let controllerCameraQ = clone$4(this.rootQ); + invert$2(controllerCameraQ, controllerCameraQ); + multiply$4(controllerCameraQ, controllerCameraQ, this.controllerQ); + let elbowPos = this.elbowPos; + copy$1(elbowPos, this.headPos); + add$1(elbowPos, elbowPos, this.headElbowOffset); + let elbowOffset = clone$1(ARM_EXTENSION_OFFSET); + scale$1(elbowOffset, elbowOffset, extensionRatio); + add$1(elbowPos, elbowPos, elbowOffset); + let totalAngle = this.quatAngle_(controllerCameraQ, create$4()); + let totalAngleDeg = totalAngle * RAD_TO_DEG; + let lerpSuppression = 1 - Math.pow(totalAngleDeg / 180, 4);let elbowRatio = ELBOW_BEND_RATIO; + let wristRatio = 1 - ELBOW_BEND_RATIO; + let lerpValue = lerpSuppression * + (elbowRatio + wristRatio * extensionRatio * EXTENSION_RATIO_WEIGHT); + let wristQ = create$4(); + slerp(wristQ, wristQ, controllerCameraQ, lerpValue); + let invWristQ = invert$2(create$4(), wristQ); + let elbowQ = clone$4(controllerCameraQ); + multiply$4(elbowQ, elbowQ, invWristQ); + let wristPos = this.wristPos; + copy$1(wristPos, WRIST_CONTROLLER_OFFSET); + transformQuat(wristPos, wristPos, wristQ); + add$1(wristPos, wristPos, ELBOW_WRIST_OFFSET); + transformQuat(wristPos, wristPos, elbowQ); + add$1(wristPos, wristPos, elbowPos); + let offset = clone$1(ARM_EXTENSION_OFFSET); + scale$1(offset, offset, extensionRatio); + add$1(this.position, this.wristPos, offset); + transformQuat(this.position, this.position, this.rootQ); + this.lastTime = this.time; + } + getPosition() { + return this.position; + } + getHeadYawOrientation_() { + let headEuler = create$1(); + eulerFromQuaternion(headEuler, this.headQ, 'YXZ'); + let destinationQ = fromEuler(create$4(), 0, headEuler[1] * RAD_TO_DEG, 0); + return destinationQ; + } + clamp_(value, min$$1, max$$1) { + return Math.min(Math.max(value, min$$1), max$$1); + } + quatAngle_(q1, q2) { + let vec1 = [0, 0, -1]; + let vec2 = [0, 0, -1]; + transformQuat(vec1, vec1, q1); + transformQuat(vec2, vec2, q2); + return angle(vec1, vec2); + } +} + +const PRIVATE$18 = Symbol('@@webxr-polyfill/XRRemappedGamepad'); +const PLACEHOLDER_BUTTON = { pressed: false, touched: false, value: 0.0 }; +Object.freeze(PLACEHOLDER_BUTTON); +class XRRemappedGamepad { + constructor(gamepad, display, map) { + if (!map) { + map = {}; + } + if (map.userAgentOverrides) { + for (let agent in map.userAgentOverrides) { + if (navigator.userAgent.includes(agent)) { + let override = map.userAgentOverrides[agent]; + for (let key in override) { + if (key in map) { + Object.assign(map[key], override[key]); + } else { + map[key] = override[key]; + } + } + break; + } + } + } + let axes = new Array(map.axes && map.axes.length ? map.axes.length : gamepad.axes.length); + let buttons = new Array(map.buttons && map.buttons.length ? map.buttons.length : gamepad.buttons.length); + let gripTransform = null; + if (map.gripTransform) { + let orientation = map.gripTransform.orientation || [0, 0, 0, 1]; + gripTransform = create(); + fromRotationTranslation( + gripTransform, + normalize$2(orientation, orientation), + map.gripTransform.position || [0, 0, 0] + ); + } + let targetRayTransform = null; + if (map.targetRayTransform) { + let orientation = map.targetRayTransform.orientation || [0, 0, 0, 1]; + targetRayTransform = create(); + fromRotationTranslation( + targetRayTransform, + normalize$2(orientation, orientation), + map.targetRayTransform.position || [0, 0, 0] + ); + } + let profiles = map.profiles; + if (map.displayProfiles) { + if (display.displayName in map.displayProfiles) { + profiles = map.displayProfiles[display.displayName]; + } + } + this[PRIVATE$18] = { + gamepad, + map, + profiles: profiles || [gamepad.id], + mapping: map.mapping || gamepad.mapping, + axes, + buttons, + gripTransform, + targetRayTransform, + }; + this._update(); + } + _update() { + let gamepad = this[PRIVATE$18].gamepad; + let map = this[PRIVATE$18].map; + let axes = this[PRIVATE$18].axes; + for (let i = 0; i < axes.length; ++i) { + if (map.axes && i in map.axes) { + if (map.axes[i] === null) { + axes[i] = 0; + } else { + axes[i] = gamepad.axes[map.axes[i]]; + } + } else { + axes[i] = gamepad.axes[i]; + } + } + if (map.axes && map.axes.invert) { + for (let axis of map.axes.invert) { + if (axis < axes.length) { + axes[axis] *= -1; + } + } + } + let buttons = this[PRIVATE$18].buttons; + for (let i = 0; i < buttons.length; ++i) { + if (map.buttons && i in map.buttons) { + if (map.buttons[i] === null) { + buttons[i] = PLACEHOLDER_BUTTON; + } else { + buttons[i] = gamepad.buttons[map.buttons[i]]; + } + } else { + buttons[i] = gamepad.buttons[i]; + } + } + } + get id() { + return ''; + } + get _profiles() { + return this[PRIVATE$18].profiles; + } + get index() { + return -1; + } + get connected() { + return this[PRIVATE$18].gamepad.connected; + } + get timestamp() { + return this[PRIVATE$18].gamepad.timestamp; + } + get mapping() { + return this[PRIVATE$18].mapping; + } + get axes() { + return this[PRIVATE$18].axes; + } + get buttons() { + return this[PRIVATE$18].buttons; + } + get hapticActuators() { + return this[PRIVATE$18].gamepad.hapticActuators; + } +} +class GamepadXRInputSource { + constructor(polyfill, display, primaryButtonIndex = 0, primarySqueezeButtonIndex = -1) { + this.polyfill = polyfill; + this.display = display; + this.nativeGamepad = null; + this.gamepad = null; + this.inputSource = new XRInputSource(this); + this.lastPosition = create$1(); + this.emulatedPosition = false; + this.basePoseMatrix = create(); + this.outputMatrix = create(); + this.primaryButtonIndex = primaryButtonIndex; + this.primaryActionPressed = false; + this.primarySqueezeButtonIndex = primarySqueezeButtonIndex; + this.primarySqueezeActionPressed = false; + this.handedness = ''; + this.targetRayMode = 'gaze'; + this.armModel = null; + } + get profiles() { + return this.gamepad ? this.gamepad._profiles : []; + } + updateFromGamepad(gamepad) { + if (this.nativeGamepad !== gamepad) { + this.nativeGamepad = gamepad; + if (gamepad) { + this.gamepad = new XRRemappedGamepad(gamepad, this.display, GamepadMappings[gamepad.id]); + } else { + this.gamepad = null; + } + } + this.handedness = gamepad.hand === '' ? 'none' : gamepad.hand; + if (this.gamepad) { + this.gamepad._update(); + } + if (gamepad.pose) { + this.targetRayMode = 'tracked-pointer'; + this.emulatedPosition = !gamepad.pose.hasPosition; + } else if (gamepad.hand === '') { + this.targetRayMode = 'gaze'; + this.emulatedPosition = false; + } + } + updateBasePoseMatrix() { + if (this.nativeGamepad && this.nativeGamepad.pose) { + let pose = this.nativeGamepad.pose; + let position = pose.position; + let orientation = pose.orientation; + if (!position && !orientation) { + return; + } + if (!position) { + if (!pose.hasPosition) { + if (!this.armModel) { + this.armModel = new OrientationArmModel(); + } + this.armModel.setHandedness(this.nativeGamepad.hand); + this.armModel.update(orientation, this.polyfill.getBasePoseMatrix()); + position = this.armModel.getPosition(); + } else { + position = this.lastPosition; + } + } else { + this.lastPosition[0] = position[0]; + this.lastPosition[1] = position[1]; + this.lastPosition[2] = position[2]; + } + fromRotationTranslation(this.basePoseMatrix, orientation, position); + } else { + copy(this.basePoseMatrix, this.polyfill.getBasePoseMatrix()); + } + return this.basePoseMatrix; + } + getXRPose(coordinateSystem, poseType) { + this.updateBasePoseMatrix(); + switch(poseType) { + case "target-ray": + coordinateSystem._transformBasePoseMatrix(this.outputMatrix, this.basePoseMatrix); + if (this.gamepad && this.gamepad[PRIVATE$18].targetRayTransform) { + multiply(this.outputMatrix, this.outputMatrix, this.gamepad[PRIVATE$18].targetRayTransform); + } + break; + case "grip": + if (!this.nativeGamepad || !this.nativeGamepad.pose) { + return null; + } + coordinateSystem._transformBasePoseMatrix(this.outputMatrix, this.basePoseMatrix); + if (this.gamepad && this.gamepad[PRIVATE$18].gripTransform) { + multiply(this.outputMatrix, this.outputMatrix, this.gamepad[PRIVATE$18].gripTransform); + } + break; + default: + return null; + } + coordinateSystem._adjustForOriginOffset(this.outputMatrix); + return new XRPose(new XRRigidTransform(this.outputMatrix), this.emulatedPosition); + } +} + +const TEST_ENV = "production" === 'test'; +const EXTRA_PRESENTATION_ATTRIBUTES = { + highRefreshRate: true, +}; +const PRIMARY_BUTTON_MAP = { + oculus: 1, + openvr: 1, + 'spatial controller (spatial interaction source)': 1 +}; +let SESSION_ID = 0; +class Session { + constructor(mode, enabledFeatures, polyfillOptions={}) { + this.mode = mode; + this.enabledFeatures = enabledFeatures; + this.outputContext = null; + this.immersive = mode == 'immersive-vr' || mode == 'immersive-ar'; + this.ended = null; + this.baseLayer = null; + this.id = ++SESSION_ID; + this.modifiedCanvasLayer = false; + if (this.outputContext && !TEST_ENV) { + const renderContextType = polyfillOptions.renderContextType || '2d'; + this.renderContext = this.outputContext.canvas.getContext(renderContextType); + } + } +} +class WebVRDevice extends XRDevice { + constructor(global, display) { + const { canPresent } = display.capabilities; + super(global); + this.display = display; + this.frame = new global.VRFrameData(); + this.sessions = new Map(); + this.immersiveSession = null; + this.canPresent = canPresent; + this.baseModelMatrix = create(); + this.gamepadInputSources = {}; + this.tempVec3 = new Float32Array(3); + this.onVRDisplayPresentChange = this.onVRDisplayPresentChange.bind(this); + global.window.addEventListener('vrdisplaypresentchange', this.onVRDisplayPresentChange); + this.CAN_USE_GAMEPAD = global.navigator && ('getGamepads' in global.navigator); + this.HAS_BITMAP_SUPPORT = isImageBitmapSupported(global); + } + get depthNear() { return this.display.depthNear; } + set depthNear(val) { this.display.depthNear = val; } + get depthFar() { return this.display.depthFar; } + set depthFar(val) { this.display.depthFar = val; } + onBaseLayerSet(sessionId, layer) { + const session = this.sessions.get(sessionId); + const canvas = layer.context.canvas; + if (session.immersive) { + const left = this.display.getEyeParameters('left'); + const right = this.display.getEyeParameters('right'); + canvas.width = Math.max(left.renderWidth, right.renderWidth) * 2; + canvas.height = Math.max(left.renderHeight, right.renderHeight); + this.display.requestPresent([{ + source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES + }]).then(() => { + if (!TEST_ENV && !this.global.document.body.contains(canvas)) { + session.modifiedCanvasLayer = true; + this.global.document.body.appendChild(canvas); + applyCanvasStylesForMinimalRendering(canvas); + } + session.baseLayer = layer; + }); + } + else { + session.baseLayer = layer; + } + } + isSessionSupported(mode) { + if (mode == 'immersive-ar') { + return false; + } + if (mode == 'immersive-vr' && this.canPresent === false) { + return false; + } + return true; + } + isFeatureSupported(featureDescriptor) { + switch(featureDescriptor) { + case 'viewer': return true; + case 'local': return true; + case 'local-floor': return true; + case 'bounded': return false; + case 'unbounded': return false; + default: return false; + } + } + async requestSession(mode, enabledFeatures) { + if (!this.isSessionSupported(mode)) { + return Promise.reject(); + } + let immersive = mode == 'immersive-vr'; + if (immersive) { + const canvas = this.global.document.createElement('canvas'); + if (!TEST_ENV) { + const ctx = canvas.getContext('webgl'); + } + await this.display.requestPresent([{ + source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES }]); + } + const session = new Session(mode, enabledFeatures, { + renderContextType: this.HAS_BITMAP_SUPPORT ? 'bitmaprenderer' : '2d' + }); + this.sessions.set(session.id, session); + if (immersive) { + this.immersiveSession = session; + this.dispatchEvent('@@webxr-polyfill/vr-present-start', session.id); + } + return Promise.resolve(session.id); + } + requestAnimationFrame(callback) { + return this.display.requestAnimationFrame(callback); + } + getPrimaryButtonIndex(gamepad) { + let primaryButton = 0; + let name = gamepad.id.toLowerCase(); + for (let key in PRIMARY_BUTTON_MAP) { + if (name.includes(key)) { + primaryButton = PRIMARY_BUTTON_MAP[key]; + break; + } + } + return Math.min(primaryButton, gamepad.buttons.length - 1); + } + onFrameStart(sessionId, renderState) { + this.display.depthNear = renderState.depthNear; + this.display.depthFar = renderState.depthFar; + this.display.getFrameData(this.frame); + const session = this.sessions.get(sessionId); + if (session.immersive && this.CAN_USE_GAMEPAD) { + let prevInputSources = this.gamepadInputSources; + this.gamepadInputSources = {}; + let gamepads = this.global.navigator.getGamepads(); + for (let i = 0; i < gamepads.length; ++i) { + let gamepad = gamepads[i]; + if (gamepad && gamepad.displayId > 0) { + let inputSourceImpl = prevInputSources[i]; + if (!inputSourceImpl) { + inputSourceImpl = new GamepadXRInputSource(this, this.display, this.getPrimaryButtonIndex(gamepad)); + } + inputSourceImpl.updateFromGamepad(gamepad); + this.gamepadInputSources[i] = inputSourceImpl; + if (inputSourceImpl.primaryButtonIndex != -1) { + let primaryActionPressed = gamepad.buttons[inputSourceImpl.primaryButtonIndex].pressed; + if (primaryActionPressed && !inputSourceImpl.primaryActionPressed) { + this.dispatchEvent('@@webxr-polyfill/input-select-start', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); + } else if (!primaryActionPressed && inputSourceImpl.primaryActionPressed) { + this.dispatchEvent('@@webxr-polyfill/input-select-end', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); + } + inputSourceImpl.primaryActionPressed = primaryActionPressed; + } + if (inputSourceImpl.primarySqueezeButtonIndex != -1) { + let primarySqueezeActionPressed = gamepad.buttons[inputSourceImpl.primarySqueezeButtonIndex].pressed; + if (primarySqueezeActionPressed && !inputSourceImpl.primarySqueezeActionPressed) { + this.dispatchEvent('@@webxr-polyfill/input-squeeze-start', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); + } else if (!primarySqueezeActionPressed && inputSourceImpl.primarySqueezeActionPressed) { + this.dispatchEvent('@@webxr-polyfill/input-squeeze-end', { sessionId: session.id, inputSource: inputSourceImpl.inputSource }); + } + inputSourceImpl.primarySqueezeActionPressed = primarySqueezeActionPressed; + } + } + } + } + if (TEST_ENV) { + return; + } + if (!session.immersive && session.baseLayer) { + const canvas = session.baseLayer.context.canvas; + perspective(this.frame.leftProjectionMatrix, renderState.inlineVerticalFieldOfView, + canvas.width/canvas.height, renderState.depthNear, renderState.depthFar); + } + } + onFrameEnd(sessionId) { + const session = this.sessions.get(sessionId); + if (session.ended || !session.baseLayer) { + return; + } + if (session.outputContext && + !(session.immersive && !this.display.capabilities.hasExternalDisplay)) { + const mirroring = + session.immersive && this.display.capabilities.hasExternalDisplay; + const iCanvas = session.baseLayer.context.canvas; + const iWidth = mirroring ? iCanvas.width / 2 : iCanvas.width; + const iHeight = iCanvas.height; + if (!TEST_ENV) { + const oCanvas = session.outputContext.canvas; + const oWidth = oCanvas.width; + const oHeight = oCanvas.height; + const renderContext = session.renderContext; + if (this.HAS_BITMAP_SUPPORT) { + if (iCanvas.transferToImageBitmap) { + renderContext.transferFromImageBitmap(iCanvas.transferToImageBitmap()); + } + else { + this.global.createImageBitmap(iCanvas, 0, 0, iWidth, iHeight, { + resizeWidth: oWidth, + resizeHeight: oHeight, + }).then(bitmap => renderContext.transferFromImageBitmap(bitmap)); + } + } else { + renderContext.drawImage(iCanvas, 0, 0, iWidth, iHeight, + 0, 0, oWidth, oHeight); + } + } + } + if (session.immersive && session.baseLayer) { + this.display.submitFrame(); + } + } + cancelAnimationFrame(handle) { + this.display.cancelAnimationFrame(handle); + } + async endSession(sessionId) { + const session = this.sessions.get(sessionId); + if (session.ended) { + return; + } + if (session.immersive) { + return this.display.exitPresent(); + } else { + session.ended = true; + } + } + doesSessionSupportReferenceSpace(sessionId, type) { + const session = this.sessions.get(sessionId); + if (session.ended) { + return false; + } + return session.enabledFeatures.has(type); + } + requestStageBounds() { + if (this.display.stageParameters) { + const width = this.display.stageParameters.sizeX; + const depth = this.display.stageParameters.sizeZ; + const data = []; + data.push(-width / 2); + data.push(-depth / 2); + data.push(width / 2); + data.push(-depth / 2); + data.push(width / 2); + data.push(depth / 2); + data.push(-width / 2); + data.push(depth / 2); + return data; + } + return null; + } + async requestFrameOfReferenceTransform(type, options) { + if ((type === 'local-floor' || type === 'bounded-floor') && + this.display.stageParameters && + this.display.stageParameters.sittingToStandingTransform) { + return this.display.stageParameters.sittingToStandingTransform; + } + return null; + } + getProjectionMatrix(eye) { + if (eye === 'left') { + return this.frame.leftProjectionMatrix; + } else if (eye === 'right') { + return this.frame.rightProjectionMatrix; + } else if (eye === 'none') { + return this.frame.leftProjectionMatrix; + } else { + throw new Error(`eye must be of type 'left' or 'right'`); + } + } + getViewport(sessionId, eye, layer, target) { + const session = this.sessions.get(sessionId); + const { width, height } = layer.context.canvas; + if (!session.immersive) { + target.x = target.y = 0; + target.width = width; + target.height = height; + return true; + } + if (eye === 'left' || eye === 'none') { + target.x = 0; + } else if (eye === 'right') { + target.x = width / 2; + } else { + return false; + } + target.y = 0; + target.width = width / 2; + target.height = height; + return true; + } + getBasePoseMatrix() { + let { position, orientation } = this.frame.pose; + if (!position && !orientation) { + return this.baseModelMatrix; + } + if (!position) { + position = this.tempVec3; + position[0] = position[1] = position[2] = 0; + } + fromRotationTranslation(this.baseModelMatrix, orientation, position); + return this.baseModelMatrix; + } + getBaseViewMatrix(eye) { + if (eye === 'left' || eye === 'none') { + return this.frame.leftViewMatrix; + } else if (eye === 'right') { + return this.frame.rightViewMatrix; + } else { + throw new Error(`eye must be of type 'left' or 'right'`); + } + } + getInputSources() { + let inputSources = []; + for (let i in this.gamepadInputSources) { + inputSources.push(this.gamepadInputSources[i].inputSource); + } + return inputSources; + } + getInputPose(inputSource, coordinateSystem, poseType) { + if (!coordinateSystem) { + return null; + } + for (let i in this.gamepadInputSources) { + let inputSourceImpl = this.gamepadInputSources[i]; + if (inputSourceImpl.inputSource === inputSource) { + return inputSourceImpl.getXRPose(coordinateSystem, poseType); + } + } + return null; + } + onWindowResize() { + } + onVRDisplayPresentChange(e) { + if (!this.display.isPresenting) { + this.sessions.forEach(session => { + if (session.immersive && !session.ended) { + if (session.modifiedCanvasLayer) { + const canvas = session.baseLayer.context.canvas; + document.body.removeChild(canvas); + canvas.setAttribute('style', ''); + } + if (this.immersiveSession === session) { + this.immersiveSession = null; + } + this.dispatchEvent('@@webxr-polyfill/vr-present-end', session.id); + } + }); + } + } +} + +class CardboardXRDevice extends WebVRDevice { + constructor(global, cardboardConfig) { + const display = new CardboardVRDisplay(cardboardConfig || {}); + super(global, display); + this.display = display; + this.frame = { + rightViewMatrix: new Float32Array(16), + leftViewMatrix: new Float32Array(16), + rightProjectionMatrix: new Float32Array(16), + leftProjectionMatrix: new Float32Array(16), + pose: null, + timestamp: null, + }; + } +} + +const TEST_ENV$1 = "production" === 'test'; +let SESSION_ID$1 = 0; +class Session$1 { + constructor(mode, enabledFeatures) { + this.mode = mode; + this.enabledFeatures = enabledFeatures; + this.ended = null; + this.baseLayer = null; + this.id = ++SESSION_ID$1; + } +} +class InlineDevice extends XRDevice { + constructor(global) { + super(global); + this.sessions = new Map(); + this.projectionMatrix = create(); + this.identityMatrix = create(); + } + onBaseLayerSet(sessionId, layer) { + const session = this.sessions.get(sessionId); + session.baseLayer = layer; + } + isSessionSupported(mode) { + return mode == 'inline'; + } + isFeatureSupported(featureDescriptor) { + switch(featureDescriptor) { + case 'viewer': return true; + default: return false; + } + } + async requestSession(mode, enabledFeatures) { + if (!this.isSessionSupported(mode)) { + return Promise.reject(); + } + const session = new Session$1(mode, enabledFeatures); + this.sessions.set(session.id, session); + return Promise.resolve(session.id); + } + requestAnimationFrame(callback) { + return window.requestAnimationFrame(callback); + } + cancelAnimationFrame(handle) { + window.cancelAnimationFrame(handle); + } + onFrameStart(sessionId, renderState) { + if (TEST_ENV$1) { + return; + } + const session = this.sessions.get(sessionId); + if (session.baseLayer) { + const canvas = session.baseLayer.context.canvas; + perspective(this.projectionMatrix, renderState.inlineVerticalFieldOfView, + canvas.width/canvas.height, renderState.depthNear, renderState.depthFar); + } + } + onFrameEnd(sessionId) { + } + async endSession(sessionId) { + const session = this.sessions.get(sessionId); + session.ended = true; + } + doesSessionSupportReferenceSpace(sessionId, type) { + const session = this.sessions.get(sessionId); + if (session.ended) { + return false; + } + return session.enabledFeatures.has(type); + } + requestStageBounds() { + return null; + } + async requestFrameOfReferenceTransform(type, options) { + return null; + } + getProjectionMatrix(eye) { + return this.projectionMatrix; + } + getViewport(sessionId, eye, layer, target) { + const session = this.sessions.get(sessionId); + const { width, height } = layer.context.canvas; + target.x = target.y = 0; + target.width = width; + target.height = height; + return true; + } + getBasePoseMatrix() { + return this.identityMatrix; + } + getBaseViewMatrix(eye) { + return this.identityMatrix; + } + getInputSources() { + return []; + } + getInputPose(inputSource, coordinateSystem, poseType) { + return null; + } + onWindowResize() { + } +} + +const getWebVRDevice = async function (global) { + let device = null; + if ('getVRDisplays' in global.navigator) { + try { + const displays = await global.navigator.getVRDisplays(); + if (displays && displays.length) { + device = new WebVRDevice(global, displays[0]); + } + } catch (e) {} + } + return device; +}; +const requestXRDevice = async function (global, config) { + if (config.webvr) { + let xr = await getWebVRDevice(global); + if (xr) { + return xr; + } + } + let mobile = isMobile(global); + if ((mobile && config.cardboard) || + (!mobile && config.allowCardboardOnDesktop)) { + if (!global.VRFrameData) { + global.VRFrameData = function () { + this.rightViewMatrix = new Float32Array(16); + this.leftViewMatrix = new Float32Array(16); + this.rightProjectionMatrix = new Float32Array(16); + this.leftProjectionMatrix = new Float32Array(16); + this.pose = null; + }; + } + return new CardboardXRDevice(global, config.cardboardConfig); + } + return new InlineDevice(global); +}; + +const CONFIG_DEFAULTS = { + global: _global, + webvr: true, + cardboard: true, + cardboardConfig: null, + allowCardboardOnDesktop: false, +}; +const partials = ['navigator', 'HTMLCanvasElement', 'WebGLRenderingContext']; +class WebXRPolyfill { + constructor(config={}) { + this.config = Object.freeze(Object.assign({}, CONFIG_DEFAULTS, config)); + this.global = this.config.global; + this.nativeWebXR = 'xr' in this.global.navigator; + this.injected = false; + if (!this.nativeWebXR) { + this._injectPolyfill(this.global); + } else { + this._injectCompatibilityShims(this.global); + } + } + _injectPolyfill(global) { + if (!partials.every(iface => !!global[iface])) { + throw new Error(`Global must have the following attributes : ${partials}`); + } + for (const className of Object.keys(API)) { + if (global[className] !== undefined) { + console.warn(`${className} already defined on global.`); + } else { + global[className] = API[className]; + } + } + { + const polyfilledCtx = polyfillMakeXRCompatible(global.WebGLRenderingContext); + if (polyfilledCtx) { + polyfillGetContext(global.HTMLCanvasElement); + if (global.OffscreenCanvas) { + polyfillGetContext(global.OffscreenCanvas); + } + if (global.WebGL2RenderingContext){ + polyfillMakeXRCompatible(global.WebGL2RenderingContext); + } + } + } + this.injected = true; + this._patchNavigatorXR(); + } + _patchNavigatorXR() { + let devicePromise = requestXRDevice(this.global, this.config); + this.xr = new API.XR(devicePromise); + Object.defineProperty(this.global.navigator, 'xr', { + value: this.xr, + configurable: true, + }); + } + _injectCompatibilityShims(global) { + if (!partials.every(iface => !!global[iface])) { + throw new Error(`Global must have the following attributes : ${partials}`); + } + if (global.navigator.xr && + 'supportsSession' in global.navigator.xr && + !('isSessionSupported' in global.navigator.xr)) { + let originalSupportsSession = global.navigator.xr.supportsSession; + global.navigator.xr.isSessionSupported = function(mode) { + return originalSupportsSession.call(this, mode).then(() => { + return true; + }).catch(() => { + return false; + }); + }; + global.navigator.xr.supportsSession = function(mode) { + console.warn("navigator.xr.supportsSession() is deprecated. Please " + + "call navigator.xr.isSessionSupported() instead and check the boolean " + + "value returned when the promise resolves."); + return originalSupportsSession.call(this, mode); + }; + } + } +} + +export default WebXRPolyfill; From 67f9cf19918931bc8562e813577ebd58aa99314f Mon Sep 17 00:00:00 2001 From: Blair MacIntyre Date: Wed, 1 Jan 2020 20:06:36 -0500 Subject: [PATCH 4/7] fix for iOS bug in subclassing system classes --- src/api/XRInputSourceEvent.js | 3 +++ src/api/XRInputSourcesChangeEvent.js | 2 ++ src/api/XRReferenceSpaceEvent.js | 2 ++ src/api/XRSessionEvent.js | 3 +++ 4 files changed, 10 insertions(+) diff --git a/src/api/XRInputSourceEvent.js b/src/api/XRInputSourceEvent.js index f934bd9..93f5f01 100644 --- a/src/api/XRInputSourceEvent.js +++ b/src/api/XRInputSourceEvent.js @@ -26,6 +26,9 @@ export default class XRInputSourceEvent extends Event { frame: eventInitDict.frame, inputSource: eventInitDict.inputSource }; + + // safari bug: super() seems to return object of type Event, with Event as prototype + Object.setPrototypeOf(this, XRInputSourceEvent.prototype); } /** diff --git a/src/api/XRInputSourcesChangeEvent.js b/src/api/XRInputSourcesChangeEvent.js index a03a65c..f87a3a4 100644 --- a/src/api/XRInputSourcesChangeEvent.js +++ b/src/api/XRInputSourcesChangeEvent.js @@ -27,6 +27,8 @@ export default class XRInputSourcesChangeEvent extends Event { added: eventInitDict.added, removed: eventInitDict.removed }; + // safari bug: super() seems to return object of type Event, with Event as prototype + Object.setPrototypeOf(this, XRInputSourcesChangeEvent.prototype); } /** diff --git a/src/api/XRReferenceSpaceEvent.js b/src/api/XRReferenceSpaceEvent.js index 3d7398b..49905ed 100644 --- a/src/api/XRReferenceSpaceEvent.js +++ b/src/api/XRReferenceSpaceEvent.js @@ -26,6 +26,8 @@ export default class XRReferenceSpaceEvent extends Event { referenceSpace: eventInitDict.referenceSpace, transform: eventInitDict.transform || null }; + // safari bug: super() seems to return object of type Event, with Event as prototype + Object.setPrototypeOf(this, XRReferenceSpaceEvent.prototype); } /** diff --git a/src/api/XRSessionEvent.js b/src/api/XRSessionEvent.js index c093d8b..8428a81 100644 --- a/src/api/XRSessionEvent.js +++ b/src/api/XRSessionEvent.js @@ -25,6 +25,9 @@ export default class XRSessionEvent extends Event { this[PRIVATE] = { session: eventInitDict.session }; + + // safari bug: super() seems to return object of type Event, with Event as prototype + Object.setPrototypeOf(this, XRSessionEvent.prototype); } /** From c33c84f82f00903ea514291bbc31cea862a91177 Mon Sep 17 00:00:00 2001 From: Blair MacIntyre Date: Wed, 1 Jan 2020 20:09:03 -0500 Subject: [PATCH 5/7] remove code from second PR --- src/api/XRSession.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/XRSession.js b/src/api/XRSession.js index 8b8d3ff..29c6dd6 100644 --- a/src/api/XRSession.js +++ b/src/api/XRSession.js @@ -407,7 +407,7 @@ export default class XRSession extends EventTarget { // If this is an immersive session, trigger the platform to end, which // will call the `onPresentationEnd` handler, wrapping this up. - if (this[PRIVATE].immersive) { + if (this.immersive) { this[PRIVATE].ended = true; this[PRIVATE].device.removeEventListener('@@webvr-polyfill/vr-present-start', this[PRIVATE].onPresentationStart); From 7b4298fc909165b27f10f56436ed206f2fe63951 Mon Sep 17 00:00:00 2001 From: Blair MacIntyre Date: Fri, 27 Dec 2019 16:40:15 -0500 Subject: [PATCH 6/7] small fix to XRSession.end() typo: this.immersive should be this[PRIVATE].immersive fix for iOS bug in subclassing system classes --- src/api/XRInputSourceEvent.js | 3 +++ src/api/XRInputSourcesChangeEvent.js | 2 ++ src/api/XRReferenceSpaceEvent.js | 2 ++ src/api/XRSessionEvent.js | 3 +++ 4 files changed, 10 insertions(+) diff --git a/src/api/XRInputSourceEvent.js b/src/api/XRInputSourceEvent.js index f934bd9..93f5f01 100644 --- a/src/api/XRInputSourceEvent.js +++ b/src/api/XRInputSourceEvent.js @@ -26,6 +26,9 @@ export default class XRInputSourceEvent extends Event { frame: eventInitDict.frame, inputSource: eventInitDict.inputSource }; + + // safari bug: super() seems to return object of type Event, with Event as prototype + Object.setPrototypeOf(this, XRInputSourceEvent.prototype); } /** diff --git a/src/api/XRInputSourcesChangeEvent.js b/src/api/XRInputSourcesChangeEvent.js index a03a65c..f87a3a4 100644 --- a/src/api/XRInputSourcesChangeEvent.js +++ b/src/api/XRInputSourcesChangeEvent.js @@ -27,6 +27,8 @@ export default class XRInputSourcesChangeEvent extends Event { added: eventInitDict.added, removed: eventInitDict.removed }; + // safari bug: super() seems to return object of type Event, with Event as prototype + Object.setPrototypeOf(this, XRInputSourcesChangeEvent.prototype); } /** diff --git a/src/api/XRReferenceSpaceEvent.js b/src/api/XRReferenceSpaceEvent.js index 3d7398b..49905ed 100644 --- a/src/api/XRReferenceSpaceEvent.js +++ b/src/api/XRReferenceSpaceEvent.js @@ -26,6 +26,8 @@ export default class XRReferenceSpaceEvent extends Event { referenceSpace: eventInitDict.referenceSpace, transform: eventInitDict.transform || null }; + // safari bug: super() seems to return object of type Event, with Event as prototype + Object.setPrototypeOf(this, XRReferenceSpaceEvent.prototype); } /** diff --git a/src/api/XRSessionEvent.js b/src/api/XRSessionEvent.js index c093d8b..8428a81 100644 --- a/src/api/XRSessionEvent.js +++ b/src/api/XRSessionEvent.js @@ -25,6 +25,9 @@ export default class XRSessionEvent extends Event { this[PRIVATE] = { session: eventInitDict.session }; + + // safari bug: super() seems to return object of type Event, with Event as prototype + Object.setPrototypeOf(this, XRSessionEvent.prototype); } /** From 55711cc884819f3ec72df99b8c7877a25421be9d Mon Sep 17 00:00:00 2001 From: Blair MacIntyre Date: Fri, 27 Dec 2019 16:40:15 -0500 Subject: [PATCH 7/7] small fix to XRSession.end() typo: this.immersive should be this[PRIVATE].immersive fix for iOS bug in subclassing system classes --- src/api/XRInputSourceEvent.js | 3 +++ src/api/XRInputSourcesChangeEvent.js | 2 ++ src/api/XRReferenceSpaceEvent.js | 2 ++ src/api/XRSessionEvent.js | 3 +++ 4 files changed, 10 insertions(+) diff --git a/src/api/XRInputSourceEvent.js b/src/api/XRInputSourceEvent.js index f934bd9..93f5f01 100644 --- a/src/api/XRInputSourceEvent.js +++ b/src/api/XRInputSourceEvent.js @@ -26,6 +26,9 @@ export default class XRInputSourceEvent extends Event { frame: eventInitDict.frame, inputSource: eventInitDict.inputSource }; + + // safari bug: super() seems to return object of type Event, with Event as prototype + Object.setPrototypeOf(this, XRInputSourceEvent.prototype); } /** diff --git a/src/api/XRInputSourcesChangeEvent.js b/src/api/XRInputSourcesChangeEvent.js index a03a65c..f87a3a4 100644 --- a/src/api/XRInputSourcesChangeEvent.js +++ b/src/api/XRInputSourcesChangeEvent.js @@ -27,6 +27,8 @@ export default class XRInputSourcesChangeEvent extends Event { added: eventInitDict.added, removed: eventInitDict.removed }; + // safari bug: super() seems to return object of type Event, with Event as prototype + Object.setPrototypeOf(this, XRInputSourcesChangeEvent.prototype); } /** diff --git a/src/api/XRReferenceSpaceEvent.js b/src/api/XRReferenceSpaceEvent.js index 3d7398b..49905ed 100644 --- a/src/api/XRReferenceSpaceEvent.js +++ b/src/api/XRReferenceSpaceEvent.js @@ -26,6 +26,8 @@ export default class XRReferenceSpaceEvent extends Event { referenceSpace: eventInitDict.referenceSpace, transform: eventInitDict.transform || null }; + // safari bug: super() seems to return object of type Event, with Event as prototype + Object.setPrototypeOf(this, XRReferenceSpaceEvent.prototype); } /** diff --git a/src/api/XRSessionEvent.js b/src/api/XRSessionEvent.js index c093d8b..8428a81 100644 --- a/src/api/XRSessionEvent.js +++ b/src/api/XRSessionEvent.js @@ -25,6 +25,9 @@ export default class XRSessionEvent extends Event { this[PRIVATE] = { session: eventInitDict.session }; + + // safari bug: super() seems to return object of type Event, with Event as prototype + Object.setPrototypeOf(this, XRSessionEvent.prototype); } /**