UNPKG

@pmndrs/xr

Version:
80 lines (79 loc) 3.19 kB
import { DefaultAssetBasePath } from '../index.js'; import { syncAsync } from './utils.js'; const DefaultDefaultControllerProfileId = 'generic-trigger'; export class XRControllerLayoutLoader { baseAssetPath; defaultProfileId; //cache profilesListCache; profileCacheMap = new Map(); constructor(options) { this.baseAssetPath = options?.baseAssetPath ?? DefaultAssetBasePath; this.defaultProfileId = options?.defaultControllerProfileId ?? DefaultDefaultControllerProfileId; } load(inputSourceProfileIds, handedness) { return syncAsync( //load profile () => this.loadProfile(inputSourceProfileIds), //get controller layout from profile (profile) => { for (const key in profile.layouts) { if (!key.includes(handedness)) { continue; } return profile.layouts[key]; } throw new Error(`No matching layout for "${handedness}", in profile ${profile.profileId} with layouts ${Object.keys(profile.layouts).join(', ')}.`); }); } //alias for Loader compatibility loadAsync = this.load; loadProfile(inputSourceProfileIds) { return syncAsync( //load profiles list () => this.profilesListCache ?? fetchJson(new URL('profilesList.json', this.baseAssetPath).href).then((profilesList) => (this.profilesListCache = profilesList)), //load profile (profilesList) => { const length = inputSourceProfileIds.length; let profileInfo; for (let i = 0; i < length; i++) { profileInfo = profilesList[inputSourceProfileIds[i]]; if (profileInfo != null) { break; } } profileInfo ??= profilesList[this.defaultProfileId]; if (profileInfo == null) { throw new Error(`no matching profile found for profiles "${inputSourceProfileIds.join(', ')}" in profile list ${JSON.stringify(profilesList)}`); } return this.loadProfileFromPath(profileInfo.path); }); } loadProfileFromPath(relativeProfilePath) { const result = this.profileCacheMap.get(relativeProfilePath); if (result != null) { return result; } const absoluteProfilePath = new URL(relativeProfilePath, this.baseAssetPath).href; return fetchJson(absoluteProfilePath).then((profile) => { //overwrite the relative assetPath into an absolute path for (const key in profile.layouts) { const layout = profile.layouts[key]; if (layout == null) { continue; } layout.assetPath = new URL(layout.assetPath, absoluteProfilePath).href; } this.profileCacheMap.set(relativeProfilePath, profile); return profile; }); } } async function fetchJson(url) { let response = await fetch(url); if (!response.ok) { return Promise.reject(new Error(response.statusText)); } return response.json(); }