Files
nothoughts/node_modules/pixi.js/lib/rendering/renderers/gl/texture/GlTextureSystem.js
2025-08-04 18:57:35 +02:00

269 lines
9.8 KiB
JavaScript

'use strict';
var adapter = require('../../../../environment/adapter.js');
var Extensions = require('../../../../extensions/Extensions.js');
var Texture = require('../../shared/texture/Texture.js');
var GlTexture = require('./GlTexture.js');
var glUploadBufferImageResource = require('./uploaders/glUploadBufferImageResource.js');
var glUploadCompressedTextureResource = require('./uploaders/glUploadCompressedTextureResource.js');
var glUploadImageResource = require('./uploaders/glUploadImageResource.js');
var glUploadVideoResource = require('./uploaders/glUploadVideoResource.js');
var applyStyleParams = require('./utils/applyStyleParams.js');
var mapFormatToGlFormat = require('./utils/mapFormatToGlFormat.js');
var mapFormatToGlInternalFormat = require('./utils/mapFormatToGlInternalFormat.js');
var mapFormatToGlType = require('./utils/mapFormatToGlType.js');
require('./utils/unpremultiplyAlpha.js');
"use strict";
const BYTES_PER_PIXEL = 4;
class GlTextureSystem {
constructor(renderer) {
this.managedTextures = [];
this._glTextures = /* @__PURE__ */ Object.create(null);
this._glSamplers = /* @__PURE__ */ Object.create(null);
this._boundTextures = [];
this._activeTextureLocation = -1;
this._boundSamplers = /* @__PURE__ */ Object.create(null);
this._uploads = {
image: glUploadImageResource.glUploadImageResource,
buffer: glUploadBufferImageResource.glUploadBufferImageResource,
video: glUploadVideoResource.glUploadVideoResource,
compressed: glUploadCompressedTextureResource.glUploadCompressedTextureResource
};
// TODO - separate samplers will be a cool thing to add, but not right now!
this._useSeparateSamplers = false;
this._renderer = renderer;
}
contextChange(gl) {
this._gl = gl;
if (!this._mapFormatToInternalFormat) {
this._mapFormatToInternalFormat = mapFormatToGlInternalFormat.mapFormatToGlInternalFormat(gl, this._renderer.context.extensions);
this._mapFormatToType = mapFormatToGlType.mapFormatToGlType(gl);
this._mapFormatToFormat = mapFormatToGlFormat.mapFormatToGlFormat(gl);
}
this._glTextures = /* @__PURE__ */ Object.create(null);
this._glSamplers = /* @__PURE__ */ Object.create(null);
this._boundSamplers = /* @__PURE__ */ Object.create(null);
for (let i = 0; i < 16; i++) {
this.bind(Texture.Texture.EMPTY, i);
}
}
initSource(source) {
this.bind(source);
}
bind(texture, location = 0) {
const source = texture.source;
if (texture) {
this.bindSource(source, location);
if (this._useSeparateSamplers) {
this._bindSampler(source.style, location);
}
} else {
this.bindSource(null, location);
if (this._useSeparateSamplers) {
this._bindSampler(null, location);
}
}
}
bindSource(source, location = 0) {
const gl = this._gl;
source._touched = this._renderer.textureGC.count;
if (this._boundTextures[location] !== source) {
this._boundTextures[location] = source;
this._activateLocation(location);
source = source || Texture.Texture.EMPTY.source;
const glTexture = this.getGlSource(source);
gl.bindTexture(glTexture.target, glTexture.texture);
}
}
_bindSampler(style, location = 0) {
const gl = this._gl;
if (!style) {
this._boundSamplers[location] = null;
gl.bindSampler(location, null);
return;
}
const sampler = this._getGlSampler(style);
if (this._boundSamplers[location] !== sampler) {
this._boundSamplers[location] = sampler;
gl.bindSampler(location, sampler);
}
}
unbind(texture) {
const source = texture.source;
const boundTextures = this._boundTextures;
const gl = this._gl;
for (let i = 0; i < boundTextures.length; i++) {
if (boundTextures[i] === source) {
this._activateLocation(i);
const glTexture = this.getGlSource(source);
gl.bindTexture(glTexture.target, null);
boundTextures[i] = null;
}
}
}
_activateLocation(location) {
if (this._activeTextureLocation !== location) {
this._activeTextureLocation = location;
this._gl.activeTexture(this._gl.TEXTURE0 + location);
}
}
_initSource(source) {
const gl = this._gl;
const glTexture = new GlTexture.GlTexture(gl.createTexture());
glTexture.type = this._mapFormatToType[source.format];
glTexture.internalFormat = this._mapFormatToInternalFormat[source.format];
glTexture.format = this._mapFormatToFormat[source.format];
if (source.autoGenerateMipmaps && (this._renderer.context.supports.nonPowOf2mipmaps || source.isPowerOfTwo)) {
const biggestDimension = Math.max(source.width, source.height);
source.mipLevelCount = Math.floor(Math.log2(biggestDimension)) + 1;
}
this._glTextures[source.uid] = glTexture;
if (!this.managedTextures.includes(source)) {
source.on("update", this.onSourceUpdate, this);
source.on("resize", this.onSourceUpdate, this);
source.on("styleChange", this.onStyleChange, this);
source.on("destroy", this.onSourceDestroy, this);
source.on("unload", this.onSourceUnload, this);
source.on("updateMipmaps", this.onUpdateMipmaps, this);
this.managedTextures.push(source);
}
this.onSourceUpdate(source);
this.updateStyle(source, false);
return glTexture;
}
onStyleChange(source) {
this.updateStyle(source, false);
}
updateStyle(source, firstCreation) {
const gl = this._gl;
const glTexture = this.getGlSource(source);
gl.bindTexture(gl.TEXTURE_2D, glTexture.texture);
this._boundTextures[this._activeTextureLocation] = source;
applyStyleParams.applyStyleParams(
source.style,
gl,
source.mipLevelCount > 1,
this._renderer.context.extensions.anisotropicFiltering,
"texParameteri",
gl.TEXTURE_2D,
// will force a clamp to edge if the texture is not a power of two
!this._renderer.context.supports.nonPowOf2wrapping && !source.isPowerOfTwo,
firstCreation
);
}
onSourceUnload(source) {
const glTexture = this._glTextures[source.uid];
if (!glTexture)
return;
this.unbind(source);
this._glTextures[source.uid] = null;
this._gl.deleteTexture(glTexture.texture);
}
onSourceUpdate(source) {
const gl = this._gl;
const glTexture = this.getGlSource(source);
gl.bindTexture(gl.TEXTURE_2D, glTexture.texture);
this._boundTextures[this._activeTextureLocation] = source;
if (this._uploads[source.uploadMethodId]) {
this._uploads[source.uploadMethodId].upload(source, glTexture, gl, this._renderer.context.webGLVersion);
} else {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, source.pixelWidth, source.pixelHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
}
if (source.autoGenerateMipmaps && source.mipLevelCount > 1) {
this.onUpdateMipmaps(source, false);
}
}
onUpdateMipmaps(source, bind = true) {
if (bind)
this.bindSource(source, 0);
const glTexture = this.getGlSource(source);
this._gl.generateMipmap(glTexture.target);
}
onSourceDestroy(source) {
source.off("destroy", this.onSourceDestroy, this);
source.off("update", this.onSourceUpdate, this);
source.off("resize", this.onSourceUpdate, this);
source.off("unload", this.onSourceUnload, this);
source.off("styleChange", this.onStyleChange, this);
source.off("updateMipmaps", this.onUpdateMipmaps, this);
this.managedTextures.splice(this.managedTextures.indexOf(source), 1);
this.onSourceUnload(source);
}
_initSampler(style) {
const gl = this._gl;
const glSampler = this._gl.createSampler();
this._glSamplers[style._resourceId] = glSampler;
applyStyleParams.applyStyleParams(
style,
gl,
this._boundTextures[this._activeTextureLocation].mipLevelCount > 1,
this._renderer.context.extensions.anisotropicFiltering,
"samplerParameteri",
glSampler,
false,
true
);
return this._glSamplers[style._resourceId];
}
_getGlSampler(sampler) {
return this._glSamplers[sampler._resourceId] || this._initSampler(sampler);
}
getGlSource(source) {
return this._glTextures[source.uid] || this._initSource(source);
}
generateCanvas(texture) {
const { pixels, width, height } = this.getPixels(texture);
const canvas = adapter.DOMAdapter.get().createCanvas();
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
if (ctx) {
const imageData = ctx.createImageData(width, height);
imageData.data.set(pixels);
ctx.putImageData(imageData, 0, 0);
}
return canvas;
}
getPixels(texture) {
const resolution = texture.source.resolution;
const frame = texture.frame;
const width = Math.max(Math.round(frame.width * resolution), 1);
const height = Math.max(Math.round(frame.height * resolution), 1);
const pixels = new Uint8Array(BYTES_PER_PIXEL * width * height);
const renderer = this._renderer;
const renderTarget = renderer.renderTarget.getRenderTarget(texture);
const glRenterTarget = renderer.renderTarget.getGpuRenderTarget(renderTarget);
const gl = renderer.gl;
gl.bindFramebuffer(gl.FRAMEBUFFER, glRenterTarget.resolveTargetFramebuffer);
gl.readPixels(
Math.round(frame.x * resolution),
Math.round(frame.y * resolution),
width,
height,
gl.RGBA,
gl.UNSIGNED_BYTE,
pixels
);
if (false) {
unpremultiplyAlpha(pixels);
}
return { pixels: new Uint8ClampedArray(pixels.buffer), width, height };
}
destroy() {
this.managedTextures.slice().forEach((source) => this.onSourceDestroy(source));
this.managedTextures = null;
this._renderer = null;
}
}
/** @ignore */
GlTextureSystem.extension = {
type: [
Extensions.ExtensionType.WebGLSystem
],
name: "texture"
};
exports.GlTextureSystem = GlTextureSystem;
//# sourceMappingURL=GlTextureSystem.js.map