UNPKG

@shopware-ag/dive

Version:

Shopware Spatial Framework

216 lines (183 loc) 6.03 kB
import { Camera, MathUtils, NoToneMapping, PCFSoftShadowMap, Scene, ShadowMapType, ToneMapping, WebGLRenderer, } from 'three'; export type DIVERendererSettings = { antialias: boolean; alpha: boolean; stencil: boolean; shadowMapEnabled: boolean; shadowMapType: ShadowMapType; toneMapping: ToneMapping; canvas?: HTMLCanvasElement; }; export const DIVERendererDefaultSettings: DIVERendererSettings = { antialias: true, alpha: true, stencil: false, shadowMapEnabled: true, shadowMapType: PCFSoftShadowMap, toneMapping: NoToneMapping, canvas: undefined, }; export type DIVERenderCallback = ( time: DOMHighResTimeStamp, frame: XRFrame, ) => void; /** * A changed version of the WebGLRenderer. * * Has to be started manually by calling StartRenderer(). * * @module */ export class DIVERenderer extends WebGLRenderer { // basic functionality members private paused: boolean = false; private running: boolean = false; private force: boolean = false; // pre- and post-render callbacks private preRenderCallbacks: Map<string, DIVERenderCallback> = new Map< string, DIVERenderCallback >(); private postRenderCallbacks: Map<string, DIVERenderCallback> = new Map< string, DIVERenderCallback >(); constructor( rendererSettings: Partial<DIVERendererSettings> = DIVERendererDefaultSettings, ) { super({ antialias: rendererSettings.antialias || DIVERendererDefaultSettings.antialias, alpha: rendererSettings.alpha || DIVERendererDefaultSettings.alpha, preserveDrawingBuffer: true, canvas: rendererSettings.canvas, }); this.setPixelRatio(window.devicePixelRatio); this.shadowMap.enabled = rendererSettings.shadowMapEnabled || DIVERendererDefaultSettings.shadowMapEnabled; this.shadowMap.type = rendererSettings.shadowMapType || DIVERendererDefaultSettings.shadowMapType; this.toneMapping = rendererSettings.toneMapping || DIVERendererDefaultSettings.toneMapping; this.debug.checkShaderErrors = false; } // Stops renderings and disposes the renderer. public Dispose(): void { this.StopRenderer(); this.dispose(); } // Starts the renderer with the given scene and camera. public StartRenderer(scene: Scene, cam: Camera): void { this.setAnimationLoop((time: DOMHighResTimeStamp, frame: XRFrame) => { this.internal_render(scene, cam, time, frame); }); this.running = true; } // Pauses the renderer. public PauseRenderer(): void { this.paused = true; } // Resumes the renderer after pausing. public ResumeRenderer(): void { this.paused = false; } // Stops the renderer completely. Has to be started again with StartRenderer(). public StopRenderer(): void { this.setAnimationLoop(null); this.running = false; } // Resizes the renderer to the given width and height. public OnResize(width: number, height: number): void { this.setSize(width, height); } /** * Adds a callback to the render loop before actual render call. * @param callback Executed before rendering. * @returns uuid to remove the callback. */ public AddPreRenderCallback(callback: DIVERenderCallback): string { // add callback to renderloop const newUUID = MathUtils.generateUUID(); this.preRenderCallbacks.set(newUUID, callback); return newUUID; } /** * Removes a callback from the render loop before actual render call. * @param uuid of callback to remove. * @returns if removing was successful. */ public RemovePreRenderCallback(uuid: string): boolean { // check if callback exists if (!this.preRenderCallbacks.has(uuid)) return false; // remove callback from renderloop this.preRenderCallbacks.delete(uuid); return true; } /** * Adds a callback to the render loop after actual render call. * @param callback Executed after rendering. * @returns uuid to remove the callback. */ public AddPostRenderCallback(callback: DIVERenderCallback): string { // add callback to renderloop const newUUID = MathUtils.generateUUID(); this.postRenderCallbacks.set(newUUID, callback); return newUUID; } /** * Removes a callback from the render loop after actual render call. * @param uuid of callback to remove. * @returns if removing was successful. */ public RemovePostRenderCallback(uuid: string): boolean { // check if callback exists if (!this.postRenderCallbacks.has(uuid)) return false; // remove callback from renderloop this.postRenderCallbacks.delete(uuid); return true; } /** * Forces the renderer to render the next frame. */ public ForceRendering(): void { this.force = true; } /** * Internal render loop. * * To control renderloop you can add callbacks via AddPreRenderCallback() and AddPostRenderCallback(). * @param scene Scene to render. * @param cam Camera to render with. */ private internal_render( scene: Scene, cam: Camera, time: DOMHighResTimeStamp, frame: XRFrame, ): void { // execute background render loop callbacks if ((this.paused || !this.running) && !this.force) return; // execute render loop callbacks this.preRenderCallbacks.forEach((callback) => { callback(time, frame); }); this.render(scene, cam); this.postRenderCallbacks.forEach((callback) => { callback(time, frame); }); this.force = false; } }