UNPKG

@tolokoban/tgd

Version:

ToloGameDev library for WebGL2

334 lines 26.5 kB
import { TgdCameraPerspective } from "./../camera/index.js"; import { TgdInputs } from "./../input/index.js"; import { TgdPainterGroup } from "../painter/group.js"; import { tgdCanvasCreate, webglLookup } from "../utils/index.js"; import { TgdManagerAnimation } from "./animation/animation-manager.js"; import { TgdEvent } from "../event/index.js"; /** * This class gives you a [WebGL2RenderingContext](https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext) for a given canvas, * through its public readonly attribute `gl`. * * It also takes care of the canvas resizing and the animation frames. * * @example * ``` * import { TgdContext, TgdPainterClear } from "@tgd" * * export function paint(canvas: HTMLCanvasElement) { * const ctx = new TgdContext(canvas) * const clear = new TgdPainterClear(ctx, { color: [1, 0.667, 0, 1] }) * ctx.add(clear) * ctx.paint() * } * ``` */ export class TgdContext extends TgdPainterGroup { /** * @param canvas The canvas to which attach a WebGL2 context. * @see {@link TgdContextOptions} */ constructor(canvas, options = {}) { var _a, _b; super(); this.canvas = canvas; this.options = options; this.eventPaint = new TgdEvent(); this.resolution = 1; this._camera = new TgdCameraPerspective({ transfo: { distance: 15 }, far: 100, near: 0.1, fovy: Math.PI / 8, zoom: 1, }); this._fps = 0; this._aspectRatio = 1; this._aspectRatioInverse = 1; this.paintingIsOngoing = false; // We need to start another paiting after the current one is finished this.paintingIsQueued = false; this.isPlaying = false; this.requestAnimationFrame = -1; // Last time the context has been painted. this.lastTimeInSec = -1; // Difference between `Data.now()` and the time in `requestAnimationFrame()`. this.timeShift = 0; // Last time `pause()` was called. this.pauseTime = 0; // Number of seconds while we have been in pause. this.pauseAccumulation = 0; this.animationManager = new TgdManagerAnimation(); /** * Trigger the painters to render the scene. */ this.paint = () => { if (this.paintingIsOngoing) { this.paintingIsQueued = true; } else { this.paintingIsQueued = false; this.paintingIsOngoing = true; globalThis.cancelAnimationFrame(this.requestAnimationFrame); this.requestAnimationFrame = globalThis.requestAnimationFrame(this.actualPaint); } }; this.actualPaint = (time) => { let timeInSec = time * 1e-3; if (this.lastTimeInSec < 0) { this.lastTimeInSec = timeInSec; this.paintingIsOngoing = false; this.paintingIsQueued = false; // First frame, let's skip it to get better timing. this.paint(); return; } try { this.timeShift = timeInSec - this.now(); if (this.playing) { // the pause is like a frozen time. timeInSec -= this.pauseAccumulation; } const { gl } = this; const delayInSec = timeInSec - this.lastTimeInSec; this._fps = Math.round(1 / delayInSec); this.lastTimeInSec = timeInSec; this._camera.screenWidth = gl.drawingBufferWidth; this._camera.screenHeight = gl.drawingBufferHeight; this._aspectRatio = gl.drawingBufferWidth / gl.drawingBufferHeight; this._aspectRatioInverse = 1 / this._aspectRatio; super.paint(timeInSec, delayInSec); if (this.paintingIsQueued || this.animationManager.paint(timeInSec) || this.isPlaying) { this.paintingIsOngoing = false; this.paint(); } this.eventPaint.dispatch(this); } catch (error) { console.error(error); } finally { this.paintingIsOngoing = false; } }; const gl = canvas.getContext("webgl2", options); if (!gl) throw new Error("Unable to create a WebGL2 context!"); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); this.resolution = (_a = options.resolution) !== null && _a !== void 0 ? _a : 1; if (options.enableTextureFloatStorage) { gl.getExtension("EXT_color_buffer_float"); } this.implementationColorReadFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT); this.implementationColorReadType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE); this.gl = gl; this.observer = new ResizeObserver(() => { const width = canvas.clientWidth * this.resolution; const height = canvas.clientHeight * this.resolution; const { onResize } = options; if (onResize) { onResize(this, canvas.clientWidth, canvas.clientHeight); } else { canvas.width = width; canvas.height = height; } gl.viewport(0, 0, canvas.width, canvas.height); this.paint(); }); this.observer.observe(canvas); this.inputs = new TgdInputs(canvas); if (options.camera) this._camera = options.camera; this.name = (_b = options.name) !== null && _b !== void 0 ? _b : `Context#${TgdContext.incrementalId++}`; // Prevent system gestures. canvas.style.touchAction = "none"; this.stateReset(); } get fps() { return this._fps; } get time() { return this.lastTimeInSec; } get camera() { return this._camera; } set camera(camera) { if (camera === this._camera) return; this._camera = camera; this.paint(); } /** * Check if the last WebGL command has returned an error. */ checkError(caption, action) { const { gl } = this; const error = gl.getError(); if (error !== gl.NO_ERROR) { console.error(`WebGL Error in ${caption}:`, webglLookup(error)); action === null || action === void 0 ? void 0 : action(); } } animSchedule(...animations) { var _a, _b; const result = []; let delay = 0; for (const animation of animations) { const duration = animation.duration + ((_a = animation.delay) !== null && _a !== void 0 ? _a : 0); animation.delay = delay + ((_b = animation.delay) !== null && _b !== void 0 ? _b : 0); delay += duration; result.push(this.animationManager.schedule(animation)); } this.paint(); return result; } animCancel(animation) { this.animationManager.cancel(animation); } get width() { return this.gl.drawingBufferWidth; } get height() { return this.gl.drawingBufferHeight; } get aspectRatio() { return this._aspectRatio; } get aspectRatioInverse() { return this._aspectRatioInverse; } /** * Is the animation playing? */ get playing() { return this.isPlaying; } /** * If `playing` is true, the method `paint()` will be called * for every animation frame. * @see paint() */ set playing(value) { if (value === this.isPlaying) return; if (value) this.paint(); else { this.paintingIsOngoing = false; this.paintingIsQueued = false; globalThis.cancelAnimationFrame(this.requestAnimationFrame); } this.isPlaying = value; } /** * Start the animation. * You can achieve the same result with `context.playing = true`. * * @see playing */ play() { this.playing = true; if (this.pauseTime > 0) { this.pauseAccumulation += this.time - this.pauseTime; } } /** * Pause the animation. * You can achieve the same result with `context.playing = false`. * * @see playing */ pause() { this.playing = false; this.pauseTime = this.time; } takeSnapshotToCanvas(target) { const context_ = target.getContext("2d"); if (!context_) throw new Error("[TgdContext.takeSnapshot] We cannot get a 2D context for the target canvas! Maybe it already has another type of context."); const { width, height } = target; const canvas = tgdCanvasCreate(width, height); const context = new TgdContext(canvas, this.options); this.forEachChild(painter => context.add(painter)); context.actualPaint(this.lastTimeInSec * 1e3); context.gl.finish(); context_.drawImage(canvas, 0, 0); } lookupWebglConstant(value) { const { gl } = this; for (const key in gl) { if (gl[key] === value) return key; } return `Unknown gl[${value}]`; } now() { return Date.now() * 1e-3; } delete() { this.pause(); this.observer.unobserve(this.canvas); super.delete(); } stateReset() { const { gl } = this; const numberAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); const temporary = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, temporary); for (let ii = 0; ii < numberAttribs; ++ii) { gl.disableVertexAttribArray(ii); gl.vertexAttribPointer(ii, 4, gl.FLOAT, false, 0, 0); gl.vertexAttrib1f(ii, 0); } gl.deleteBuffer(temporary); const numberTextureUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS); for (let ii = 0; ii < numberTextureUnits; ++ii) { gl.activeTexture(gl.TEXTURE0 + ii); gl.bindTexture(gl.TEXTURE_CUBE_MAP, null); gl.bindTexture(gl.TEXTURE_2D, null); } gl.activeTexture(gl.TEXTURE0); gl.useProgram(null); gl.bindBuffer(gl.ARRAY_BUFFER, null); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.bindRenderbuffer(gl.RENDERBUFFER, null); gl.disable(gl.BLEND); gl.disable(gl.CULL_FACE); gl.disable(gl.DEPTH_TEST); gl.disable(gl.DITHER); gl.disable(gl.SCISSOR_TEST); gl.blendColor(0, 0, 0, 0); gl.blendEquation(gl.FUNC_ADD); gl.blendFunc(gl.ONE, gl.ZERO); gl.clearColor(0, 0, 0, 0); gl.clearDepth(1); gl.clearStencil(-1); gl.colorMask(true, true, true, true); gl.cullFace(gl.BACK); gl.depthFunc(gl.LESS); gl.depthMask(true); gl.depthRange(0, 1); gl.frontFace(gl.CCW); gl.hint(gl.GENERATE_MIPMAP_HINT, gl.DONT_CARE); gl.lineWidth(1); gl.pixelStorei(gl.PACK_ALIGNMENT, 4); gl.pixelStorei(gl.UNPACK_ALIGNMENT, 4); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.polygonOffset(0, 0); gl.sampleCoverage(1, false); gl.scissor(0, 0, gl.canvas.width, gl.canvas.height); gl.stencilFunc(gl.ALWAYS, 0, 0xffffffff); gl.stencilMask(0xffffffff); gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); return gl; } } TgdContext.incrementalId = 1; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb250ZXh0L2NvbnRleHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFhLG9CQUFvQixFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQzdELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDdEMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGtCQUFrQixDQUFBO0FBQ2xELE9BQU8sRUFBRSxlQUFlLEVBQUUsV0FBVyxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQ3ZELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLCtCQUErQixDQUFBO0FBRW5FLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxVQUFVLENBQUE7QUFtQ25DOzs7Ozs7Ozs7Ozs7Ozs7OztHQWlCRztBQUNILE1BQU0sT0FBTyxVQUFXLFNBQVEsZUFBZTtJQXFDM0M7OztPQUdHO0lBQ0gsWUFDb0IsTUFBeUIsRUFDeEIsVUFBNkIsRUFBRTs7UUFFaEQsS0FBSyxFQUFFLENBQUE7UUFIUyxXQUFNLEdBQU4sTUFBTSxDQUFtQjtRQUN4QixZQUFPLEdBQVAsT0FBTyxDQUF3QjtRQW5DcEMsZUFBVSxHQUFHLElBQUksUUFBUSxFQUFjLENBQUE7UUFDaEQsZUFBVSxHQUFHLENBQUMsQ0FBQTtRQUViLFlBQU8sR0FBYyxJQUFJLG9CQUFvQixDQUFDO1lBQ2xELE9BQU8sRUFBRSxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUU7WUFDekIsR0FBRyxFQUFFLEdBQUc7WUFDUixJQUFJLEVBQUUsR0FBRztZQUNULElBQUksRUFBRSxJQUFJLENBQUMsRUFBRSxHQUFHLENBQUM7WUFDakIsSUFBSSxFQUFFLENBQUM7U0FDVixDQUFDLENBQUE7UUFDTSxTQUFJLEdBQUcsQ0FBQyxDQUFBO1FBQ1IsaUJBQVksR0FBRyxDQUFDLENBQUE7UUFDaEIsd0JBQW1CLEdBQUcsQ0FBQyxDQUFBO1FBRXZCLHNC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