UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

189 lines (188 loc) 6.39 kB
import { path } from "../../core/path.js"; import { Vec2 } from "../../core/math/vec2.js"; import { Vec4 } from "../../core/math/vec4.js"; import { ADDRESS_CLAMP_TO_EDGE, ADDRESS_MIRRORED_REPEAT, ADDRESS_REPEAT, FILTER_LINEAR, FILTER_NEAREST, FILTER_NEAREST_MIPMAP_NEAREST, FILTER_NEAREST_MIPMAP_LINEAR, FILTER_LINEAR_MIPMAP_NEAREST, FILTER_LINEAR_MIPMAP_LINEAR, TEXTURETYPE_DEFAULT, TEXTURETYPE_RGBM } from "../../platform/graphics/constants.js"; import { http } from "../../platform/net/http.js"; import { TextureAtlas } from "../../scene/texture-atlas.js"; import { ResourceHandler } from "./handler.js"; const JSON_ADDRESS_MODE = { "repeat": ADDRESS_REPEAT, "clamp": ADDRESS_CLAMP_TO_EDGE, "mirror": ADDRESS_MIRRORED_REPEAT }; const JSON_FILTER_MODE = { "nearest": FILTER_NEAREST, "linear": FILTER_LINEAR, "nearest_mip_nearest": FILTER_NEAREST_MIPMAP_NEAREST, "linear_mip_nearest": FILTER_LINEAR_MIPMAP_NEAREST, "nearest_mip_linear": FILTER_NEAREST_MIPMAP_LINEAR, "linear_mip_linear": FILTER_LINEAR_MIPMAP_LINEAR }; const regexFrame = /^data\.frames\.(\d+)$/; class TextureAtlasHandler extends ResourceHandler { constructor(app) { super(app, "textureatlas"); this._loader = app.loader; } // Load the texture atlas texture using the texture resource loader load(url, callback) { if (typeof url === "string") { url = { load: url, original: url }; } const self = this; const handler = this._loader.getHandler("texture"); if (path.getExtension(url.original) === ".json") { http.get(url.load, { retry: this.maxRetries > 0, maxRetries: this.maxRetries }, (err, response) => { if (!err) { const textureUrl = url.original.replace(".json", ".png"); self._loader.load(textureUrl, "texture", (err2, texture) => { if (err2) { callback(err2); } else { callback(null, { data: response, texture }); } }); } else { callback(err); } }); } else { handler.load(url, callback); } } // Create texture atlas resource using the texture from the texture loader open(url, data, asset) { const resource = new TextureAtlas(); if (data.texture && data.data) { resource.texture = data.texture; resource.__data = data.data; } else { const handler = this._loader.getHandler("texture"); const texture = handler.open(url, data, asset); if (!texture) return null; resource.texture = texture; } return resource; } patch(asset, assets) { if (!asset.resource) { return; } if (asset.resource.__data) { if (asset.resource.__data.minfilter !== void 0) asset.data.minfilter = asset.resource.__data.minfilter; if (asset.resource.__data.magfilter !== void 0) asset.data.magfilter = asset.resource.__data.magfilter; if (asset.resource.__data.addressu !== void 0) asset.data.addressu = asset.resource.__data.addressu; if (asset.resource.__data.addressv !== void 0) asset.data.addressv = asset.resource.__data.addressv; if (asset.resource.__data.mipmaps !== void 0) asset.data.mipmaps = asset.resource.__data.mipmaps; if (asset.resource.__data.anisotropy !== void 0) asset.data.anisotropy = asset.resource.__data.anisotropy; if (asset.resource.__data.rgbm !== void 0) asset.data.rgbm = !!asset.resource.__data.rgbm; asset.data.frames = asset.resource.__data.frames; delete asset.resource.__data; } const texture = asset.resource.texture; if (texture) { texture.name = asset.name; if (asset.data.hasOwnProperty("minfilter") && texture.minFilter !== JSON_FILTER_MODE[asset.data.minfilter]) { texture.minFilter = JSON_FILTER_MODE[asset.data.minfilter]; } if (asset.data.hasOwnProperty("magfilter") && texture.magFilter !== JSON_FILTER_MODE[asset.data.magfilter]) { texture.magFilter = JSON_FILTER_MODE[asset.data.magfilter]; } if (asset.data.hasOwnProperty("addressu") && texture.addressU !== JSON_ADDRESS_MODE[asset.data.addressu]) { texture.addressU = JSON_ADDRESS_MODE[asset.data.addressu]; } if (asset.data.hasOwnProperty("addressv") && texture.addressV !== JSON_ADDRESS_MODE[asset.data.addressv]) { texture.addressV = JSON_ADDRESS_MODE[asset.data.addressv]; } if (asset.data.hasOwnProperty("mipmaps") && texture.mipmaps !== asset.data.mipmaps) { texture.mipmaps = asset.data.mipmaps; } if (asset.data.hasOwnProperty("anisotropy") && texture.anisotropy !== asset.data.anisotropy) { texture.anisotropy = asset.data.anisotropy; } if (asset.data.hasOwnProperty("rgbm")) { const type = asset.data.rgbm ? TEXTURETYPE_RGBM : TEXTURETYPE_DEFAULT; if (texture.type !== type) { texture.type = type; } } } asset.resource.texture = texture; const frames = {}; for (const key in asset.data.frames) { const frame = asset.data.frames[key]; frames[key] = { rect: new Vec4(frame.rect), pivot: new Vec2(frame.pivot), border: new Vec4(frame.border) }; } asset.resource.frames = frames; asset.off("change", this._onAssetChange, this); asset.on("change", this._onAssetChange, this); } _onAssetChange(asset, attribute, value) { let frame; if (attribute === "data" || attribute === "data.frames") { const frames = {}; for (const key in value.frames) { frame = value.frames[key]; frames[key] = { rect: new Vec4(frame.rect), pivot: new Vec2(frame.pivot), border: new Vec4(frame.border) }; } asset.resource.frames = frames; } else { const match = attribute.match(regexFrame); if (match) { const frameKey = match[1]; if (value) { if (!asset.resource.frames[frameKey]) { asset.resource.frames[frameKey] = { rect: new Vec4(value.rect), pivot: new Vec2(value.pivot), border: new Vec4(value.border) }; } else { frame = asset.resource.frames[frameKey]; frame.rect.set(value.rect[0], value.rect[1], value.rect[2], value.rect[3]); frame.pivot.set(value.pivot[0], value.pivot[1]); frame.border.set(value.border[0], value.border[1], value.border[2], value.border[3]); } asset.resource.fire("set:frame", frameKey, asset.resource.frames[frameKey]); } else { if (asset.resource.frames[frameKey]) { delete asset.resource.frames[frameKey]; asset.resource.fire("remove:frame", frameKey); } } } } } } export { TextureAtlasHandler };