import { TextureInfo } from "./TextureInfo";
const _placeholderImage = document.createElement("img");
/**
* Texture
* @extends {TextureInfo}
* @property {boolean} isVideo
* @property {boolean} shouldUpdate
*/
export class Texture extends TextureInfo {
/**
* Creates an instance of Texture.
* @constructor
* @param {HTMLElement} source
* @param {boolean} shouldUpdate
*/
constructor(source, shouldUpdate) {
super();
this._source = _placeholderImage;
this._parseTextureSize = this._parseTextureSize.bind(this);
this.source = source;
this.shouldUpdate = shouldUpdate;
this._currentRenderTime = 0;
}
/**
* Get width
* @readonly
* @type {number}
*/
get width() {
return this._sourceWidth || 1;
}
/**
* Get height
* @readonly
* @type {number}
*/
get height() {
return this._sourceHeight || 1;
}
/**
* Set/Get source of the texture
* @type {HTMLElement}
*/
get source() {
return this._source;
}
set source(value) {
if (value) {
this._source.removeEventListener(this._eventType, this._parseTextureSize);
this._source = value;
this.isVideo = value.tagName.toLowerCase() === "video";
this._eventType = this.isVideo ? "canplay" : "load";
!this._parseTextureSize() &&
value.addEventListener(this._eventType, this._parseTextureSize, {
once: true,
});
}
}
/**
* Destruct the class
*/
destruct() {
this._source.removeEventListener(this._eventType, this._parseTextureSize);
}
/**
* Use TextureInfo
* @param {WebGLContext} gl
* @param {number} id
* @param {boolean} forceBind
* @param {number} renderTime
*/
use(gl, id, forceBind, renderTime) {
if (this.$currentAglId < gl.agl_id) {
this.$currentAglId = gl.agl_id;
this._baseTexture = gl.createTexture();
this.useActiveTexture(gl, id);
} else if (
this.$updated ||
this._loaded ||
(this.shouldUpdate && this._currentRenderTime < renderTime) ||
(this.isVideo && !this._source.paused)
) {
this.$updated = this._loaded = false;
this._currentRenderTime = renderTime;
this.useActiveTexture(gl, id);
} else if (this._currenActiveId !== id || forceBind)
this.bindActiveTexture(gl, id);
}
/**
* @readonly
* @type {number}
* @ignore
*/
get _sourceWidth() {
return this._source[this._dimensionWidthName];
}
/**
* @readonly
* @type {number}
* @ignore
*/
get _sourceHeight() {
return this._source[this._dimensionHeightName];
}
/**
* @ignore
*/
_parseTextureSize() {
this._dimensionWidthName = "width";
this._dimensionHeightName = "height";
if (this._source.naturalWidth) {
this._dimensionWidthName = "naturalWidth";
this._dimensionHeightName = "naturalHeight";
} else if (this._source.videoWidth) {
this._dimensionWidthName = "videoWidth";
this._dimensionHeightName = "videoHeight";
}
if (this._sourceWidth * this._sourceHeight) {
this.$renderSource = this._source;
this._loaded = true;
return true;
}
this.$renderSource = null;
}
}
/**
* Create a new Texture from an image source
* @function
* @param {HTMLElement} src
* @param {boolean} shouldUpdate
* @returns {Texture}
*/
Texture.loadImage = (src, shouldUpdate) => {
const image = document.createElement("img");
image.src = src;
return new Texture(image, shouldUpdate);
};
/**
* Create a new Texture from a video source
* @function
* @param {HTMLVideoElement} src
* @returns {Texture}
*/
Texture.loadVideo = (src) => {
const video = document.createElement("video");
video.src = src;
return new Texture(video);
};