@onirix/ar-engine-sdk 1.6.2 → 1.6.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,7 @@
2
2
 
3
3
  const TrackingMode={Image:1,QRCode:2,Surface:3,Spatial:4},SurfaceMode={WebXR:1,SLAM:2,Gyroscope:3},Events={OnDetected:1,OnPose:2,OnLost:3,OnResize:4,OnTouch:5,OnHitTestResult:6,OnKeyFrame:7,OnStatusChange:8,OnSessionEnd:9,OnFrame:10},DefaultConfig={useVocabulary:!1,forceCompatWorldTracking:!1,forceRotationOnlyTracking:!1,debug:!1,cameraAccess:!1};
4
4
 
5
- class InternalError extends Error{constructor(r){super(r),this.name="INTERNAL_ERROR";}}class LicenseError extends Error{constructor(r){super(r),this.name="LICENSE_ERROR";}}class CameraError extends Error{constructor(r){super(r),this.name="CAMERA_ERROR";}}class SensorsError extends Error{constructor(r){super(r),this.name="SENSORS_ERROR";}}
5
+ class InternalError extends Error{constructor(r){super(r),this.name="INTERNAL_ERROR";}}class LicenseError extends Error{constructor(r){super(r),this.name="LICENSE_ERROR";}}class CameraError extends Error{constructor(r){super(r),this.name="CAMERA_ERROR";}}class SensorsError extends Error{constructor(r){super(r),this.name="SENSORS_ERROR";}}class ReconstructionPendingError extends Error{constructor(r){super(r),this.name="RECONSTRUCTION_PENDING_ERROR";}}
6
6
 
7
7
  const BROWSER_ALIASES_MAP={"Amazon Silk":"amazon_silk","Android Browser":"android",Bada:"bada",BlackBerry:"blackberry",Chrome:"chrome",Chromium:"chromium",Electron:"electron",Epiphany:"epiphany",Firefox:"firefox",Focus:"focus",Generic:"generic","Google Search":"google_search",Googlebot:"googlebot","Internet Explorer":"ie","K-Meleon":"k_meleon",Maxthon:"maxthon","Microsoft Edge":"edge","MZ Browser":"mz","NAVER Whale Browser":"naver",Opera:"opera","Opera Coast":"opera_coast",PhantomJS:"phantomjs",Puffin:"puffin",QupZilla:"qupzilla",QQ:"qq",QQLite:"qqlite",Safari:"safari",Sailfish:"sailfish","Samsung Internet for Android":"samsung_internet",SeaMonkey:"seamonkey",Sleipnir:"sleipnir",Swing:"swing",Tizen:"tizen","UC Browser":"uc",Vivaldi:"vivaldi","WebOS Browser":"webos",WeChat:"wechat","Yandex Browser":"yandex",Roku:"roku"};const BROWSER_MAP={amazon_silk:"Amazon Silk",android:"Android Browser",bada:"Bada",blackberry:"BlackBerry",chrome:"Chrome",chromium:"Chromium",electron:"Electron",epiphany:"Epiphany",firefox:"Firefox",focus:"Focus",generic:"Generic",googlebot:"Googlebot",google_search:"Google Search",ie:"Internet Explorer",k_meleon:"K-Meleon",maxthon:"Maxthon",edge:"Microsoft Edge",mz:"MZ Browser",naver:"NAVER Whale Browser",opera:"Opera",opera_coast:"Opera Coast",phantomjs:"PhantomJS",puffin:"Puffin",qupzilla:"QupZilla",qq:"QQ Browser",qqlite:"QQ Browser Lite",safari:"Safari",sailfish:"Sailfish",samsung_internet:"Samsung Internet for Android",seamonkey:"SeaMonkey",sleipnir:"Sleipnir",swing:"Swing",tizen:"Tizen",uc:"UC Browser",vivaldi:"Vivaldi",webos:"WebOS Browser",wechat:"WeChat",yandex:"Yandex Browser"};const PLATFORMS_MAP={tablet:"tablet",mobile:"mobile",desktop:"desktop",tv:"tv"};const OS_MAP={WindowsPhone:"Windows Phone",Windows:"Windows",MacOS:"macOS",iOS:"iOS",Android:"Android",WebOS:"WebOS",BlackBerry:"BlackBerry",Bada:"Bada",Tizen:"Tizen",Linux:"Linux",ChromeOS:"Chrome OS",PlayStation4:"PlayStation 4",Roku:"Roku"};const ENGINE_MAP={EdgeHTML:"EdgeHTML",Blink:"Blink",Trident:"Trident",Presto:"Presto",Gecko:"Gecko",WebKit:"WebKit"};
8
8
 
@@ -38,7 +38,7 @@ class Quaternion{constructor(t=0,s=0,i=0,h=1){this.x=t,this.y=s,this.z=i,this.w=
38
38
 
39
39
  const mat4RotationZ90CCW=(new Matrix4).set(0,1,0,0,-1,0,0,0,0,0,1,0,0,0,0,1),mat4RotationZ90CW=(new Matrix4).set(0,-1,0,0,1,0,0,0,0,0,1,0,0,0,0,1),mat4RotationX90CW=(new Matrix4).set(1,0,0,0,0,0,1,0,0,-1,0,0,0,0,0,1),mat3RotationX90CCW=(new Matrix3).set(1,0,0,0,0,1,0,-1,0),mat3RotationZ90CW=(new Matrix3).set(0,-1,0,1,0,0,0,0,1);
40
40
 
41
- class NativeManager{constructor(t,i,e,a){this.uiManager=t,this.deviceManager=i,this.workerManager=e,this.indexedDBManager=a;}async init(t,i){try{let e;try{e=await getFileFromIndexedDB("SDK_1.6.2");}catch(t){let i=await fetch(new URL("./onirix_native_sdk.js",import.meta.url).href);e=await i.text(),await this.indexedDBManager.saveFileToIndexedDB("SDK_1.6.2",e);}let a=URL.createObjectURL(new Blob([e],{type:"text/javascript"}));const{default:r}=await import(/* webpackIgnore: true, webpackMode: "lazy" */a);let s,n,o;if(this.useVocabulary=i.useVocabulary,this.host=i.host??"https://studio.onirix.com",this.useVocabulary&&(s=await this.indexedDBManager.getFromCacheOrFetch("orb.fbow","https://sdk.onirix.com/common/orb.fbow")),i.mode===TrackingMode.Spatial){if(n=await fetch(`${this.host}/api/projects/self/targets/${i.sceneOid}/osf?token=${t}`),!n.ok)throw new Error(`Could not get Onirix Spatial File. Server responded with ${n.status}`);const e=await n.arrayBuffer();o=new Uint8Array(e),await this.workerManager.createWorkers();}this.nativeSDK=await r({preRun:e=>{i.mode==TrackingMode.Spatial?e.FS_createDataFile("/","scene.osf",o,!0,!0,!0):i.mode===TrackingMode.Image?(this.useVocabulary&&e.FS_createDataFile("/","orb.fbow",s,!0,!0,!0),e.FS_createPreloadedFile("/","classifier.otf",`${this.host}/api/projects/self/targets/otf?token=${t}`,!0,!1)):i.mode===TrackingMode.Surface&&this.useVocabulary&&e.FS_createDataFile("/","orb.fbow",s,!0,!0,!0);}}),this.buffer=this.nativeSDK._malloc(1228800),this.imageBuffer=this.nativeSDK._malloc(1228800),this.imuAccData=this.nativeSDK._malloc(32),this.imuRotData=this.nativeSDK._malloc(72),this.cameraParamsStruct=this.nativeSDK._malloc(40),this.frameLayoutStruct=this.nativeSDK._malloc(28),this.nativeSDK.HEAPU32[this.cameraParamsStruct/4+0]=640,this.nativeSDK.HEAPU32[this.cameraParamsStruct/4+1]=480,this.nativeSDK.HEAPF64[this.cameraParamsStruct/8+1]=468,this.nativeSDK.HEAPF64[this.cameraParamsStruct/8+2]=468,this.nativeSDK.HEAPF64[this.cameraParamsStruct/8+3]=320,this.nativeSDK.HEAPF64[this.cameraParamsStruct/8+4]=240,i.debug&&this.nativeSDK._OX_SetLogCallback(this.nativeSDK.addFunction((t=>{console.log(this.nativeSDK.UTF8ToString(t));}),"vi"));}catch(t){throw new InternalError(t)}await this.checkLicense(t);}async checkLicense(t){try{const i=this.getStringBuffer(this.host),e=this.getStringBuffer(t),a=this.getStringBuffer(window.location.hostname),r=this.getStringBuffer(this.deviceManager.platform),s=this.getStringBuffer(this.deviceManager.device),n=await new Promise(((t,n)=>{this.nativeSDK._OX_SetLicense([i],[e],[a],[r],[s],this.nativeSDK.addFunction((i=>t(i)),"vi"));}));if(this.releaseStringBuffer(i),this.releaseStringBuffer(e),this.releaseStringBuffer(a),this.releaseStringBuffer(r),this.releaseStringBuffer(s),!n)throw new LicenseError("Invalid license")}catch(t){throw new LicenseError(t)}}startImageTracking(t,i,e){if(this.onDetected=t,this.onPose=i,this.onLost=e,this.useVocabulary){const t=this.getStringBuffer("orb.fbow");this.nativeSDK._OX_Initialize(this.cameraParamsStruct,[t]),this.releaseStringBuffer(t);}else this.nativeSDK._OX_Initialize(this.cameraParamsStruct,"");let a=this.getStringBuffer("classifier.otf");this.nativeSDK._OX_LoadImageClassifier([a]),this.releaseStringBuffer(a),this.nativeSDK._OX_StartImageDetection(2,this.nativeSDK.addFunction((t=>this.onDetected(this.nativeSDK.UTF8ToString(t))),"vi"),this.nativeSDK.addFunction((t=>{const i=this.nativeSDK.HEAPF64.subarray(t/8,t/8+16);let e=(new Matrix4).fromArray(i);e.multiply(mat4RotationX90CW),e.invert(),this.uiManager.isPortrait()?(e.multiply(mat4RotationZ90CCW),this.onPose(e.toArray())):this.onPose(e.toArray());}),"vi"),this.nativeSDK.addFunction((t=>this.onLost(this.nativeSDK.UTF8ToString(t))),"vi"));}startQRCodeTracking(t,i,e){this.onDetected=t,this.onPose=i,this.onLost=e,this.nativeSDK._OX_Initialize(this.cameraParamsStruct,""),this.nativeSDK._OX_StartQRCodeDetection(2,this.nativeSDK.addFunction((t=>this.onDetected(this.nativeSDK.UTF8ToString(t))),"vi"),this.nativeSDK.addFunction((t=>{const i=this.nativeSDK.HEAPF64.subarray(t/8,t/8+16);let e=(new Matrix4).fromArray(i);e.multiply(mat4RotationX90CW),e.invert(),this.uiManager.isPortrait()?(e.multiply(mat4RotationZ90CCW),this.onPose(e.toArray())):this.onPose(e.toArray());}),"vi"),this.nativeSDK.addFunction((t=>this.onLost(this.nativeSDK.UTF8ToString(t))),"vi"));}startSLAM(t,i,e){if(this.onPose=t,this.onKeyFrame=i,this.onStatusChange=e,this.useVocabulary){const t=this.getStringBuffer("orb.fbow");this.nativeSDK._OX_Initialize(this.cameraParamsStruct,[t]),this.releaseStringBuffer(t);}else this.nativeSDK._OX_Initialize(this.cameraParamsStruct,"");this.nativeSDK._OX_StartSLAM(this.nativeSDK.addFunction((t=>{const i=this.nativeSDK.HEAPF64.subarray(t/8,t/8+16);let e=(new Matrix4).fromArray(i);e.invert(),this.uiManager.isPortrait()?(e.multiply(mat4RotationZ90CCW),this.onPose(e.toArray())):this.onPose(e.toArray());}),"vi"),null!=this.onKeyFrame?this.nativeSDK.addFunction((()=>this.onKeyFrame()),"v"):null,this.nativeSDK.addFunction(((t,i)=>{this.onStatusChange([this.nativeSDK.UTF8ToString(t),this.nativeSDK.UTF8ToString(i)]);}),"vii"));}xrRelocation(t){if(this.lastXrPose){let i=(new Matrix4).fromArray(this.lastXrPose),e=(new Matrix4).fromArray(t.elements);this.xrTransform=e.multiply(i.invert());}}slamRelocation(t){if(this.lastSlamPose){let i=(new Matrix4).fromArray(this.lastSlamPose),e=(new Matrix4).fromArray(t.elements);this.slamTransform=e.multiply(i.invert());}}startSpatialTracking(t,i,e){this.onDetected=t,e||(this.onPose=i),this.nativeSDK._OX_Initialize(this.cameraParamsStruct,""),this.nativeSDK._OX_StartSpatialTracking(this.nativeSDK.addFunction((t=>{e||(this.spatialLocated=!0),this.onDetected("");}),"vi"),this.nativeSDK.addFunction((t=>{const i=this.nativeSDK.HEAPF64.subarray(t/8,t/8+16);let a=(new Matrix4).fromArray(i);a.invert(),this.uiManager.isPortrait()&&a.multiply(e?mat4RotationZ90CW:mat4RotationZ90CCW),e?(this.xrRelocation(a),this.onDetected("")):this.onPose(a.toArray());}),"vi"),!e);let a=this.getStringBuffer("scene.osf");this.nativeSDK._OX_LoadOSF(a),this.releaseStringBuffer(a);}processFrame(t,i=null,e=480,a=640,r=0,s=0){let n=i||this.buffer;this.nativeSDK.HEAPU8.set(t,n),this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+0]=a,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+1]=e,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+2]=4*a,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+3]=!1,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+4]=5,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+5]=s,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+6]=r,this.nativeSDK._OX_ProcessFrame(n,this.frameLayoutStruct);}loadExtractionData(t,i=-1){return this.siftBuffer&&this.netvladBuffer?(this.nativeSDK.HEAPF32.set(t.extraction,this.siftBuffer/4),this.nativeSDK.HEAPF32.set(t.descriptor,this.netvladBuffer/4),this.nativeSDK._OX_LoadExtractionData(this.siftBuffer,this.netvladBuffer,i)):0}getCandidateData(t){let i=this.nativeSDK._OX_GetCandidateData(t),e=[];for(let t=0;t<55e4;t++)e.push(this.nativeSDK.HEAPF32[i/4+t]);return new Float32Array(e)}loadMatch(t){this.matchBuffer&&(this.nativeSDK.HEAPF32.set(t,this.matchBuffer/4),this.nativeSDK._OX_LoadMatch(this.matchBuffer));}spatialLocate(){this.nativeSDK._OX_SpatialLocate();}loadKeyframePose(t){this.nativeSDK._OX_LoadKfPose(t);}numSLAMKeyframes(){return this.nativeSDK._OX_GetSLAMNumKfs()}getSLAMKeyframe(t){let i=this.nativeSDK._OX_GetSLAMKf(t),e=[];for(let t=0;t<1228800;t++)e.push(this.nativeSDK.HEAPU8[i+t]);return new Uint8Array(e)}stopImageTracking(){this.nativeSDK._OX_StopImageDetection();}stopQRCodeTracking(){this.nativeSDK._OX_StopQRCodeDetection();}stopSLAM(){this.nativeSDK._OX_StopSLAM();}stopSLAM(){this.nativeSDK._OX_StopSLAM();}addImage(t,i){this.nativeSDK.HEAPU8.set(i,this.imageBuffer),this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+0]=640,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+1]=480,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+2]=2560,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+3]=!1,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+4]=5,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+5]=0,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+6]=0;const e=this.getStringBuffer(t);this.nativeSDK._OX_AddImage([e],this.imageBuffer,this.frameLayoutStruct),this.releaseStringBuffer(e);}destroy(){this.nativeSDK._OX_Destroy();}extractionType(){return this.nativeSDK._OX_ExtractionType()}getStringBuffer(t){const i=this.nativeSDK.lengthBytesUTF8(t)+1;let e=this.nativeSDK._malloc(i);return this.nativeSDK.stringToUTF8(t,e,i),e}releaseStringBuffer(t){this.nativeSDK._free(t);}getSLAMMap(){const t=this.nativeSDK.UTF8ToString(this.nativeSDK._OX_GetSLAMMap());let i;try{i=JSON.parse(t);}catch(i){console.error(`Could not parse ${t}`);}return i}getSLAMTrackingPoints(){const t=this.nativeSDK.UTF8ToString(this.nativeSDK._OX_GetSLAMTrackingPoints());let i;try{i=JSON.parse(t);}catch(i){console.error(`Could not parse ${t}`);}return i}raycast(t,i,e,a,r,s){const n=this.nativeSDK.UTF8ToString(this.nativeSDK._OX_Raycast(t,i,e,a,r,s));let o;try{o=JSON.parse(n);}catch(t){console.error(`Could not parse ${n}`);}return o}}
41
+ class NativeManager{constructor(t,i,e,a){this.uiManager=t,this.deviceManager=i,this.workerManager=e,this.indexedDBManager=a;}async init(t,i){try{let e;try{e=await getFileFromIndexedDB("SDK_1.6.3");}catch(t){let i=await fetch(new URL("./onirix_native_sdk.js",import.meta.url).href);e=await i.text(),await this.indexedDBManager.saveFileToIndexedDB("SDK_1.6.3",e);}let a=URL.createObjectURL(new Blob([e],{type:"text/javascript"}));const{default:r}=await import(/* webpackIgnore: true, webpackMode: "lazy" */a);let s,n,o;if(this.useVocabulary=i.useVocabulary,this.host=i.host??"https://studio.onirix.com",this.useVocabulary&&(s=await this.indexedDBManager.getFromCacheOrFetch("orb.fbow","https://sdk.onirix.com/common/orb.fbow")),i.mode===TrackingMode.Spatial){if(n=await fetch(`${this.host}/api/projects/self/targets/${i.sceneOid}/osf?token=${t}`),!n.ok)throw new ReconstructionPendingError(`Could not get Onirix Spatial File. Server responded with ${n.status}`);const e=await n.arrayBuffer();o=new Uint8Array(e),await this.workerManager.createWorkers();}this.nativeSDK=await r({preRun:e=>{i.mode==TrackingMode.Spatial?e.FS_createDataFile("/","scene.osf",o,!0,!0,!0):i.mode===TrackingMode.Image?(this.useVocabulary&&e.FS_createDataFile("/","orb.fbow",s,!0,!0,!0),e.FS_createPreloadedFile("/","classifier.otf",`${this.host}/api/projects/self/targets/otf?token=${t}`,!0,!1)):i.mode===TrackingMode.Surface&&this.useVocabulary&&e.FS_createDataFile("/","orb.fbow",s,!0,!0,!0);}}),this.buffer=this.nativeSDK._malloc(1228800),this.imageBuffer=this.nativeSDK._malloc(1228800),this.imuAccData=this.nativeSDK._malloc(32),this.imuRotData=this.nativeSDK._malloc(72),this.cameraParamsStruct=this.nativeSDK._malloc(40),this.frameLayoutStruct=this.nativeSDK._malloc(28),this.nativeSDK.HEAPU32[this.cameraParamsStruct/4+0]=640,this.nativeSDK.HEAPU32[this.cameraParamsStruct/4+1]=480,this.nativeSDK.HEAPF64[this.cameraParamsStruct/8+1]=468,this.nativeSDK.HEAPF64[this.cameraParamsStruct/8+2]=468,this.nativeSDK.HEAPF64[this.cameraParamsStruct/8+3]=320,this.nativeSDK.HEAPF64[this.cameraParamsStruct/8+4]=240,i.debug&&this.nativeSDK._OX_SetLogCallback(this.nativeSDK.addFunction((t=>{console.log(this.nativeSDK.UTF8ToString(t));}),"vi"));}catch(t){throw t instanceof ReconstructionPendingError?t:new InternalError(t)}await this.checkLicense(t);}async checkLicense(t){try{const i=this.getStringBuffer(this.host),e=this.getStringBuffer(t),a=this.getStringBuffer(window.location.hostname),r=this.getStringBuffer(this.deviceManager.platform),s=this.getStringBuffer(this.deviceManager.device),n=await new Promise(((t,n)=>{this.nativeSDK._OX_SetLicense([i],[e],[a],[r],[s],this.nativeSDK.addFunction((i=>t(i)),"vi"));}));if(this.releaseStringBuffer(i),this.releaseStringBuffer(e),this.releaseStringBuffer(a),this.releaseStringBuffer(r),this.releaseStringBuffer(s),!n)throw new LicenseError("Invalid license")}catch(t){throw new LicenseError(t)}}startImageTracking(t,i,e){if(this.onDetected=t,this.onPose=i,this.onLost=e,this.useVocabulary){const t=this.getStringBuffer("orb.fbow");this.nativeSDK._OX_Initialize(this.cameraParamsStruct,[t]),this.releaseStringBuffer(t);}else this.nativeSDK._OX_Initialize(this.cameraParamsStruct,"");let a=this.getStringBuffer("classifier.otf");this.nativeSDK._OX_LoadImageClassifier([a]),this.releaseStringBuffer(a),this.nativeSDK._OX_StartImageDetection(2,this.nativeSDK.addFunction((t=>this.onDetected(this.nativeSDK.UTF8ToString(t))),"vi"),this.nativeSDK.addFunction((t=>{const i=this.nativeSDK.HEAPF64.subarray(t/8,t/8+16);let e=(new Matrix4).fromArray(i);e.multiply(mat4RotationX90CW),e.invert(),this.uiManager.isPortrait()?(e.multiply(mat4RotationZ90CCW),this.onPose(e.toArray())):this.onPose(e.toArray());}),"vi"),this.nativeSDK.addFunction((t=>this.onLost(this.nativeSDK.UTF8ToString(t))),"vi"));}startQRCodeTracking(t,i,e){this.onDetected=t,this.onPose=i,this.onLost=e,this.nativeSDK._OX_Initialize(this.cameraParamsStruct,""),this.nativeSDK._OX_StartQRCodeDetection(2,this.nativeSDK.addFunction((t=>this.onDetected(this.nativeSDK.UTF8ToString(t))),"vi"),this.nativeSDK.addFunction((t=>{const i=this.nativeSDK.HEAPF64.subarray(t/8,t/8+16);let e=(new Matrix4).fromArray(i);e.multiply(mat4RotationX90CW),e.invert(),this.uiManager.isPortrait()?(e.multiply(mat4RotationZ90CCW),this.onPose(e.toArray())):this.onPose(e.toArray());}),"vi"),this.nativeSDK.addFunction((t=>this.onLost(this.nativeSDK.UTF8ToString(t))),"vi"));}startSLAM(t,i,e){if(this.onPose=t,this.onKeyFrame=i,this.onStatusChange=e,this.useVocabulary){const t=this.getStringBuffer("orb.fbow");this.nativeSDK._OX_Initialize(this.cameraParamsStruct,[t]),this.releaseStringBuffer(t);}else this.nativeSDK._OX_Initialize(this.cameraParamsStruct,"");this.nativeSDK._OX_StartSLAM(this.nativeSDK.addFunction((t=>{const i=this.nativeSDK.HEAPF64.subarray(t/8,t/8+16);let e=(new Matrix4).fromArray(i);e.invert(),this.uiManager.isPortrait()?(e.multiply(mat4RotationZ90CCW),this.onPose(e.toArray())):this.onPose(e.toArray());}),"vi"),null!=this.onKeyFrame?this.nativeSDK.addFunction((()=>this.onKeyFrame()),"v"):null,this.nativeSDK.addFunction(((t,i)=>{this.onStatusChange([this.nativeSDK.UTF8ToString(t),this.nativeSDK.UTF8ToString(i)]);}),"vii"));}xrRelocation(t){if(this.lastXrPose){let i=(new Matrix4).fromArray(this.lastXrPose),e=(new Matrix4).fromArray(t.elements);this.xrTransform=e.multiply(i.invert());}}slamRelocation(t){if(this.lastSlamPose){let i=(new Matrix4).fromArray(this.lastSlamPose),e=(new Matrix4).fromArray(t.elements);this.slamTransform=e.multiply(i.invert());}}startSpatialTracking(t,i,e){this.onDetected=t,e||(this.onPose=i),this.nativeSDK._OX_Initialize(this.cameraParamsStruct,""),this.nativeSDK._OX_StartSpatialTracking(this.nativeSDK.addFunction((t=>{e||(this.spatialLocated=!0),this.onDetected("");}),"vi"),this.nativeSDK.addFunction((t=>{const i=this.nativeSDK.HEAPF64.subarray(t/8,t/8+16);let a=(new Matrix4).fromArray(i);a.invert(),this.uiManager.isPortrait()&&a.multiply(e?mat4RotationZ90CW:mat4RotationZ90CCW),e?(this.xrRelocation(a),this.onDetected("")):this.onPose(a.toArray());}),"vi"),!e);let a=this.getStringBuffer("scene.osf");this.nativeSDK._OX_LoadOSF(a),this.releaseStringBuffer(a);}processFrame(t,i=null,e=480,a=640,r=0,s=0){let n=i||this.buffer;this.nativeSDK.HEAPU8.set(t,n),this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+0]=a,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+1]=e,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+2]=4*a,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+3]=!1,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+4]=5,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+5]=s,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+6]=r,this.nativeSDK._OX_ProcessFrame(n,this.frameLayoutStruct);}loadExtractionData(t,i=-1){return this.siftBuffer&&this.netvladBuffer?(this.nativeSDK.HEAPF32.set(t.extraction,this.siftBuffer/4),this.nativeSDK.HEAPF32.set(t.descriptor,this.netvladBuffer/4),this.nativeSDK._OX_LoadExtractionData(this.siftBuffer,this.netvladBuffer,i)):0}getCandidateData(t){let i=this.nativeSDK._OX_GetCandidateData(t),e=[];for(let t=0;t<55e4;t++)e.push(this.nativeSDK.HEAPF32[i/4+t]);return new Float32Array(e)}loadMatch(t){this.matchBuffer&&(this.nativeSDK.HEAPF32.set(t,this.matchBuffer/4),this.nativeSDK._OX_LoadMatch(this.matchBuffer));}spatialLocate(){this.nativeSDK._OX_SpatialLocate();}loadKeyframePose(t){this.nativeSDK._OX_LoadKfPose(t);}numSLAMKeyframes(){return this.nativeSDK._OX_GetSLAMNumKfs()}getSLAMKeyframe(t){let i=this.nativeSDK._OX_GetSLAMKf(t),e=[];for(let t=0;t<1228800;t++)e.push(this.nativeSDK.HEAPU8[i+t]);return new Uint8Array(e)}stopImageTracking(){this.nativeSDK._OX_StopImageDetection();}stopQRCodeTracking(){this.nativeSDK._OX_StopQRCodeDetection();}stopSLAM(){this.nativeSDK._OX_StopSLAM();}stopSLAM(){this.nativeSDK._OX_StopSLAM();}addImage(t,i){this.nativeSDK.HEAPU8.set(i,this.imageBuffer),this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+0]=640,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+1]=480,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+2]=2560,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+3]=!1,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+4]=5,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+5]=0,this.nativeSDK.HEAPU32[this.frameLayoutStruct/4+6]=0;const e=this.getStringBuffer(t);this.nativeSDK._OX_AddImage([e],this.imageBuffer,this.frameLayoutStruct),this.releaseStringBuffer(e);}destroy(){this.nativeSDK._OX_Destroy();}extractionType(){return this.nativeSDK._OX_ExtractionType()}getStringBuffer(t){const i=this.nativeSDK.lengthBytesUTF8(t)+1;let e=this.nativeSDK._malloc(i);return this.nativeSDK.stringToUTF8(t,e,i),e}releaseStringBuffer(t){this.nativeSDK._free(t);}getSLAMMap(){const t=this.nativeSDK.UTF8ToString(this.nativeSDK._OX_GetSLAMMap());let i;try{i=JSON.parse(t);}catch(i){console.error(`Could not parse ${t}`);}return i}getSLAMTrackingPoints(){const t=this.nativeSDK.UTF8ToString(this.nativeSDK._OX_GetSLAMTrackingPoints());let i;try{i=JSON.parse(t);}catch(i){console.error(`Could not parse ${t}`);}return i}raycast(t,i,e,a,r,s){const n=this.nativeSDK.UTF8ToString(this.nativeSDK._OX_Raycast(t,i,e,a,r,s));let o;try{o=JSON.parse(n);}catch(t){console.error(`Could not parse ${n}`);}return o}}
42
42
 
43
43
  class UIManager{constructor(){this.onFocus=this.onFocus.bind(this);}createRenderCanvas(){this.renderCanvas=document.createElement("canvas"),this.renderCanvas.id="renderer",this.renderCanvas.style.position="absolute",document.body.prepend(this.renderCanvas),this.addTouchListeners();}setRenderCanvas(e){this.renderCanvas=e,this.addTouchListeners();}addTouchListeners(){this.renderCanvas.addEventListener("click",(e=>{this.onCanvasTouch(e);})),this.renderCanvas.addEventListener("touchstart",(e=>{this.onCanvasTouchStart(e);})),this.renderCanvas.addEventListener("touchmove",(e=>{this.onCanvasTouchMove(e);})),this.renderCanvas.addEventListener("touchend",(e=>{this.onCanvasTouchEnd(e);}));}removeRenderCanvas(){this.renderCanvas&&(this.renderCanvas.remove(),this.renderCanvas=null);}createVideoElement(e){let t=document.createElement("video");t.setAttribute("playsinline","true"),t.setAttribute("autoplay","true"),t.setAttribute("muted",""),this.videoCanvas=document.createElement("canvas"),this.videoCanvas.width=640,this.videoCanvas.height=480,this.videoContext=this.videoCanvas.getContext("2d"),t.srcObject=e,document.body.appendChild(t),this.videoElement=t;const i=this.videoElement.srcObject.getVideoTracks()[0].getSettings();this.videoSizeHorizontal=[Math.max(i.width,i.height),Math.min(i.width,i.height)],this.videoSizeVertical=[Math.min(i.width,i.height),Math.max(i.width,i.height)],window.addEventListener("focus",this.onFocus);}onFocus(){this.videoElement.play();}removeVideoElement(){this.videoElement&&(window.removeEventListener("focus",this.onFocus),this.videoElement.remove(),this.videoElement=null);}fitVideoToScreen(){this.videoSize=window.innerWidth>window.innerHeight?this.videoSizeHorizontal:this.videoSizeVertical;let e=[],t=[];this.videoSize[0]/this.videoSize[1]>window.innerWidth/window.innerHeight?(t=[Math.floor(this.videoSize[0]*(window.innerHeight/this.videoSize[1])),window.innerHeight],e=[-(t[0]-window.innerWidth)/2,0]):(t=[window.innerWidth,Math.floor(this.videoSize[1]*(window.innerWidth/this.videoSize[0]))],e=[0,-(t[1]-window.innerHeight)/2]),document.body.style.setProperty("overflow","hidden"),this.videoElement.width=t[0],this.videoElement.height=t[1],this.videoElement.style.setProperty("position","absolute"),this.videoElement.style.setProperty("z-index","-1"),this.videoElement.style.setProperty("width",`${t[0]}px`),this.videoElement.style.setProperty("height",`${t[1]}px`),this.videoElement.style.setProperty("left",`${e[0]}px`),this.videoElement.style.setProperty("top",`${e[1]}px`),this.videoElement.style.setProperty("touch-action","none"),this.renderCanvas.width=t[0],this.renderCanvas.height=t[1],this.renderCanvas.style.setProperty("position","absolute","important"),this.renderCanvas.style.setProperty("width",`${t[0]}px`,"important"),this.renderCanvas.style.setProperty("height",`${t[1]}px`,"important"),this.renderCanvas.style.setProperty("left",`${e[0]}px`,"important"),this.renderCanvas.style.setProperty("top",`${e[1]}px`,"important"),this.renderCanvas.style.setProperty("touch-action","none","important");}async displayPermissionsDialog(e){return new Promise(((t,i)=>{let o,s,n,r;o=document.createElement("div"),o.id="ox-permissions-dialog",o.style.setProperty("position","fixed"),o.style.setProperty("z-index","999999"),o.style.setProperty("max-width","360px"),o.style.setProperty("width","calc(100% - 140px"),o.style.setProperty("left","50vw"),o.style.setProperty("top","50vh"),o.style.setProperty("transform","translate(-50%, -50%)"),o.style.setProperty("background-color","#FFFFFF"),o.style.setProperty("border-radius","10px"),o.style.setProperty("font-family","'Open Sans', Arial, sans-serif"),o.style.setProperty("text-align","center"),o.style.setProperty("padding","30px"),document.body.appendChild(o),s=document.createElement("h1"),s.id="ox-permissions-dialog-title",s.innerText="Access to motion sensors required",s.style.setProperty("font-size","20px"),o.appendChild(s),n=document.createElement("span"),n.id="ox-permissions-dialog-message",n.innerText="This augmented reality experience requires access to your phone motion sensors. The browser may ask you for permissions.",n.style.setProperty("display","block"),n.style.setProperty("padding","10px 0"),o.appendChild(n),r=document.createElement("button"),r.id="ox-permissions-dialog-ok-button",r.innerText="Okay!",r.style.setProperty("display","block"),r.style.setProperty("margin","auto"),r.style.setProperty("background","#000000"),r.style.setProperty("color","#FFFFFF"),r.style.setProperty("border","none"),r.style.setProperty("border-radius","12px"),r.style.setProperty("padding","20px 0"),r.style.setProperty("width","100%"),r.style.setProperty("font-size","18px"),r.style.setProperty("font-weight","bold"),r.style.setProperty("margin-top","20px"),r.style.setProperty("background-image","linear-gradient(to left, #f6414b, #ee0979)"),o.appendChild(r),r.addEventListener("click",(async s=>{s.stopPropagation(),o.remove();try{await e(),t();}catch(e){i(e);}}));}))}getVideoData(){let e;if(this.videoElement){if(this.isPortrait()){let e=320,i=240,o=480,s=640;var t=Math.PI/2;this.videoContext.translate(e,i),this.videoContext.rotate(t),this.videoContext.drawImage(this.videoElement,-i,-e,o,s),this.videoContext.rotate(-t),this.videoContext.translate(-e,-i);}else this.videoContext.drawImage(this.videoElement,0,0,640,480);e=this.videoContext.getImageData(0,0,640,480).data;}return e}getVideoElement(){return this.videoElement}getCameraParameters(){return {fov:radToDeg(2*Math.atan(this.videoSize[1]/936)),aspect:this.videoSize[0]/this.videoSize[1]}}isPortrait(){return window.innerWidth<window.innerHeight}setTouchListener(e){this.onTouch=e;}setTouchStartListener(e){this.onTouchStart=e;}setTouchMoveListener(e){this.onTouchMove=e;}setTouchEndListener(e){this.onTouchEnd=e;}getNormalizedTouchCoords(e){const t=new Vector2,i=this.renderCanvas.getBoundingClientRect();return null!=e.clientX?(t.x=(e.clientX-i.left)/i.width*2-1,t.y=-(e.clientY-i.top)/i.height*2+1):e.touches[0]?(t.x=e.touches[0].clientX/window.innerWidth*2-1,t.y=-e.touches[0].clientY/window.innerHeight*2+1):(t.x=e.changedTouches[0].clientX/window.innerWidth*2-1,t.y=-e.changedTouches[0].clientY/window.innerHeight*2+1),t}onCanvasTouch(e){const t=this.getNormalizedTouchCoords(e);this.onTouch&&this.onTouch(t);}onCanvasTouchStart(e){const t=this.getNormalizedTouchCoords(e);this.onTouchStart&&this.onTouchStart(t);}onCanvasTouchMove(e){const t=this.getNormalizedTouchCoords(e);this.onTouchMove&&this.onTouchMove(t);}onCanvasTouchEnd(e){const t=this.getNormalizedTouchCoords(e);this.onTouchEnd&&this.onTouchEnd(t);}}
44
44
 
@@ -48,7 +48,7 @@ class IMUManager{constructor(e,t){this.uiManager=e,this.deviceManager=t,this.sta
48
48
 
49
49
  class WorkerExtractionData{constructor(r,t,e,s,a,i,o=5){this.data=r,this.width=t,this.height=e,this.rotate=s,this.flip=a,this.colorSpace=o,this.dtype=i;}}class WorkerMatchingData{constructor(r,t,e,s){this.idx=r,this.from=t,this.to=e,this.dtype=s;}}class WorkerManager{constructor(){this.workers={},this.callbacks={};}workerExists(r){return void 0!==this.workers[r]&&void 0!==this.callbacks[r]}createExtractionWorker(r,t){this.workerExists(r)||(this.workers[r]=new Worker(new URL("worker-a.js",import.meta.url),{type:"module"}),this.callbacks[r]=t,this.workers[r].addEventListener("message",(t=>{this.callbacks[r](t.data);})));}createMatchingWorker(r,t){this.workerExists(r)||(this.workers[r]=new Worker(new URL("worker-b.js",import.meta.url),{type:"module"}),this.callbacks[r]=t,this.workers[r].addEventListener("message",(t=>{this.callbacks[r](t.data);})));}replaceCallback(r,t){this.workerExists(r)&&(this.callbacks[r]=t);}sendDataToWorker(r,t){this.workers[r].postMessage(t);}async createWorkers(){return Promise.all([new Promise(((r,t)=>{this.createExtractionWorker("extraction",(t=>{"ready"===t&&r();}));})),new Promise(((r,t)=>{this.createMatchingWorker("matching",(t=>{"ready"===t&&r();}));}))])}}
50
50
 
51
- class WebXRManager{constructor(t,e,i,a){this.uiManager=t,this.nativeManager=e,this.deviceManager=i,this.workerManager=a;}async isWebXRSupported(){let t=!1;return navigator.xr&&(t=await navigator.xr.isSessionSupported("immersive-ar")),t}async init(t,e,i){this.onPose=e,this.onSessionEnd=i;await this.uiManager.displayPermissionsDialog((async()=>{const e=["hit-test"],i=["dom-overlay"];t&&i.push("camera-access");try{const t=await navigator.xr.requestSession("immersive-ar",{requiredFeatures:e,optionalFeatures:i,domOverlay:{root:document.body}});await this.onXRSessionStarted(t);}catch(t){throw new SensorsError(`error while initializing webXR API: ${t}`)}}));}start(){this.started=!0,this.usingSpatial&&(this.relocating=!1,this.workerManager.replaceCallback("extraction",(t=>{if(!1===t)return void(this.relocating=!1);let e=this.nativeManager.loadExtractionData(t);this.candidates=Array.from(Array(e).keys()).reverse(),this.siftData=t.extraction,this.matchKeyframes();})),this.workerManager.replaceCallback("matching",(t=>{this.nativeManager.loadMatch(t),this.matchKeyframes();})));}matchKeyframes(){if(this.candidates.length>0){let t=this.candidates.pop();this.workerManager.sendDataToWorker("matching",new WorkerMatchingData(t,this.siftData,this.nativeManager.getCandidateData(t),this.nativeManager.extractionType()));}else this.nativeManager.spatialLocate(),this.relocating=!1;}async destroy(){this.xrSession&&(await this.xrSession.end(),this.xrSession=null,this.xrLastPose=null);}async onXRSessionStarted(t){let e=this.uiManager.renderCanvas.getContext("webgl2");e||(e=this.uiManager.renderCanvas.getContext("webgl")),e.getContextAttributes().xrCompatible||await e.makeXRCompatible(),this.xrContext=e,this.framebuffer=this.xrContext.createFramebuffer(),this.xrLayer=new XRWebGLLayer(t,this.xrContext);let i=this.xrLayer.framebufferWidth,a=this.xrLayer.framebufferHeight;this.usingSpatial&&(this.glBinding=new XRWebGLBinding(t,this.xrContext),this.nativeManager.xrbuffer=this.nativeManager.nativeSDK._malloc(i*a*4),this.nativeManager.siftBuffer=this.nativeManager.nativeSDK._malloc(22e5),this.nativeManager.matchBuffer=this.nativeManager.nativeSDK._malloc(14e3),this.nativeManager.netvladBuffer=this.nativeManager.nativeSDK._malloc(32768)),t.updateRenderState({baseLayer:this.xrLayer}),this.xrLocalRefSpace=await t.requestReferenceSpace("local"),this.xrViewerRefSpace=await t.requestReferenceSpace("viewer"),this.xrHitTestSource=await t.requestHitTestSource({space:this.xrViewerRefSpace}),t.requestAnimationFrame(this.onXRFrame.bind(this)),window.navigator.userAgent.includes("WebXRViewer")?(window.addEventListener("click",(t=>{this.onTouch&&this.onTouch(this.getNormalizedTouchCoords(t));})),window.addEventListener("touchstart",(t=>{this.onTouchStart&&this.onTouchStart(this.getNormalizedTouchCoords(t));})),window.addEventListener("touchend",(t=>{this.onTouchEnd&&this.onTouchEnd(this.getNormalizedTouchCoords(t));}))):(t.addEventListener("select",(t=>{this.onTouch&&this.onTouch(this.getXRInputCoords(t));})),t.addEventListener("selectstart",(t=>{this.onTouchStart&&this.onTouchStart(this.getXRInputCoords(t));})),t.addEventListener("selectend",(t=>{this.onTouchEnd&&this.onTouchEnd(this.getXRInputCoords(t));}))),window.addEventListener("touchmove",(t=>{this.onTouchMove&&this.onTouchMove(this.getNormalizedTouchCoords(t));})),t.addEventListener("end",(()=>{this.onSessionEnd&&this.onSessionEnd();})),this.xrSession=t;}hasRelocated(){return this.usingSpatial&&this.nativeManager.xrTransform}needsRelocation(){return this.usingSpatial&&!this.hasRelocated()&&(null==this.lastRelocationTry||this.msSinceRelocation()>2500)}startRelocationTimer(){this.lastRelocationTry=new Date;}msSinceRelocation(){let t=new Date;return this.lastRelocationTry?t-this.lastRelocationTry:0}onXRFrame(t,e){let i=e.session;i.requestAnimationFrame(this.onXRFrame.bind(this));const a=e.getViewerPose(this.xrLocalRefSpace);if(a){if(this.needsRelocation())for(const t of a.views)if(t.camera){const e=t.camera.width,i=t.camera.height;var r=new Uint8ClampedArray(e*i*4);let s=this.glBinding.getCameraImage(t.camera);const n=this.xrContext;let o,h;n.bindTexture(n.TEXTURE_2D,s),n.bindFramebuffer(n.FRAMEBUFFER,this.framebuffer),n.framebufferTexture2D(n.FRAMEBUFFER,n.COLOR_ATTACHMENT0,n.TEXTURE_2D,s,0),n.readPixels(0,0,t.camera.width,t.camera.height,n.RGBA,n.UNSIGNED_BYTE,r),this.uiManager.isPortrait()?(o=1,h=3):(o=2,h=0),this.relocating||(this.relocating=!0,this.extractionFrame=r,this.extractionWidth=e,this.extractionHeight=i,this.workerManager.sendDataToWorker("extraction",new WorkerExtractionData(r,e,i,h,o,this.nativeManager.extractionType())),this.nativeManager.lastXrPose=(new Matrix4).fromArray(a.transform.matrix).toArray()),this.startRelocationTimer();}this.xrContext.bindFramebuffer(this.xrContext.FRAMEBUFFER,i.renderState.baseLayer.framebuffer);const t=a.views[0];let s=(new Matrix4).fromArray(t.transform.matrix);if(this.deviceManager.os===DeviceManager.OS.Android&&this.started&&this.lastPose&&!this.jumpPose){2*Math.acos(Math.abs((new Quaternion).setFromRotationMatrix(s).dot((new Quaternion).setFromRotationMatrix(this.lastPose))))>1&&(this.jumpPose=s);}if(this.jumpPose){const t=this.jumpPose.clone().invert().multiply(s);s=this.lastPose.clone().multiply(t);}else this.lastPose=s;this.hasRelocated()&&(s=(new Matrix4).fromArray(this.nativeManager.xrTransform.elements).multiply(s)),this.usingSpatial&&!this.hasRelocated()||this.onPose(s.toArray());const n=null==this.xrLastPose||this.lastViewportWidth!=window.innerWidth||this.lastViewportHeight!=window.innerHeight;if(this.xrLastPose=a,this.lastViewportWidth=window.innerWidth,this.lastViewportHeight=window.innerHeight,n&&this.onResize&&this.onResize(),this.onHitTestResult){const t=e.getHitTestResults(this.xrHitTestSource);if(t.length>0){const e=t[0].getPose(this.xrLocalRefSpace),i=(new Matrix4).fromArray(e.transform.matrix),a=i.extractPosition(),r=((new Quaternion).setFromRotationMatrix(i),s.extractPosition()),n=Math.atan2(r.x-a.x,r.z-a.z),o={position:a,rotation:(new Quaternion).setFromEuler(new Euler(0,n,0))};this.onHitTestResult(o);}}}this.onFrame&&this.onFrame(e);}fitCanvasToXRViewport(){if(this.xrLastPose){const t=this.xrLastPose.views[0],e=this.xrLayer.getViewport(t);(e.width>e.height&&window.innerWidth>window.innerHeight||e.width<=e.height&&window.innerWidth<=window.innerHeight)&&e.width*e.height>window.innerWidth*window.innerHeight?(this.uiManager.renderCanvas.width=e.width,this.uiManager.renderCanvas.height=e.height):(this.uiManager.renderCanvas.width=window.innerWidth,this.uiManager.renderCanvas.height=window.innerHeight);}}getCameraParameters(){let t=60,e=9/16;if(this.xrSession&&this.xrLastPose){const i=this.xrLastPose.views[0].projectionMatrix;e=this.uiManager.renderCanvas.width/this.uiManager.renderCanvas.height,t=radToDeg(2*Math.atan(1/i[5]));}return {fov:t,aspect:e}}getXRLayer(){return this.xrLayer}getXRInputCoords(t){const e=t.inputSource.gamepad.axes;return new Vector2(e[0],-e[1])}getNormalizedTouchCoords(t){const e=new Vector2;return e.x=t.touches[0].clientX/window.innerWidth*2-1,e.y=-t.touches[0].clientY/window.innerHeight*2+1,e}setResizeListener(t){this.onResize=t;}setTouchListener(t){this.onTouch=t;}setTouchStartListener(t){this.onTouchStart=t;}setTouchMoveListener(t){this.onTouchMove=t;}setTouchEndListener(t){this.onTouchEnd=t;}setSessionEndListener(t){this.onSessionEnd=t;}setHitTestListener(t){this.onHitTestResult=t;}setFrameListener(t){this.onFrame=t;}}
51
+ class WebXRManager{constructor(t,e,i,a){this.uiManager=t,this.nativeManager=e,this.deviceManager=i,this.workerManager=a;}async isWebXRSupported(){let t=!1;return navigator.xr&&(t=await navigator.xr.isSessionSupported("immersive-ar")),t}async init(t,e,i){this.onPose=e,this.onSessionEnd=i;await this.uiManager.displayPermissionsDialog((async()=>{const e=["hit-test"],i=["dom-overlay"];t&&i.push("camera-access");try{const t=await navigator.xr.requestSession("immersive-ar",{requiredFeatures:e,optionalFeatures:i,domOverlay:{root:document.body}});await this.onXRSessionStarted(t);}catch(t){throw new SensorsError(`error while initializing webXR API: ${t}`)}}));}start(){this.started=!0,this.usingSpatial&&(this.relocating=!1,this.workerManager.replaceCallback("extraction",(t=>{if(!1===t)return void(this.relocating=!1);let e=this.nativeManager.loadExtractionData(t);this.candidates=Array.from(Array(e).keys()).reverse(),this.siftData=t.extraction,this.matchKeyframes();})),this.workerManager.replaceCallback("matching",(t=>{this.nativeManager.loadMatch(t),this.matchKeyframes();})));}matchKeyframes(){if(this.candidates.length>0){let t=this.candidates.pop();this.workerManager.sendDataToWorker("matching",new WorkerMatchingData(t,this.siftData,this.nativeManager.getCandidateData(t),this.nativeManager.extractionType()));}else this.nativeManager.spatialLocate(),this.relocating=!1;}async destroy(){this.xrSession&&(await this.xrSession.end(),this.xrSession=null,this.xrLastPose=null);}async onXRSessionStarted(t){let e=this.uiManager.renderCanvas.getContext("webgl2");e||(e=this.uiManager.renderCanvas.getContext("webgl")),e.getContextAttributes().xrCompatible||await e.makeXRCompatible(),this.xrContext=e,this.framebuffer=this.xrContext.createFramebuffer(),this.xrLayer=new XRWebGLLayer(t,this.xrContext);let i=this.xrLayer.framebufferWidth,a=this.xrLayer.framebufferHeight;this.usingSpatial&&(this.glBinding=new XRWebGLBinding(t,this.xrContext),this.nativeManager.xrbuffer=this.nativeManager.nativeSDK._malloc(i*a*4),this.nativeManager.siftBuffer=this.nativeManager.nativeSDK._malloc(22e5),this.nativeManager.matchBuffer=this.nativeManager.nativeSDK._malloc(14e3),this.nativeManager.netvladBuffer=this.nativeManager.nativeSDK._malloc(32768)),t.updateRenderState({baseLayer:this.xrLayer}),this.xrLocalRefSpace=await t.requestReferenceSpace("local"),this.xrViewerRefSpace=await t.requestReferenceSpace("viewer"),this.xrHitTestSource=await t.requestHitTestSource({space:this.xrViewerRefSpace}),t.requestAnimationFrame(this.onXRFrame.bind(this)),window.navigator.userAgent.includes("WebXRViewer")?(window.addEventListener("click",(t=>{this.onTouch&&this.onTouch(this.getNormalizedTouchCoords(t));})),window.addEventListener("touchstart",(t=>{this.onTouchStart&&this.onTouchStart(this.getNormalizedTouchCoords(t));})),window.addEventListener("touchend",(t=>{this.onTouchEnd&&this.onTouchEnd(this.getNormalizedTouchCoords(t));}))):(t.addEventListener("select",(t=>{this.onTouch&&this.onTouch(this.getXRInputCoords(t));})),t.addEventListener("selectstart",(t=>{this.onTouchStart&&this.onTouchStart(this.getXRInputCoords(t));})),t.addEventListener("selectend",(t=>{this.onTouchEnd&&this.onTouchEnd(this.getXRInputCoords(t));}))),window.addEventListener("touchmove",(t=>{this.onTouchMove&&this.onTouchMove(this.getNormalizedTouchCoords(t));})),t.addEventListener("end",(()=>{this.onSessionEnd&&this.onSessionEnd();})),this.xrSession=t;}hasRelocated(){return this.usingSpatial&&this.nativeManager.xrTransform}needsRelocation(){return this.usingSpatial&&!this.hasRelocated()&&(null==this.lastRelocationTry||this.msSinceRelocation()>2500)}startRelocationTimer(){this.lastRelocationTry=new Date;}msSinceRelocation(){let t=new Date;return this.lastRelocationTry?t-this.lastRelocationTry:0}onXRFrame(t,e){let i=e.session;i.requestAnimationFrame(this.onXRFrame.bind(this));const a=e.getViewerPose(this.xrLocalRefSpace);if(a){if(this.needsRelocation())for(const t of a.views)if(t.camera){const e=t.camera.width,i=t.camera.height;var r=new Uint8ClampedArray(e*i*4);let s=this.glBinding.getCameraImage(t.camera);const n=this.xrContext;let o,h;n.bindTexture(n.TEXTURE_2D,s),n.bindFramebuffer(n.FRAMEBUFFER,this.framebuffer),n.framebufferTexture2D(n.FRAMEBUFFER,n.COLOR_ATTACHMENT0,n.TEXTURE_2D,s,0),n.readPixels(0,0,t.camera.width,t.camera.height,n.RGBA,n.UNSIGNED_BYTE,r),this.uiManager.isPortrait()?(o=1,h=3):(o=2,h=0),this.relocating||(this.relocating=!0,this.extractionFrame=r,this.extractionWidth=e,this.extractionHeight=i,this.workerManager.sendDataToWorker("extraction",new WorkerExtractionData(r,e,i,h,o,this.nativeManager.extractionType())),this.nativeManager.lastXrPose=(new Matrix4).fromArray(a.transform.matrix).toArray()),this.startRelocationTimer();}this.xrContext.bindFramebuffer(this.xrContext.FRAMEBUFFER,i.renderState.baseLayer.framebuffer);const t=a.views[0];let s=(new Matrix4).fromArray(t.transform.matrix);if(this.deviceManager.os===DeviceManager.OS.Android&&this.started&&this.lastPose&&!this.jumpPose){2*Math.acos(Math.abs((new Quaternion).setFromRotationMatrix(s).dot((new Quaternion).setFromRotationMatrix(this.lastPose))))>1&&(this.jumpPose=s);}if(this.jumpPose){const t=this.jumpPose.clone().invert().multiply(s);s=this.lastPose.clone().multiply(t);}else this.lastPose=s;this.hasRelocated()&&(s=(new Matrix4).fromArray(this.nativeManager.xrTransform.elements).multiply(s)),this.usingSpatial&&!this.hasRelocated()||this.onPose(s.toArray());const n=null==this.xrLastPose||this.lastViewportWidth!=window.innerWidth||this.lastViewportHeight!=window.innerHeight;if(this.xrLastPose=a,this.lastViewportWidth=window.innerWidth,this.lastViewportHeight=window.innerHeight,n&&this.onResize&&this.onResize(),this.onHitTestResult){const t=e.getHitTestResults(this.xrHitTestSource);if(t.length>0){const e=t[0].getPose(this.xrLocalRefSpace),i=(new Matrix4).fromArray(e.transform.matrix),a=i.extractPosition(),r=((new Quaternion).setFromRotationMatrix(i),s.extractPosition()),n=Math.atan2(r.x-a.x,r.z-a.z),o={position:a,rotation:(new Quaternion).setFromEuler(new Euler(0,n,0))};this.onHitTestResult(o);}}}this.onFrame&&this.onFrame(e);}fitCanvasToXRViewport(){if(this.xrLastPose){const t=this.xrLastPose.views[0],e=this.xrLayer.getViewport(t);if((e.width>e.height&&window.innerWidth>window.innerHeight||e.width<=e.height&&window.innerWidth<=window.innerHeight)&&e.width*e.height>window.innerWidth*window.innerHeight)this.uiManager.renderCanvas.width=e.width,this.uiManager.renderCanvas.height=e.height;else {this.uiManager.renderCanvas.width=window.innerWidth;const t=parseInt(getComputedStyle(document.documentElement).getPropertyValue("--sat"),10)||0,e=parseInt(getComputedStyle(document.documentElement).getPropertyValue("--sab"),10)||0,i=window.innerHeight+t+e;this.uiManager.renderCanvas.height=i;}}}getCameraParameters(){let t=60,e=9/16;if(this.xrSession&&this.xrLastPose){const i=this.xrLastPose.views[0].projectionMatrix;e=this.uiManager.renderCanvas.width/this.uiManager.renderCanvas.height,t=radToDeg(2*Math.atan(1/i[5]));}return {fov:t,aspect:e}}getXRLayer(){return this.xrLayer}getXRInputCoords(t){const e=t.inputSource.gamepad.axes;return new Vector2(e[0],-e[1])}getNormalizedTouchCoords(t){const e=new Vector2;return e.x=t.touches[0].clientX/window.innerWidth*2-1,e.y=-t.touches[0].clientY/window.innerHeight*2+1,e}setResizeListener(t){this.onResize=t;}setTouchListener(t){this.onTouch=t;}setTouchStartListener(t){this.onTouchStart=t;}setTouchMoveListener(t){this.onTouchMove=t;}setTouchEndListener(t){this.onTouchEnd=t;}setSessionEndListener(t){this.onSessionEnd=t;}setHitTestListener(t){this.onHitTestResult=t;}setFrameListener(t){this.onFrame=t;}}
52
52
 
53
53
  class EventManager{constructor(){this.eventListeners={},this.eventListenerCount=0;}stop(){this.eventListeners={},this.eventListenerCount=0;}addEventListener(e,t){this.eventListeners[e]||(this.eventListeners[e]=[]);const n=this.eventListenerCount++;return this.eventListeners[e].push({id:n,func:t}),n}triggerEvent(e,t){this.eventListeners[e]&&this.eventListeners[e].map((e=>e.func(t)));}removeEventListener(e){for(let t of Object.keys(this.eventListeners))for(let n=0;n<t.length;n++)if(t[n].id===e){t.splice(n,1);break}}}
54
54