106 lines
3.3 KiB
JavaScript
106 lines
3.3 KiB
JavaScript
/**
|
|
* Provide the necessary methods to get a snapshot of the framebuffer into a render texture.
|
|
* Class meant to be used as a singleton.
|
|
* Created with the precious advices of dev7355608.
|
|
*/
|
|
class FramebufferSnapshot {
|
|
constructor() {
|
|
/**
|
|
* The RenderTexture that is the render destination for the framebuffer snapshot.
|
|
* @type {PIXI.RenderTexture}
|
|
*/
|
|
this.framebufferTexture = FramebufferSnapshot.#createRenderTexture();
|
|
|
|
// Listen for resize events
|
|
canvas.app.renderer.on("resize", () => this.#hasResized = true);
|
|
}
|
|
|
|
/**
|
|
* To know if we need to update the texture.
|
|
* @type {boolean}
|
|
*/
|
|
#hasResized = true;
|
|
|
|
/**
|
|
* A placeholder for temporary copy.
|
|
* @type {PIXI.Rectangle}
|
|
*/
|
|
#tempSourceFrame = new PIXI.Rectangle();
|
|
|
|
/* ---------------------------------------- */
|
|
|
|
/**
|
|
* Get the framebuffer texture snapshot.
|
|
* @param {PIXI.Renderer} renderer The renderer for this context.
|
|
* @returns {PIXI.RenderTexture} The framebuffer snapshot.
|
|
*/
|
|
getFramebufferTexture(renderer) {
|
|
// Need resize?
|
|
if ( this.#hasResized ) {
|
|
CachedContainer.resizeRenderTexture(renderer, this.framebufferTexture);
|
|
this.#hasResized = false;
|
|
}
|
|
|
|
// Flush batched operations before anything else
|
|
renderer.batch.flush();
|
|
|
|
const fb = renderer.framebuffer.current;
|
|
const vf = this.#tempSourceFrame.copyFrom(renderer.renderTexture.viewportFrame);
|
|
|
|
// Inverted Y in the case of canvas
|
|
if ( !fb ) vf.y = renderer.view.height - (vf.y + vf.height);
|
|
|
|
// Empty viewport
|
|
if ( !(vf.width > 0 && vf.height > 0) ) return PIXI.Texture.WHITE;
|
|
|
|
// Computing bounds of the source
|
|
let srcX = vf.x;
|
|
let srcY = vf.y;
|
|
let srcX2 = srcX + vf.width;
|
|
let srcY2 = srcY + vf.height;
|
|
|
|
// Inverted Y in the case of canvas
|
|
if ( !fb ) {
|
|
srcY = renderer.view.height - 1 - srcY;
|
|
srcY2 = srcY - vf.height;
|
|
}
|
|
|
|
// Computing bounds of the destination
|
|
let dstX = 0;
|
|
let dstY = 0;
|
|
let dstX2 = vf.width;
|
|
let dstY2 = vf.height;
|
|
|
|
// Preparing the gl context
|
|
const gl = renderer.gl;
|
|
const framebufferSys = renderer.framebuffer;
|
|
const currentFramebuffer = framebufferSys.current;
|
|
|
|
// Binding our render texture to the framebuffer
|
|
framebufferSys.bind(this.framebufferTexture.framebuffer, framebufferSys.viewport);
|
|
// Current framebuffer is binded as a read framebuffer (to prepare the blit)
|
|
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb?.glFramebuffers[framebufferSys.CONTEXT_UID].framebuffer);
|
|
// Blit current framebuffer into our render texture
|
|
gl.blitFramebuffer(srcX, srcY, srcX2, srcY2, dstX, dstY, dstX2, dstY2, gl.COLOR_BUFFER_BIT, gl.NEAREST);
|
|
// Restore original behavior
|
|
framebufferSys.bind(currentFramebuffer, framebufferSys.viewport);
|
|
|
|
return this.framebufferTexture;
|
|
}
|
|
|
|
/* ---------------------------------------- */
|
|
|
|
/**
|
|
* Create a render texture, provide a render method and an optional clear color.
|
|
* @returns {PIXI.RenderTexture} A reference to the created render texture.
|
|
*/
|
|
static #createRenderTexture() {
|
|
const renderer = canvas.app?.renderer;
|
|
return PIXI.RenderTexture.create({
|
|
width: renderer?.screen.width ?? window.innerWidth,
|
|
height: renderer?.screen.height ?? window.innerHeight,
|
|
resolution: renderer.resolution ?? PIXI.settings.RESOLUTION
|
|
});
|
|
}
|
|
}
|