From 718d66f14cee1170c92d55cc4fc620f07aa0e461 Mon Sep 17 00:00:00 2001 From: Travis Martin Date: Fri, 11 Nov 2022 22:56:54 -0600 Subject: [PATCH] Automatically update textures when necessary. --- package.json | 2 +- src/types/MeasuredIterable.ts | 1 + src/webgl/Texture.ts | 100 +++++++++++++++++++++++++++++----- src/webgl/Uniform.ts | 4 +- 4 files changed, 91 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 23d62320..3b0773b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lakuna/umbra.js", - "version": "10.1.6", + "version": "10.2.0", "description": "A lightweight visual application framework for WebGL.", "keywords": [ "front-end", diff --git a/src/types/MeasuredIterable.ts b/src/types/MeasuredIterable.ts index 4c6e9874..d76d8b69 100644 --- a/src/types/MeasuredIterable.ts +++ b/src/types/MeasuredIterable.ts @@ -1 +1,2 @@ +/** An iterable with known size. */ export default interface MeasuredIterable extends Iterable, ArrayLike { } diff --git a/src/webgl/Texture.ts b/src/webgl/Texture.ts index 8d15a679..ea9e4264 100644 --- a/src/webgl/Texture.ts +++ b/src/webgl/Texture.ts @@ -15,6 +15,8 @@ export default abstract class Texture { const texture: WebGLTexture | null = gl.createTexture(); if (!texture) { throw new Error("Failed to create a texture."); } this.texture = texture; + + this.needsUpdate = true; } /** The rendering context of this texture. */ @@ -41,13 +43,27 @@ export default abstract class Texture { } /** Updates the texels of this texture. */ - public abstract update(): void; + public update(): void { + this.updateInternal(); + this.needsUpdate = false; + } + + /** Updates the texels of this texture. */ + protected abstract updateInternal(): void; /** Generates a mipmap for this texture. */ public generateMipmap(): void { this.bind(); this.gl.generateMipmap(this.target); } + + /** Whether this texture needs to be updated. */ + protected needsUpdate: boolean; + + /** Updates this texture if necessary. */ + public updateIfNeeded(): void { + if (this.needsUpdate) { this.update(); } + } } /** Pixel sources for 2D textures. */ @@ -123,13 +139,13 @@ export class Texture2D extends Texture { wrapTFunction }: Texture2DParameters) { super(gl, target); - this.lod = lod; - this.internalFormat = internalFormat; - this.width = width; - this.height = height; - this.format = format; - this.type = type; - this.pixels = pixels; + this.lodPrivate = lod; + this.internalFormatPrivate = internalFormat; + this.widthPrivate = width; + this.heightPrivate = height; + if (format) { this.format = format; } + if (type) { this.type = type; } + this.pixelsPrivate = pixels; if (magFilter) { this.magFilter = magFilter; } if (minFilter) { this.minFilter = minFilter; } if (wrapSFunction) { this.wrapSFunction = wrapSFunction; } @@ -138,16 +154,56 @@ export class Texture2D extends Texture { } /** The level of detail of this texture. */ - public lod: number; + private lodPrivate: number; + + /** The level of detail of this texture. */ + public get lod(): number { + return this.lodPrivate; + } + + public set lod(value: number) { + this.lodPrivate = value; + this.needsUpdate = true; + } /** The format of the color components in this texture. */ - public internalFormat: TextureFormat; + private internalFormatPrivate: TextureFormat; + + /** The format of the color components in this texture. */ + public get internalFormat(): TextureFormat { + return this.internalFormatPrivate; + } + + public set internalFormat(value: TextureFormat) { + this.internalFormatPrivate = value; + this.needsUpdate = true; + } /** The width of this texture. */ - public width: number | undefined; + private widthPrivate: number | undefined; + + /** The width of this texture. */ + public get width(): number | undefined { + return this.widthPrivate; + } + + public set width(value: number | undefined) { + this.widthPrivate = value; + this.needsUpdate = true; + } + + /** The height of this texture. */ + private heightPrivate: number | undefined; /** The height of this texture. */ - public height: number | undefined; + public get height(): number | undefined { + return this.heightPrivate; + } + + public set height(value: number | undefined) { + this.heightPrivate = value; + this.needsUpdate = true; + } /** The format of the texel data. */ private formatPrivate: TextureFormat | undefined; @@ -204,6 +260,7 @@ export class Texture2D extends Texture { public set format(value: TextureFormat | undefined) { this.formatPrivate = value; + this.needsUpdate = true; } /** The data type of the components in this texture. */ @@ -253,10 +310,21 @@ export class Texture2D extends Texture { public set type(value: TextureDataType | undefined) { this.typePrivate = value; + this.needsUpdate = true; } /** The pixel source for this texture. */ - public pixels: Texture2DPixelSource; + private pixelsPrivate: Texture2DPixelSource; + + /** The pixel source for this texture. */ + public get pixels(): Texture2DPixelSource { + return this.pixelsPrivate; + } + + public set pixels(value: Texture2DPixelSource) { + this.pixelsPrivate = value; + this.needsUpdate = true; + } /** The magnification filter for this texture. */ public get magFilter(): TextureFilter { @@ -267,6 +335,7 @@ export class Texture2D extends Texture { public set magFilter(value: TextureFilter) { this.bind(); this.gl.texParameteri(this.target, TEXTURE_MAG_FILTER, value); + this.needsUpdate = true; } /** The minification filter for this texture. */ @@ -278,6 +347,7 @@ export class Texture2D extends Texture { public set minFilter(value: TextureFilter) { this.bind(); this.gl.texParameteri(this.target, TEXTURE_MIN_FILTER, value); + this.needsUpdate = true; } /** The wrapping function of this texture in the S direction. */ @@ -289,6 +359,7 @@ export class Texture2D extends Texture { public set wrapSFunction(value: TextureWrapFunction) { this.bind(); this.gl.texParameteri(this.target, TEXTURE_WRAP_S, value); + this.needsUpdate = true; } /** The wrapping function of this texture in the T direction. */ @@ -300,10 +371,11 @@ export class Texture2D extends Texture { public set wrapTFunction(value: TextureWrapFunction) { this.bind(); this.gl.texParameteri(this.target, TEXTURE_WRAP_T, value); + this.needsUpdate = true; } /** Updates the texels of this texture. */ - public update(): void { + protected updateInternal(): void { this.bind(); if (this.width && this.height) { diff --git a/src/webgl/Uniform.ts b/src/webgl/Uniform.ts index 5f277582..82e19ee6 100644 --- a/src/webgl/Uniform.ts +++ b/src/webgl/Uniform.ts @@ -172,14 +172,16 @@ export class SamplerUniform extends SingleValuedUniform { public arraySetter(value: MeasuredIterable): void { const textureUnits: Int32Array = new Int32Array(value.length); for (let i = 0; i < value.length; i++) { textureUnits[i] = (this.textureUnit) + i; } - this.gl.uniform1iv(this.location, textureUnits, this.sourceOffset, this.sourceLength); for (let i = 0; i < value.length; i++) { + (value[i] as Texture).updateIfNeeded(); (value[i] as Texture).assign(textureUnits[i] as number); } + this.gl.uniform1iv(this.location, textureUnits, this.sourceOffset, this.sourceLength); } /** The setter method for this uniform. */ public setter(value: Texture): void { + value.updateIfNeeded(); value.assign(this.textureUnit); this.gl.uniform1i(this.location, this.textureUnit); }