@tolokoban/tgd
Version:
ToloGameDev library for WebGL2
615 lines • 48.1 kB
JavaScript
import { TgdCameraPerspective } from "./../camera/index.js";
import { TgdConsole } from "./../debug/index.js";
import { TgdInputs } from "./../input/index.js";
import { TgdTime } from "./../time/index.js";
import { TgdEvent } from "../event/index.js";
import { TgdPainterGroup } from "../painter/group.js";
import { webglLookup } from "../utils/index.js";
import { TgdManagerAnimation } from "./animation/animation-manager.js";
import { Console } from "./console.js";
import { TgdExtensions } from "./extensions.js";
import { UniformBufferObjectsManager } from "./ubo-manager.js";
import { WebglParams } from "./webgl-params.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 {
/**
* Ratio of the resolution in physical pixels to the resolution in CSS pixels
* for the current display device.
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio
*/
static get devicePixelRatio() {
return globalThis.devicePixelRatio ?? 1;
}
/** When the context has been deleted, this is `true` and you can read it with `context.isDeleted`. */
/**
* @param canvas The canvas to which attach a WebGL2 context.
* @see {@link TgdContextOptions}
*/
constructor(canvas, options = {}) {
super({ name: options.name });
this.canvas = canvas;
this.options = options;
/**
* TGD will write error and warning messages to the console
* in case of problems and if `verbose` is set to `true`.
*/
this.verbose = true;
this.console = new Console(this);
this.eventResize = new TgdEvent();
/**
* Dispatched when everything has been painted.
*/
this.eventPaint = new TgdEvent();
/**
* Dispatched before anything is painted.
*/
this.eventPaintEnter = new TgdEvent();
/**
* Dispathed everytime we play or pause the main animation loop (`TgdContext.play()`, `TgdContext.pause()`).
*/
this.eventPlayingChange = new TgdEvent();
/**
* When the browser decides to destroy the context.
* @see https://wikis.khronos.org/webgl/HandlingContextLost
*/
this.eventWebGLContextLost = new TgdEvent();
/**
* At the point that setupWebGLStateAndResources is called the browser
* has reset all state to the default WebGL state and all previously
* allocated resources are invalid. So, you need to re-create textures,
* buffers, framebuffers, renderbuffers, shaders, programs,
* and setup your state (clearColor, blendFunc, depthFunc, etc...)
* @see https://wikis.khronos.org/webgl/HandlingContextLost
*/
this.eventWebGLContextRestored = new TgdEvent();
this.resolution = 1;
this.uniformBufferObjects = new UniformBufferObjectsManager();
this._gl = null;
/**
* If this function is set, it will be called once at the end of the next repaint.
* This is useful for snapshots.
*/
this.doSnapshot = null;
this._camera = new TgdCameraPerspective({
transfo: { distance: 10 },
far: 100,
near: 0.1,
fovy: Math.PI / 8,
zoom: 1,
});
this._width = 0;
this._height = 0;
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;
this.animationManager = new TgdManagerAnimation(this);
// Used to store result of gl.readPixels() for one pixel.
this.readPixelColor = new Uint8Array(4);
this.oneTimePainters = new Set();
/**
* When you need a painter to be painted only one time.
*
* These painters will be painted before all the recurrent ones during next repaint.
* The main purpose of this function is to use it with framebuffers that will
* update textures that could be used in normal paintings.
*/
this.paintOneTime = (...painters) => {
for (const painter of painters) {
this.oneTimePainters.add(painter);
}
this.paint();
};
/**
* 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) => {
const 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 {
const { gl } = this;
this.virtualTime.update(this);
this.setCurrentSize(gl.drawingBufferWidth, gl.drawingBufferHeight);
this.eventPaintEnter.dispatch(this);
const delayInSec = timeInSec - this.lastTimeInSec;
this._fps = Math.round(1 / delayInSec);
this.lastTimeInSec = timeInSec;
for (const oneTimePainter of this.oneTimePainters) {
oneTimePainter.paint(timeInSec, delayInSec);
}
this.oneTimePainters.clear();
super.paint(timeInSec, delayInSec);
if (this.animationManager.paint(timeInSec) ||
this.paintingIsQueued ||
this.isPlaying) {
this.paintingIsOngoing = false;
this.paint();
}
this.eventPaint.dispatch(this);
}
catch (error) {
this.console.error(error);
this.pause();
}
finally {
this.paintingIsOngoing = false;
this.doSnapshot?.();
}
};
this.createWebGLContext = () => {
const { canvas, options } = this;
const gl = canvas.getContext("webgl2", options);
if (!gl)
throw new Error("Unable to create a WebGL2 context!");
this._gl = gl;
gl.canvas.addEventListener("webglcontextlost", (evt) => {
// @see https://wikis.khronos.org/webgl/HandlingContextLost
evt.preventDefault();
this.console.error("[TgdContext] WebGL context has been lost!", evt instanceof WebGLContextEvent ? evt.statusMessage : evt);
this.pause();
super.delete();
this.eventWebGLContextLost.dispatch(this);
}, false);
gl.canvas.addEventListener("webglcontextrestored", () => {
this.console.info("[TgdContext] WebGL context has been restored.");
this.initialize?.(this);
this.eventWebGLContextRestored.dispatch(this);
}, false);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
this.resolution = options.resolution ?? 1;
if (this.resolution <= 0) {
this.resolution = TgdContext.devicePixelRatio ?? 1;
}
this.stateReset();
return gl;
};
this.verbose = options.verbose ?? false;
const gl = this.createWebGLContext();
this.extensions = new TgdExtensions(gl);
this.initialize = options.initialize;
canvas.addEventListener("webglcontextlost", (evt) => {
TgdConsole.debug({
text: "[TgdContext]",
color: "#fffe",
background: "#a00",
}, ` WebGL context has been lost! ${evt instanceof WebGLContextEvent ? evt.statusMessage : evt}`);
// @see https://wikis.khronos.org/webgl/HandlingContextLost
evt.preventDefault();
this.delete({ preserveContextLostEvents: true });
this.eventWebGLContextLost.dispatch(this);
}, false);
canvas.addEventListener("webglcontextrestored", () => {
TgdConsole.debug({
text: "[TgdContext]",
color: "#000e",
background: "#0f0",
}, " WebGL context has been restored");
const { initialize } = this;
if (initialize) {
this.createWebGLContext();
initialize(this);
}
this.eventWebGLContextRestored.dispatch(this);
}, false);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
this.resolution = options.resolution ?? 1;
if (this.resolution <= 0) {
this.resolution = TgdContext.devicePixelRatio ?? 1;
}
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 = isOffscreen(canvas)
? canvas.width
: canvas.clientWidth * this.resolution;
const height = isOffscreen(canvas)
? canvas.width
: canvas.clientHeight * this.resolution;
const { onResize } = options;
if (onResize) {
if (!isOffscreen(canvas)) {
onResize(this, canvas.clientWidth, canvas.clientHeight);
}
}
else {
canvas.width = width;
canvas.height = height;
}
this.eventResize.dispatch({ width, height });
this.paint();
});
if (isOffscreen(canvas)) {
this.inputs = new TgdInputs();
}
else {
this.observer.observe(canvas);
this.inputs = new TgdInputs(canvas);
// Prevent system gestures.
canvas.style.touchAction = "none";
}
if (options.camera)
this._camera = options.camera;
this.name = options.name ?? `Context#${TgdContext.incrementalId++}`;
this.stateReset();
this.webglParams = new WebglParams(gl);
this.virtualTime = new TgdTime();
this.console.debug(`[TgdContext/${this.name}] New:`, options);
}
get isDeleted() {
return !this._gl;
}
viewportExec(action, viewport) {
const { webglParams, camera } = this;
const savedWidth = this.width;
const savedHeight = this.height;
const savedViewport = webglParams.viewport;
const savedScissor = webglParams.scissor;
const savedScissorTest = webglParams.scissorTest;
const savedAspectRatio = this.width / this.height;
const savedAspectRatioInverse = 1 / savedAspectRatio;
const { x = 0, y = 0, width = savedWidth, height = savedHeight } = viewport;
this.width = width;
this.height = height;
this._aspectRatio = width / height;
this._aspectRatioInverse = 1 / this._aspectRatio;
webglParams.setViewport(x, y, width, height);
webglParams.scissorTest = true;
webglParams.scissor = [x, y, width, height];
if (camera) {
camera.screenWidth = width;
camera.screenHeight = height;
}
action();
if (camera) {
camera.screenWidth = savedWidth;
camera.screenHeight = savedHeight;
}
webglParams.scissorTest = savedScissorTest;
webglParams.scissor = savedScissor;
webglParams.viewport = savedViewport;
this._aspectRatio = savedAspectRatio;
this._aspectRatioInverse = savedAspectRatioInverse;
this.width = savedWidth;
this.height = savedHeight;
}
get gl() {
if (!this._gl) {
throw new Error(`[TgdContext] This context has been deleted: ${this.name}!`);
}
return this._gl;
}
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;
camera.screenWidth = this.width;
camera.screenHeight = this.height;
}
/**
* Check if the last WebGL command has returned an error.
* If an error has been found, output `caption` to the console (if verbose is true)
* and execute `action()`.
* Do not use this function in a loop because it is slow.
* @returns `true` is an error has been detected.
*/
checkError(caption, action) {
const { gl } = this;
const error = gl.getError();
if (error !== gl.NO_ERROR && error !== gl.CONTEXT_LOST_WEBGL) {
this.console.error(`WebGL Error in ${caption}:`, webglLookup(error));
action?.();
return true;
}
return false;
}
animSchedule(...animations) {
const result = [];
let delay = 0;
for (const animation of animations) {
const duration = animation.duration + (animation.delay ?? 0);
animation.delay = delay + (animation.delay ?? 0);
delay += duration;
result.push(this.animationManager.schedule(animation));
}
this.paint();
return result;
}
animCancel(animation) {
this.animationManager.cancel(animation);
}
animCancelArray(animations) {
for (const animation of animations)
this.animationManager.cancel(animation);
}
animDebug(caption) {
this.animationManager.debug(caption);
}
get width() {
return this._width;
}
set width(width) {
this._width = width;
}
get height() {
return this._height;
}
set height(height) {
this._height = height;
}
get aspectRatio() {
return this._aspectRatio;
}
get aspectRatioInverse() {
return this._aspectRatioInverse;
}
set aspectRatio(aspectRatio) {
this._aspectRatio = aspectRatio;
this._aspectRatioInverse = 1 / aspectRatio;
}
/**
* 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.paintingIsOngoing = false;
this.paintingIsQueued = false;
globalThis.cancelAnimationFrame(this.requestAnimationFrame);
this.requestAnimationFrame = -1;
}
this.isPlaying = value;
this.eventPlayingChange.dispatch(value);
/**
* Even when pausing, we want to paint a last time.
* This will be helpful for TgdTime, for instance.
*/
this.paint();
}
/**
* 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;
}
takeSnapshot() {
const { canvas } = this;
const img = new Image();
return new Promise((resolve) => {
const blobToImage = (blob) => {
if (!blob) {
resolve(img);
return;
}
const url = URL.createObjectURL(blob);
img.src = url;
// eslint-disable-next-line unicorn/prefer-add-event-listener
img.onload = () => resolve(img);
};
this.doSnapshot = () => {
if (isOffscreen(canvas)) {
canvas
.convertToBlob()
.then(blobToImage)
.catch(() => resolve(img));
}
else {
canvas.toBlob(blobToImage);
}
};
});
}
lookupWebglConstant(value) {
const { gl } = this;
for (const key in gl) {
if (gl[key] === value)
return key;
}
return `Unknown gl[${value}]`;
}
/**
* Helper to test a context lost situation.
* @param restorationDelayInMilliseconds Time, in milliseconds, before the context is restored.
*/
loseContext(restorationDelayInMilliseconds = 1000) {
const ext = this.extensions.WEBGL_lose_context;
if (ext) {
ext.loseContext();
globalThis.setTimeout(() => {
ext.restoreContext();
}, restorationDelayInMilliseconds);
}
}
/**
* Most of the painters rely on the current viewport which is based on the canvas size.
* But if you want to paint in a framebuffer, you may want to use the texture widt/height
* instead.
*/
paintInCustomSize(width, height, paint) {
const { width: savedWidth, height: savedHeight } = this;
this.setCurrentSize(width, height);
paint();
this.setCurrentSize(savedWidth, savedHeight);
}
setCurrentSize(width, height) {
this.width = width;
this.height = height;
this.camera.screenWidth = this.width;
this.camera.screenHeight = this.height;
this.aspectRatio = this.width / this.height;
this.webglParams.setViewport(0, 0, this.width, this.height);
}
now() {
return Date.now() * 1e-3;
}
/**
* Read the color of a pixel as a Uint8Array of size 4.
*
* Don't forget to use `preserveDrawingBuffer: true` in the creation options
* of the WebGL context.
*
* @param xScreen From -1 (left) to +1 (right)
* @param yScreen From -1 (bottom) to +1 (top)
* @returns The color of a pixel
*/
readPixel(xScreen, yScreen) {
const { gl } = this;
const pixelX = Math.round(0.5 * (xScreen + 1) * gl.drawingBufferWidth);
const pixelY = Math.round(0.5 * (yScreen + 1) * gl.drawingBufferHeight);
gl.readPixels(pixelX, pixelY, 1, // width
1, // height
gl.RGBA, // format
gl.UNSIGNED_BYTE, // type
this.readPixelColor);
return this.readPixelColor;
}
delete({ preserveContextLostEvents = false, } = {}) {
this.eventPaint.removeAllListeners();
if (!preserveContextLostEvents) {
this.eventWebGLContextLost.removeAllListeners();
this.eventWebGLContextRestored.removeAllListeners();
}
this.inputs.keyboard.detach();
this.inputs.pointer.detach();
this.pause();
if (!isOffscreen(this.canvas)) {
this.observer.unobserve(this.canvas);
}
super.delete();
this._gl = null;
this.console.debug(`[TgdContext/${this.name}] Delete`);
globalThis.cancelAnimationFrame(this.requestAnimationFrame);
}
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;
function isOffscreen(canvas) {
return canvas instanceof OffscreenCanvas;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGV4dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb250ZXh0L2NvbnRleHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFrQixvQkFBb0IsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUNsRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sWUFBWSxDQUFBO0FBQ3ZDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDdEMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUduQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQ25DLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUVsRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQ3RDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLCtCQUErQixDQUFBO0FBQ25FLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFDbkMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUM1QyxPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFDM0QsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBc0Q1Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQkc7QUFDSCxNQUFNLE9BQU8sVUFBVyxTQUFRLGVBQWU7SUFFOUM7Ozs7T0FJRztJQUNJLE1BQU0sS0FBSyxnQkFBZ0I7UUFDakMsT0FBTyxVQUFVLENBQUMsZ0JBQWdCLElBQUksQ0FBQyxDQUFBO0lBQ3hDLENBQUM7SUFnRkQsc0dBQXNHO0lBRXRHOzs7T0FHRztJQUNILFlBQ2lCLE1BQTJDLEVBQzNDLFVBQXVDLEVBQUU7UUFFekQsS0FBSyxDQUFDLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFBO1FBSGIsV0FBTSxH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