(function () { // Shared Lib var CANVAS_ID = 'application-canvas'; // Needed as we will have edge cases for particular versions of iOS // returns null if not iOS var getIosVersion = function () { if (/iP(hone|od|ad)/.test(navigator.platform)) { var v = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/); var version = [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)]; return version; } return null; }; var lastWindowHeight = window.innerHeight; var lastWindowWidth = window.innerWidth; var windowSizeChangeIntervalHandler = null; var pcBootstrap = { reflowHandler: null, iosVersion: getIosVersion(), createCanvas: function () { var canvas = document.createElement('canvas'); canvas.setAttribute('id', CANVAS_ID); canvas.setAttribute('tabindex', 0); // Disable I-bar cursor on click+drag canvas.onselectstart = function () { return false; }; // Disable long-touch select on iOS devices canvas.style['-webkit-user-select'] = 'none'; document.body.appendChild(canvas); return canvas; }, resizeCanvas: function (app, canvas) { canvas.style.width = ''; canvas.style.height = ''; app.resizeCanvas(canvas.width, canvas.height); var fillMode = app._fillMode; if (fillMode === pc.FILLMODE_NONE || fillMode === pc.FILLMODE_KEEP_ASPECT) { if ((fillMode === pc.FILLMODE_NONE && canvas.clientHeight < window.innerHeight) || (canvas.clientWidth / canvas.clientHeight >= window.innerWidth / window.innerHeight)) { canvas.style.marginTop = Math.floor((window.innerHeight - canvas.clientHeight) / 2) + 'px'; } else { canvas.style.marginTop = ''; } } lastWindowHeight = window.innerHeight; lastWindowWidth = window.innerWidth; // Work around when in landscape to work on iOS 12 otherwise // the content is under the URL bar at the top if (this.iosVersion && this.iosVersion[0] <= 12) { window.scrollTo(0, 0); } }, reflow: function (app, canvas) { this.resizeCanvas(app, canvas); // Poll for size changes as the window inner height can change after the resize event for iOS // Have one tab only, and rotate from portrait -> landscape -> portrait if (windowSizeChangeIntervalHandler === null) { windowSizeChangeIntervalHandler = setInterval(function () { if (lastWindowHeight !== window.innerHeight || lastWindowWidth !== window.innerWidth) { this.resizeCanvas(app, canvas); } }.bind(this), 100); // Don't want to do this all the time so stop polling after some short time setTimeout(function () { if (!!windowSizeChangeIntervalHandler) { clearInterval(windowSizeChangeIntervalHandler); windowSizeChangeIntervalHandler = null; } }, 2000); } } }; // Expose the reflow to users so that they can override the existing // reflow logic if need be window.pcBootstrap = pcBootstrap; })(); (function () { // template varants var LTC_MAT_1 = []; var LTC_MAT_2 = []; // varants var canvas = pcBootstrap.createCanvas(); var app = new pc.AppBase(canvas); function initCSS() { if (document.head.querySelector) { // css media query for aspect ratio changes // TODO: Change these from private properties var css = `@media screen and (min-aspect-ratio: ${app._width}/${app._height}) { #application-canvas.fill-mode-KEEP_ASPECT { width: auto; height: 100%; margin: 0 auto; } }`; document.head.querySelector('style').innerHTML += css; } // Configure resolution and resize event if (canvas.classList) { canvas.classList.add(`fill-mode-${app.fillMode}`); } } function displayError(html) { var div = document.createElement('div'); div.innerHTML = `
${html}
`; document.body.appendChild(div); } function createGraphicsDevice(callback) { var deviceOptions = window.CONTEXT_OPTIONS ? window.CONTEXT_OPTIONS : {}; if (typeof window.Promise === 'function') { var LEGACY_WEBGL = 'webgl'; var deviceTypes = [...deviceOptions.deviceTypes, LEGACY_WEBGL]; var gpuLibPath = window.ASSET_PREFIX ? (window.ASSET_PREFIX.replace(/\/$/g, '') + '/') : ''; // new graphics device creation function with promises var gfxOptions = { deviceTypes: deviceTypes, glslangUrl: gpuLibPath + 'glslang.js', twgslUrl: gpuLibPath + 'twgsl.js', powerPreference: deviceOptions.powerPreference, antialias: deviceOptions.antialias !== false, alpha: deviceOptions.alpha === true, preserveDrawingBuffer: !!deviceOptions.preserveDrawingBuffer }; pc.createGraphicsDevice(canvas, gfxOptions).then((device) => { callback(device); }).catch((e) => { console.error('Device creation error:', e); callback(null); }) } else { var igl1 = deviceOptions.deviceTypes.indexOf('webgl1'); var igl2 = deviceOptions.deviceTypes.indexOf('webgl2'); // old webgl graphics device creation var options = { powerPreference: deviceOptions.powerPreference, antialias: deviceOptions.antialias !== false, alpha: deviceOptions.transparentCanvas !== false, preserveDrawingBuffer: !!deviceOptions.preserveDrawingBuffer, preferWebGl2: igl2 > igl1 }; if (pc.platform.browser && !!navigator.xr) { options.xrCompatible = true; } callback(new pc.WebglGraphicsDevice(canvas, options)); } } function initApp(device) { try { var createOptions = new pc.AppOptions(); createOptions.graphicsDevice = device; createOptions.componentSystems = [ pc.RigidBodyComponentSystem, pc.CollisionComponentSystem, pc.JointComponentSystem, pc.AnimationComponentSystem, pc.AnimComponentSystem, pc.ModelComponentSystem, pc.RenderComponentSystem, pc.CameraComponentSystem, pc.LightComponentSystem, pc.script.legacy ? pc.ScriptLegacyComponentSystem : pc.ScriptComponentSystem, pc.AudioSourceComponentSystem, pc.SoundComponentSystem, pc.AudioListenerComponentSystem, pc.ParticleSystemComponentSystem, pc.ScreenComponentSystem, pc.ElementComponentSystem, pc.ButtonComponentSystem, pc.ScrollViewComponentSystem, pc.ScrollbarComponentSystem, pc.SpriteComponentSystem, pc.LayoutGroupComponentSystem, pc.LayoutChildComponentSystem, pc.ZoneComponentSystem, pc.GSplatComponentSystem, ].filter(Boolean); createOptions.resourceHandlers = [ pc.RenderHandler, pc.AnimationHandler, pc.AnimClipHandler, pc.AnimStateGraphHandler, pc.ModelHandler, pc.MaterialHandler, pc.TextureHandler, pc.TextHandler, pc.JsonHandler, pc.AudioHandler, pc.ScriptHandler, pc.SceneHandler, pc.CubemapHandler, pc.HtmlHandler, pc.CssHandler, pc.ShaderHandler, pc.HierarchyHandler, pc.FolderHandler, pc.FontHandler, pc.BinaryHandler, pc.TextureAtlasHandler, pc.SpriteHandler, pc.TemplateHandler, pc.ContainerHandler, pc.GSplatHandler ].filter(Boolean); createOptions.elementInput = new pc.ElementInput(canvas, { useMouse: INPUT_SETTINGS.useMouse, useTouch: INPUT_SETTINGS.useTouch }); createOptions.keyboard = INPUT_SETTINGS.useKeyboard ? new pc.Keyboard(window) : null; createOptions.mouse = INPUT_SETTINGS.useMouse ? new pc.Mouse(canvas) : null; createOptions.gamepads = INPUT_SETTINGS.useGamepads ? new pc.GamePads() : null; createOptions.touch = INPUT_SETTINGS.useTouch && pc.platform.touch ? new pc.TouchDevice(canvas) : null; createOptions.assetPrefix = window.ASSET_PREFIX || ''; createOptions.scriptPrefix = window.SCRIPT_PREFIX || ''; createOptions.scriptsOrder = window.SCRIPTS || []; createOptions.soundManager = new pc.SoundManager(); createOptions.lightmapper = pc.Lightmapper; createOptions.batchManager = pc.BatchManager; createOptions.xr = pc.XrManager; app.init(createOptions); return true; } catch (e) { displayError('Could not initialize application. Error: ' + e); console.error(e); return false; } } function configure() { app.configure(window.CONFIG_FILENAME, (err) => { if (err) { console.error(err); return; } initCSS(canvas, app._fillMode, app._width, app._height); if (LTC_MAT_1.length && LTC_MAT_2.length && app.setAreaLightLuts.length === 2) { app.setAreaLightLuts(LTC_MAT_1, LTC_MAT_2); } // do the first reflow after a timeout because of // iOS showing a squished iframe sometimes setTimeout(() => { pcBootstrap.reflow(app, canvas); pcBootstrap.reflowHandler = function () { pcBootstrap.reflow(app, canvas); }; window.addEventListener('resize', pcBootstrap.reflowHandler, false); window.addEventListener('orientationchange', pcBootstrap.reflowHandler, false); app.preload(() => { app.scenes.loadScene(window.SCENE_PATH, (err) => { if (err) { console.error(err); return; } app.start(); }) }) }); }); } function main() { createGraphicsDevice((device) => { if (!device) { return; } if (!initApp(device)) { return; } if (window.PRELOAD_MODULES.length) { loadModules(window.PRELOAD_MODULES, window.ASSET_PREFIX, () => { configure(() => { console.timeEnd('start'); }); }) } else { configure(); } }); } main(); })(); // Add scope to avoid polluting window scope