UNPKG

@tolokoban/tgd

Version:

ToloGameDev library for WebGL2

306 lines 23.3 kB
import { TgdCameraPerspective } from "./../camera/index.js"; import { TgdInputs } from "./../input/index.js"; import { TgdPainterGroup } from "../painter/group.js"; import { tgdCanvasCreate } 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 acts as a resource manager for most of the WebGL2 reources you need. * * @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 { /** * @param canvas The canvas to which attach a WebGL2 context. * @see {@link TgdContextOptions} */ constructor(canvas, options = {}) { var _a; this.canvas = canvas; this.options = options; this.eventPaint = new TgdEvent(); this._camera = new TgdCameraPerspective({ transfo: { distance: 15 }, far: 100, near: 0.1, fovy: Math.PI / 8, zoom: 1, }); this._aspectRatio = 1; this._aspectRatioInverse = 1; this.isPlaying = false; this.requestAnimationFrame = -1; // Last time the context has been painted. this.lastTime = -1; // Difference between `Data.now()` and the time in `requestAnimationFrame()`. this.timeShift = 0; this.animationManager = new TgdManagerAnimation(); /** * Trigger the painters to render the scene. */ this.paint = () => { // globalThis.cancelAnimationFrame(this.requestAnimationFrame) this.requestAnimationFrame = globalThis.requestAnimationFrame(this.actualPaint); }; this.actualPaint = (time) => { this.timeShift = time - Date.now(); const { lastTime, gl } = this; if (lastTime < 0) { this.lastTime = time; // First frame, let's skip it to get better timing. this.paint(); return; } const delay = time - this.lastTime; // Prevent too many painting in the same refresh. if (delay < 1.016) return; this.lastTime = time; this._camera.screenWidth = gl.drawingBufferWidth; this._camera.screenHeight = gl.drawingBufferHeight; this._aspectRatio = gl.drawingBufferWidth / gl.drawingBufferHeight; this._aspectRatioInverse = 1 / this._aspectRatio; const timeInSec = time * 1e-3; const delayInSec = delay * 1e-3; this.painters.paint(timeInSec, delayInSec); if (this.animationManager.paint(timeInSec) || this.isPlaying) this.paint(); this.eventPaint.dispatch(this); }; const gl = canvas.getContext("webgl2", options); if (!gl) throw new Error("Unable to create a WebGL2 context!"); 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(() => { var _a; const width = canvas.clientWidth; const height = canvas.clientHeight; canvas.width = width; canvas.height = height; gl.viewport(0, 0, width, height); this.paint(); (_a = options.onResize) === null || _a === void 0 ? void 0 : _a.call(options, this, canvas.clientWidth, canvas.clientHeight); }); this.observer.observe(canvas); this.inputs = new TgdInputs(canvas); if (options.camera) this._camera = options.camera; this.painters = new TgdPainterGroup(); this.name = (_a = options.name) !== null && _a !== void 0 ? _a : `Context#${TgdContext.incrementalId++}`; this.painters.name = this.name; // Prevent system gestures. canvas.style.touchAction = "none"; } get time() { return Date.now() + this.timeShift; } debugHierarchy() { return this.painters.debugHierarchy(); } get camera() { return this._camera; } set camera(camera) { if (camera === this._camera) return; this._camera = camera; this.paint(); } animSchedule(animation) { const result = this.animationManager.schedule(animation); this.paint(); return result; } animCancel(animation) { this.animationManager.cancel(animation); } get onEnter() { return this.painters.onEnter; } set onEnter(v) { this.painters.onEnter = v; } get onExit() { return this.painters.onExit; } set onExit(v) { this.painters.onExit = v; } 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(); this.isPlaying = value; } /** * Start the animation. * You can achieve the same result with `context.playing = true`. * * @see playing */ play() { this.playing = true; } /** * Pause the animation. * You can achieve the same result with `context.playing = false`. * * @see playing */ pause() { this.playing = false; } /** * Check if `painter` already exist in the current list of painters. */ has(painter) { return this.painters.has(painter); } /** * Add one or more painters. */ add(...painters) { this.painters.add(...painters); } /** * Add one or more painters at the beginning of the list. */ addFirst(...painters) { this.painters.addFirst(...painters); } /** * Remove one or more painters. * */ remove(...painters) { this.painters.remove(...painters); } removeAll() { this.painters.removeAll(); } takeSnapshot(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.painters.forEachChild(painter => context.add(painter)); context.actualPaint(this.lastTime); 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}]`; } destroy() { globalThis.cancelAnimationFrame(this.requestAnimationFrame); this.playing = false; this.painters.delete(); this.observer.unobserve(this.canvas); } 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb250ZXh0L2NvbnRleHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFhLG9CQUFvQixFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQzdELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFFdEMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGtCQUFrQixDQUFBO0FBRWxELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxVQUFVLENBQUE7QUFDMUMsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sK0JBQStCLENBQUE7QUFFbkUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQThCbkM7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBaUJHO0FBQ0gsTUFBTSxPQUFPLFVBQVU7SUE2Qm5COzs7T0FHRztJQUNILFlBQ29CLE1BQXlCLEVBQ3hCLFVBQTZCLEVBQUU7O1FBRGhDLFdBQU0sR0FBTixNQUFNLENBQW1CO1FBQ3hCLFlBQU8sR0FBUCxPQUFPLENBQXdCO1FBM0JwQyxlQUFVLEdBQUcsSUFBSSxRQUFRLEVBQWMsQ0FBQTtRQUUvQyxZQUFPLEdBQWMsSUFBSSxvQkFBb0IsQ0FBQztZQUNsRCxPQUFPLEVBQUUsRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFO1lBQ3pCLEdBQUcsRUFBRSxHQUFHO1lBQ1IsSUFBSSxFQUFFLEdBQUc7WUFDVCxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsR0FBRyxDQUFDO1lBQ2pCLElBQUksRUFBRSxDQUFDO1NBQ1YsQ0FBQyxDQUFBO1FBQ00saUJBQVksR0FBRyxDQUFDLENBQUE7UUFDaEIsd0JBQW1CLEdBQUcsQ0FBQyxDQUFBO1FBR3ZCLGNBQVMsR0FBRyxLQUFLLENBQUE7UUFDakIsMEJBQXFCLEdBQUcsQ0FBQyxDQUFDLENBQUE7UUFDbEMsMENBQTBDO1FBQ2xDLGFBQVEsR0FBRyxDQUFDLENBQUMs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