diff --git a/src/core/cleanup.ts b/src/core/cleanup.ts index 3311bf9..768cd43 100644 --- a/src/core/cleanup.ts +++ b/src/core/cleanup.ts @@ -1,11 +1,11 @@ -import { Engine } from "@babylonjs/core"; +import { AbstractEngine } from "@babylonjs/core"; import { DefaultScene } from "./defaultScene"; import { RockFactory } from "../environment/asteroids/rockFactory"; import log from './logger'; import Level from "../levels/level"; export interface CleanupContext { - getEngine(): Engine; + getEngine(): AbstractEngine; getCurrentLevel(): Level | null; setCurrentLevel(level: Level | null): void; resetState(): void; diff --git a/src/core/handlers/levelSelectedHandler.ts b/src/core/handlers/levelSelectedHandler.ts index fa4827d..b8cafcc 100644 --- a/src/core/handlers/levelSelectedHandler.ts +++ b/src/core/handlers/levelSelectedHandler.ts @@ -1,4 +1,4 @@ -import { AudioEngineV2, Engine, ParticleHelper } from "@babylonjs/core"; +import { AbstractEngine, AudioEngineV2, ParticleHelper } from "@babylonjs/core"; import { DefaultScene } from "../defaultScene"; import { Level1 } from "../../levels/level1"; import Level from "../../levels/level"; @@ -20,7 +20,7 @@ export interface LevelSelectedContext { initializeEngine(): Promise; initializeXR(): Promise; getAudioEngine(): AudioEngineV2; - getEngine(): Engine; + getEngine(): AbstractEngine; setCurrentLevel(level: Level): void; setProgressCallback(callback: (percent: number, message: string) => void): void; play(): Promise; @@ -169,7 +169,7 @@ function attachAudioListener(audioEngine: AudioEngineV2): void { async function finalizeLevelStart( level: Level1, - engine: Engine, + engine: AbstractEngine, preloader: Preloader, context: LevelSelectedContext ): Promise { @@ -188,7 +188,7 @@ async function finalizeLevelStart( await context.play(); } -function showCanvasForFlatMode(engine: Engine): void { +function showCanvasForFlatMode(engine: AbstractEngine): void { const canvas = document.getElementById('gameCanvas'); if (canvas) canvas.style.display = 'block'; engine.stopRenderLoop(); diff --git a/src/core/handlers/xrEntryHandler.ts b/src/core/handlers/xrEntryHandler.ts index 3803563..6210e10 100644 --- a/src/core/handlers/xrEntryHandler.ts +++ b/src/core/handlers/xrEntryHandler.ts @@ -1,4 +1,4 @@ -import { Engine, FreeCamera, Vector3 } from "@babylonjs/core"; +import { AbstractEngine, FreeCamera, Vector3 } from "@babylonjs/core"; import { DefaultScene } from "../defaultScene"; import { LevelConfig } from "../../levels/config/levelConfig"; import log from '../logger'; @@ -9,7 +9,7 @@ import log from '../logger'; */ export async function enterXRMode( config: LevelConfig, - engine: Engine + engine: AbstractEngine ): Promise { if (!DefaultScene.XR) { return startFlatMode(engine); @@ -39,7 +39,7 @@ function prePositionCamera(config: LevelConfig): void { log.debug('[XR] Camera pre-positioned at cockpit:', cockpitPosition.toString()); } -function startFlatMode(engine: Engine): null { +function startFlatMode(engine: AbstractEngine): null { const canvas = document.getElementById('gameCanvas'); if (canvas) canvas.style.display = 'block'; engine.stopRenderLoop(); diff --git a/src/core/queryParams.ts b/src/core/queryParams.ts new file mode 100644 index 0000000..334300a --- /dev/null +++ b/src/core/queryParams.ts @@ -0,0 +1,3 @@ +const urlParams = new URLSearchParams(window.location.search); + +export const useWebGPU = urlParams.get('webGPU') === 'true'; diff --git a/src/core/sceneSetup.ts b/src/core/sceneSetup.ts index 58ca194..2470a58 100644 --- a/src/core/sceneSetup.ts +++ b/src/core/sceneSetup.ts @@ -1,18 +1,22 @@ import { + AbstractEngine, AudioEngineV2, Color3, CreateAudioEngineAsync, Engine, HavokPlugin, Scene, - Vector3 + Vector3, + WebGPUEngine, } from "@babylonjs/core"; import HavokPhysics from "@babylonjs/havok"; import { DefaultScene } from "./defaultScene"; import { ProgressReporter } from "./xrSetup"; +import { useWebGPU } from "./queryParams"; +import log from './logger'; export interface SceneSetupResult { - engine: Engine; + engine: AbstractEngine; audioEngine: AudioEngineV2; } @@ -24,7 +28,7 @@ export async function setupScene( reporter: ProgressReporter ): Promise { reporter.reportProgress(5, 'Creating rendering engine...'); - const engine = createEngine(canvas); + const engine = await createEngine(canvas); reporter.reportProgress(10, 'Creating scene...'); createMainScene(engine); @@ -44,14 +48,22 @@ export async function setupScene( return { engine, audioEngine }; } -function createEngine(canvas: HTMLCanvasElement): Engine { - const engine = new Engine(canvas, true); +async function createEngine(canvas: HTMLCanvasElement): Promise { + let engine: AbstractEngine; + if (useWebGPU) { + log.info('[Engine] Creating WebGPU engine'); + log.warn('[Engine] WebXR/VR is still experimental'); + engine = await WebGPUEngine.CreateAsync(canvas, { antialias: true }); + } else { + log.info('[Engine] Creating WebGL engine'); + engine = new Engine(canvas, true); + } engine.setHardwareScalingLevel(1 / window.devicePixelRatio); window.onresize = () => engine.resize(); return engine; } -function createMainScene(engine: Engine): void { +function createMainScene(engine: AbstractEngine): void { // Dispose old scene if it exists (prevents doubling on reload) if (DefaultScene.MainScene && !DefaultScene.MainScene.isDisposed) { DefaultScene.MainScene.dispose(); diff --git a/src/main.ts b/src/main.ts index 387e25c..78d59ec 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,4 @@ -import { AudioEngineV2, Engine } from "@babylonjs/core"; +import { AbstractEngine, AudioEngineV2 } from "@babylonjs/core"; import '@babylonjs/loaders'; import { DefaultScene } from "./core/defaultScene"; @@ -20,7 +20,7 @@ const canvas = document.querySelector('#gameCanvas') as HTMLCanvasElement; export class Main implements LevelSelectedContext, CleanupContext { private _currentLevel: Level | null = null; - private _engine: Engine; + private _engine: AbstractEngine; private _audioEngine: AudioEngineV2; private _initialized: boolean = false; private _assetsLoaded: boolean = false; @@ -43,7 +43,7 @@ export class Main implements LevelSelectedContext, CleanupContext { areAssetsLoaded(): boolean { return this._assetsLoaded; } setAssetsLoaded(value: boolean): void { this._assetsLoaded = value; } getAudioEngine(): AudioEngineV2 { return this._audioEngine; } - getEngine(): Engine { return this._engine; } + getEngine(): AbstractEngine { return this._engine; } setCurrentLevel(level: Level): void { this._currentLevel = level; } setProgressCallback(cb: (percent: number, message: string) => void): void { this._progressCallback = cb;