Allow to provide a canvas to be used for the game rendering instead of creating a new one (#7199)

Only show in developer changelog
This commit is contained in:
danvervlad
2024-11-29 18:51:12 +02:00
committed by GitHub
parent d110e83f6f
commit 35fd7e972b
3 changed files with 96 additions and 14 deletions

View File

@@ -60,15 +60,29 @@ namespace gdjs {
}
/**
* Create a standard canvas inside canvasArea.
* Create the canvas on which the game will be rendered, inside the specified DOM element, and
* setup the rendering of the game.
* If you want to use your own canvas, use `initializeForCanvas` instead.
*
* @param parentElement The parent element to which the canvas will be added.
*/
createStandardCanvas(parentElement: HTMLElement) {
this._throwIfDisposed();
let gameCanvas: HTMLCanvasElement;
const gameCanvas = document.createElement('canvas');
parentElement.appendChild(gameCanvas);
this.initializeForCanvas(gameCanvas);
}
/**
* Setup the rendering of the game to use a canvas that was already created.
* @param gameCanvas The canvas to use.
*/
initializeForCanvas(gameCanvas: HTMLCanvasElement): void {
this._throwIfDisposed();
if (typeof THREE !== 'undefined') {
gameCanvas = document.createElement('canvas');
this._threeRenderer = new THREE.WebGLRenderer({
canvas: gameCanvas,
antialias:
@@ -99,8 +113,6 @@ namespace gdjs {
backgroundAlpha: 0,
// TODO (3D): add a setting for pixel ratio (`resolution: window.devicePixelRatio`)
});
gameCanvas = this._threeRenderer.domElement;
} else {
// Create the renderer and setup the rendering area.
// "preserveDrawingBuffer: true" is needed to avoid flickering
@@ -108,11 +120,10 @@ namespace gdjs {
this._pixiRenderer = PIXI.autoDetectRenderer({
width: this._game.getGameResolutionWidth(),
height: this._game.getGameResolutionHeight(),
view: gameCanvas,
preserveDrawingBuffer: true,
antialias: false,
}) as PIXI.Renderer;
gameCanvas = this._pixiRenderer.view as HTMLCanvasElement;
}
// Deactivating accessibility support in PixiJS renderer, as we want to be in control of this.
@@ -121,7 +132,6 @@ namespace gdjs {
delete this._pixiRenderer.plugins.accessibility;
// Add the renderer view element to the DOM
parentElement.appendChild(gameCanvas);
this._gameCanvas = gameCanvas;
gameCanvas.style.position = 'absolute';
@@ -160,7 +170,7 @@ namespace gdjs {
// but it seems not to affect us as the `domElementsContainer` has `pointerEvents` set to `none`.
domElementsContainer.style['-webkit-user-select'] = 'none';
parentElement.appendChild(domElementsContainer);
gameCanvas.parentNode?.appendChild(domElementsContainer);
this._domElementsContainer = domElementsContainer;
this._resizeCanvas();
@@ -938,14 +948,26 @@ namespace gdjs {
}
/**
* Dispose PixiRenderer, ThreeRenderer and remove canvas from DOM.
* Dispose the renderers (PixiJS and/or Three.js) as well as DOM elements
* used for the game (the canvas, if specified, and the additional DOM container
* created on top of it to allow display HTML elements, for example for text inputs).
*
* @param removeCanvas If true, the canvas will be removed from the DOM.
*/
dispose() {
this._pixiRenderer?.destroy(true);
dispose(removeCanvas?: boolean) {
this._pixiRenderer?.destroy();
this._threeRenderer?.dispose();
this._pixiRenderer = null;
this._threeRenderer = null;
if (removeCanvas && this._gameCanvas) {
this._gameCanvas.parentNode?.removeChild(this._gameCanvas);
}
this._gameCanvas = null;
this._domElementsContainer?.parentNode?.removeChild(
this._domElementsContainer
);
this._domElementsContainer = null;
this._wasDisposed = true;
}

View File

@@ -976,11 +976,12 @@ namespace gdjs {
/**
* Stop game loop, unload all scenes, dispose renderer and resources.
* After calling this method, the RuntimeGame should not be used anymore.
* @param removeCanvas If true, the canvas will be removed from the DOM.
*/
dispose(): void {
dispose(removeCanvas?: boolean): void {
this._renderer.stopGameLoop();
this._sceneStack.dispose();
this._renderer.dispose();
this._renderer.dispose(removeCanvas);
this._resourcesLoader.dispose();
this._wasDisposed = true;

View File

@@ -0,0 +1,59 @@
describe('gdjs.RuntimeGameRenderer canvas tests', () => {
let runtimeGame;
let renderer;
let gameContainer;
beforeEach(() => {
runtimeGame = gdjs.getPixiRuntimeGame();
renderer = runtimeGame.getRenderer();
gameContainer = document.createElement('div');
});
it('should correctly create standard canvas and domElementsContainer', () => {
renderer.createStandardCanvas(gameContainer);
const actualGameCanvas = renderer.getCanvas();
const actualDomElementsContainer = renderer.getDomElementContainer();
expect(actualGameCanvas).to.not.be(null);
expect(actualDomElementsContainer).to.not.be(null);
expect(actualGameCanvas.parentElement).to.be(gameContainer);
expect(actualDomElementsContainer.parentElement).to.be(gameContainer);
});
it('should correctly initialize external canvas and create domElementsContainer', () => {
const gameCanvas = document.createElement('canvas');
gameContainer.appendChild(gameCanvas);
renderer.initializeForCanvas(gameCanvas);
const actualGameCanvas = renderer.getCanvas();
const actualDomElementsContainer = renderer.getDomElementContainer();
expect(actualGameCanvas).to.not.be(null);
expect(actualDomElementsContainer).to.not.be(null);
expect(actualGameCanvas).to.be(gameCanvas);
expect(actualDomElementsContainer.parentElement).to.be(gameContainer);
});
it('should remove canvas and domElementsContainer on dispose', () => {
renderer.createStandardCanvas(gameContainer);
const actualGameCanvas = renderer.getCanvas();
const actualDomElementsContainer = renderer.getDomElementContainer();
expect(actualGameCanvas).to.not.be(null);
expect(actualDomElementsContainer).to.not.be(null);
expect(actualGameCanvas.parentElement).to.be(gameContainer);
expect(actualDomElementsContainer.parentElement).to.be(gameContainer);
runtimeGame.dispose(true);
const actualGameCanvasAfterDispose = renderer.getCanvas();
const actualDomElementsContainerAfterDispose = renderer.getDomElementContainer();
expect(actualGameCanvasAfterDispose).to.be(null);
expect(actualDomElementsContainerAfterDispose).to.be(null);
expect(gameContainer.childNodes.length).to.be(0);
});
});