@tolokoban/tgd
Version:
ToloGameDev library for WebGL2
306 lines • 23.3 kB
JavaScript
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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