Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/excaliburjs/Excalibur. 🎮 Your friendly TypeScript 2D game engine for the web 🗡️ excaliburjs.com
excalibur excaliburjs game-development game-engine game-framework gamedev games html5-canvas typescript
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218import { RenderSource } from './render-source';
declare global { interface WebGL2RenderingContext { /** * Experimental only in chrome */ drawingBufferFormat?: number; }}
export interface RenderTargetOptions { gl: WebGL2RenderingContext; width: number; height: number; transparency: boolean; /** * Optionally enable render buffer multisample anti-aliasing * * By default false */ antialias?: boolean; /** * Optionally specify number of anti-aliasing samples to use * * By default the max for the platform is used if antialias is on. */ samples?: number;}
export class RenderTarget { width: number; height: number; transparency: boolean; antialias: boolean = false; samples: number = 1; private _gl: WebGL2RenderingContext; public readonly bufferFormat: number; constructor(options: RenderTargetOptions) { this._gl = options.gl; this.width = options.width; this.height = options.height; this.transparency = options.transparency; this.antialias = options.antialias ?? this.antialias; this.samples = options.samples ?? this._gl.getParameter(this._gl.MAX_SAMPLES);
const gl = this._gl; // Determine current context format for blitting later needs to match if (gl.drawingBufferFormat) { this.bufferFormat = gl.drawingBufferFormat; } else { // Documented in webgl spec // https://registry.khronos.org/webgl/specs/latest/1.0/ if (this.transparency) { this.bufferFormat = gl.RGBA8; } else { this.bufferFormat = gl.RGB8; } }
this._setupRenderBuffer(); this._setupFramebuffer(); }
setResolution(width: number, height: number) { const gl = this._gl; this.width = width; this.height = height;
// update backing texture size gl.bindTexture(gl.TEXTURE_2D, this._frameTexture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
// update render buffer size if (this._renderBuffer) { gl.bindRenderbuffer(gl.RENDERBUFFER, this._renderBuffer); gl.renderbufferStorageMultisample( gl.RENDERBUFFER, Math.min(this.samples, gl.getParameter(gl.MAX_SAMPLES)), this.bufferFormat, this.width, this.height ); } }
private _renderBuffer!: WebGLRenderbuffer; public get renderBuffer() { return this._renderBuffer; } private _renderFrameBuffer!: WebGLFramebuffer; public get renderFrameBuffer() { return this._renderFrameBuffer; }
private _frameBuffer!: WebGLFramebuffer; public get frameBuffer() { return this._frameBuffer; } private _frameTexture!: WebGLTexture; public get frameTexture() { return this._frameTexture; }
private _setupRenderBuffer() { if (this.antialias) { const gl = this._gl; // Render buffers can be used as an input to a shader this._renderBuffer = gl.createRenderbuffer()!; this._renderFrameBuffer = gl.createFramebuffer()!; gl.bindRenderbuffer(gl.RENDERBUFFER, this._renderBuffer); gl.renderbufferStorageMultisample( gl.RENDERBUFFER, Math.min(this.samples, gl.getParameter(gl.MAX_SAMPLES)), this.bufferFormat, this.width, this.height ); gl.bindFramebuffer(gl.FRAMEBUFFER, this._renderFrameBuffer); gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, this._renderBuffer); } }
private _setupFramebuffer() { // Allocates frame buffer const gl = this._gl; this._frameTexture = gl.createTexture()!; gl.bindTexture(gl.TEXTURE_2D, this._frameTexture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
// set the filtering so we don't need mips gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// attach the texture as the first color attachment const attachmentPoint = gl.COLOR_ATTACHMENT0;
// After this bind all draw calls will draw to this framebuffer texture this._frameBuffer = gl.createFramebuffer()!; gl.bindFramebuffer(gl.FRAMEBUFFER, this._frameBuffer); gl.framebufferTexture2D(gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, this._frameTexture, 0);
// Reset after initialized this.disable(); }
public toRenderSource() { if (this.renderBuffer) { this.blitRenderBufferToFrameBuffer(); } const source = new RenderSource(this._gl, this._frameTexture); return source; }
public blitToScreen() { const gl = this._gl; // set to size of canvas's drawingBuffer if (this._renderBuffer) { gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.renderFrameBuffer); gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); gl.clearBufferfv(gl.COLOR, 0, [0.0, 0.0, 1.0, 1.0]); gl.blitFramebuffer(0, 0, this.width, this.height, 0, 0, this.width, this.height, gl.COLOR_BUFFER_BIT, gl.LINEAR); } else { gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.frameBuffer); gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); gl.clearBufferfv(gl.COLOR, 0, [0.0, 0.0, 1.0, 1.0]); gl.blitFramebuffer(0, 0, this.width, this.height, 0, 0, this.width, this.height, gl.COLOR_BUFFER_BIT, gl.LINEAR); } }
public blitRenderBufferToFrameBuffer() { if (this._renderBuffer) { const gl = this._gl; gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.renderFrameBuffer); gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.frameBuffer); gl.clearBufferfv(gl.COLOR, 0, [0.0, 0.0, 1.0, 1.0]); gl.blitFramebuffer(0, 0, this.width, this.height, 0, 0, this.width, this.height, gl.COLOR_BUFFER_BIT, gl.LINEAR); } }
public copyToTexture(texture: WebGLTexture) { const gl = this._gl; if (this._renderBuffer) { this.blitRenderBufferToFrameBuffer(); } gl.bindFramebuffer(gl.FRAMEBUFFER, this._frameBuffer); gl.bindTexture(gl.TEXTURE_2D, texture); gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, this.width, this.height, 0); }
/** * When called, all drawing gets redirected to this render target */ public use() { const gl = this._gl; if (this.antialias) { gl.bindFramebuffer(gl.FRAMEBUFFER, this._renderFrameBuffer); } else { gl.bindFramebuffer(gl.FRAMEBUFFER, this._frameBuffer); }
// very important to set the viewport to the size of the framebuffer texture gl.viewport(0, 0, this.width, this.height); }
/** * When called, all drawing is sent back to the canvas */ public disable() { const gl = this._gl; // passing null switches rendering back to the canvas gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.bindTexture(gl.TEXTURE_2D, null); }}