@pixi/core
Version:
Core PixiJS
294 lines (291 loc) • 9.51 kB
JavaScript
import { Rectangle, Point } from '@pixi/math';
import { settings } from '@pixi/settings';
import { EventEmitter, TextureCache, uid, getResolutionOfUrl } from '@pixi/utils';
import { BaseTexture } from './BaseTexture.mjs';
import { ImageResource } from './resources/ImageResource.mjs';
import { TextureUvs } from './TextureUvs.mjs';
const DEFAULT_UVS = new TextureUvs();
function removeAllHandlers(tex) {
tex.destroy = function _emptyDestroy() {
};
tex.on = function _emptyOn() {
};
tex.once = function _emptyOnce() {
};
tex.emit = function _emptyEmit() {
};
}
class Texture extends EventEmitter {
constructor(baseTexture, frame, orig, trim, rotate, anchor, borders) {
super();
this.noFrame = false;
if (!frame) {
this.noFrame = true;
frame = new Rectangle(0, 0, 1, 1);
}
if (baseTexture instanceof Texture) {
baseTexture = baseTexture.baseTexture;
}
this.baseTexture = baseTexture;
this._frame = frame;
this.trim = trim;
this.valid = false;
this._uvs = DEFAULT_UVS;
this.uvMatrix = null;
this.orig = orig || frame;
this._rotate = Number(rotate || 0);
if (rotate === true) {
this._rotate = 2;
} else if (this._rotate % 2 !== 0) {
throw new Error("attempt to use diamond-shaped UVs. If you are sure, set rotation manually");
}
this.defaultAnchor = anchor ? new Point(anchor.x, anchor.y) : new Point(0, 0);
this.defaultBorders = borders;
this._updateID = 0;
this.textureCacheIds = [];
if (!baseTexture.valid) {
baseTexture.once("loaded", this.onBaseTextureUpdated, this);
} else if (this.noFrame) {
if (baseTexture.valid) {
this.onBaseTextureUpdated(baseTexture);
}
} else {
this.frame = frame;
}
if (this.noFrame) {
baseTexture.on("update", this.onBaseTextureUpdated, this);
}
}
update() {
if (this.baseTexture.resource) {
this.baseTexture.resource.update();
}
}
onBaseTextureUpdated(baseTexture) {
if (this.noFrame) {
if (!this.baseTexture.valid) {
return;
}
this._frame.width = baseTexture.width;
this._frame.height = baseTexture.height;
this.valid = true;
this.updateUvs();
} else {
this.frame = this._frame;
}
this.emit("update", this);
}
destroy(destroyBase) {
if (this.baseTexture) {
if (destroyBase) {
const { resource } = this.baseTexture;
if (resource?.url && TextureCache[resource.url]) {
Texture.removeFromCache(resource.url);
}
this.baseTexture.destroy();
}
this.baseTexture.off("loaded", this.onBaseTextureUpdated, this);
this.baseTexture.off("update", this.onBaseTextureUpdated, this);
this.baseTexture = null;
}
this._frame = null;
this._uvs = null;
this.trim = null;
this.orig = null;
this.valid = false;
Texture.removeFromCache(this);
this.textureCacheIds = null;
}
clone() {
const clonedFrame = this._frame.clone();
const clonedOrig = this._frame === this.orig ? clonedFrame : this.orig.clone();
const clonedTexture = new Texture(this.baseTexture, !this.noFrame && clonedFrame, clonedOrig, this.trim?.clone(), this.rotate, this.defaultAnchor, this.defaultBorders);
if (this.noFrame) {
clonedTexture._frame = clonedFrame;
}
return clonedTexture;
}
updateUvs() {
if (this._uvs === DEFAULT_UVS) {
this._uvs = new TextureUvs();
}
this._uvs.set(this._frame, this.baseTexture, this.rotate);
this._updateID++;
}
static from(source, options = {}, strict = settings.STRICT_TEXTURE_CACHE) {
const isFrame = typeof source === "string";
let cacheId = null;
if (isFrame) {
cacheId = source;
} else if (source instanceof BaseTexture) {
if (!source.cacheId) {
const prefix = options?.pixiIdPrefix || "pixiid";
source.cacheId = `${prefix}-${uid()}`;
BaseTexture.addToCache(source, source.cacheId);
}
cacheId = source.cacheId;
} else {
if (!source._pixiId) {
const prefix = options?.pixiIdPrefix || "pixiid";
source._pixiId = `${prefix}_${uid()}`;
}
cacheId = source._pixiId;
}
let texture = TextureCache[cacheId];
if (isFrame && strict && !texture) {
throw new Error(`The cacheId "${cacheId}" does not exist in TextureCache.`);
}
if (!texture && !(source instanceof BaseTexture)) {
if (!options.resolution) {
options.resolution = getResolutionOfUrl(source);
}
texture = new Texture(new BaseTexture(source, options));
texture.baseTexture.cacheId = cacheId;
BaseTexture.addToCache(texture.baseTexture, cacheId);
Texture.addToCache(texture, cacheId);
} else if (!texture && source instanceof BaseTexture) {
texture = new Texture(source);
Texture.addToCache(texture, cacheId);
}
return texture;
}
static fromURL(url, options) {
const resourceOptions = Object.assign({ autoLoad: false }, options?.resourceOptions);
const texture = Texture.from(url, Object.assign({ resourceOptions }, options), false);
const resource = texture.baseTexture.resource;
if (texture.baseTexture.valid) {
return Promise.resolve(texture);
}
return resource.load().then(() => Promise.resolve(texture));
}
static fromBuffer(buffer, width, height, options) {
return new Texture(BaseTexture.fromBuffer(buffer, width, height, options));
}
static fromLoader(source, imageUrl, name, options) {
const baseTexture = new BaseTexture(source, Object.assign({
scaleMode: BaseTexture.defaultOptions.scaleMode,
resolution: getResolutionOfUrl(imageUrl)
}, options));
const { resource } = baseTexture;
if (resource instanceof ImageResource) {
resource.url = imageUrl;
}
const texture = new Texture(baseTexture);
if (!name) {
name = imageUrl;
}
BaseTexture.addToCache(texture.baseTexture, name);
Texture.addToCache(texture, name);
if (name !== imageUrl) {
BaseTexture.addToCache(texture.baseTexture, imageUrl);
Texture.addToCache(texture, imageUrl);
}
if (texture.baseTexture.valid) {
return Promise.resolve(texture);
}
return new Promise((resolve) => {
texture.baseTexture.once("loaded", () => resolve(texture));
});
}
static addToCache(texture, id) {
if (id) {
if (!texture.textureCacheIds.includes(id)) {
texture.textureCacheIds.push(id);
}
if (TextureCache[id] && TextureCache[id] !== texture) {
console.warn(`Texture added to the cache with an id [${id}] that already had an entry`);
}
TextureCache[id] = texture;
}
}
static removeFromCache(texture) {
if (typeof texture === "string") {
const textureFromCache = TextureCache[texture];
if (textureFromCache) {
const index = textureFromCache.textureCacheIds.indexOf(texture);
if (index > -1) {
textureFromCache.textureCacheIds.splice(index, 1);
}
delete TextureCache[texture];
return textureFromCache;
}
} else if (texture?.textureCacheIds) {
for (let i = 0; i < texture.textureCacheIds.length; ++i) {
if (TextureCache[texture.textureCacheIds[i]] === texture) {
delete TextureCache[texture.textureCacheIds[i]];
}
}
texture.textureCacheIds.length = 0;
return texture;
}
return null;
}
get resolution() {
return this.baseTexture.resolution;
}
get frame() {
return this._frame;
}
set frame(frame) {
this._frame = frame;
this.noFrame = false;
const { x, y, width, height } = frame;
const xNotFit = x + width > this.baseTexture.width;
const yNotFit = y + height > this.baseTexture.height;
if (xNotFit || yNotFit) {
const relationship = xNotFit && yNotFit ? "and" : "or";
const errorX = `X: ${x} + ${width} = ${x + width} > ${this.baseTexture.width}`;
const errorY = `Y: ${y} + ${height} = ${y + height} > ${this.baseTexture.height}`;
throw new Error(`Texture Error: frame does not fit inside the base Texture dimensions: ${errorX} ${relationship} ${errorY}`);
}
this.valid = width && height && this.baseTexture.valid;
if (!this.trim && !this.rotate) {
this.orig = frame;
}
if (this.valid) {
this.updateUvs();
}
}
get rotate() {
return this._rotate;
}
set rotate(rotate) {
this._rotate = rotate;
if (this.valid) {
this.updateUvs();
}
}
get width() {
return this.orig.width;
}
get height() {
return this.orig.height;
}
castToBaseTexture() {
return this.baseTexture;
}
static get EMPTY() {
if (!Texture._EMPTY) {
Texture._EMPTY = new Texture(new BaseTexture());
removeAllHandlers(Texture._EMPTY);
removeAllHandlers(Texture._EMPTY.baseTexture);
}
return Texture._EMPTY;
}
static get WHITE() {
if (!Texture._WHITE) {
const canvas = settings.ADAPTER.createCanvas(16, 16);
const context = canvas.getContext("2d");
canvas.width = 16;
canvas.height = 16;
context.fillStyle = "white";
context.fillRect(0, 0, 16, 16);
Texture._WHITE = new Texture(BaseTexture.from(canvas));
removeAllHandlers(Texture._WHITE);
removeAllHandlers(Texture._WHITE.baseTexture);
}
return Texture._WHITE;
}
}
export { Texture };
//# sourceMappingURL=Texture.mjs.map