UNPKG

playcanvas

Version:

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

127 lines (126 loc) 3.31 kB
import { path } from "../../core/path.js"; import { http, Http } from "../../platform/net/http.js"; import { getDefaultMaterial } from "../../scene/materials/default-material.js"; import { GlbModelParser } from "../parsers/glb-model.js"; import { JsonModelParser } from "../parsers/json-model.js"; import { ResourceHandler } from "./handler.js"; class ModelHandler extends ResourceHandler { constructor(app) { super(app, "model"); this._parsers = []; this.device = app.graphicsDevice; this.assets = app.assets; this.defaultMaterial = getDefaultMaterial(this.device); this.addParser(new JsonModelParser(this), (url, data) => { return path.getExtension(url) === ".json"; }); this.addParser(new GlbModelParser(this), (url, data) => { return path.getExtension(url) === ".glb"; }); } load(url, callback, asset) { if (typeof url === "string") { url = { load: url, original: url }; } const options = { retry: this.maxRetries > 0, maxRetries: this.maxRetries }; if (url.load.startsWith("blob:") || url.load.startsWith("data:")) { if (path.getExtension(url.original).toLowerCase() === ".glb") { options.responseType = Http.ResponseType.ARRAY_BUFFER; } else { options.responseType = Http.ResponseType.JSON; } } http.get(url.load, options, (err, response) => { if (!callback) { return; } if (!err) { for (let i = 0; i < this._parsers.length; i++) { const p = this._parsers[i]; if (p.decider(url.original, response)) { p.parser.parse(response, (err2, parseResult) => { if (err2) { callback(err2); } else { callback(null, parseResult); } }, asset); return; } } callback("No parsers found"); } else { callback(`Error loading model: ${url.original} [${err}]`); } }); } open(url, data) { return data; } patch(asset, assets) { if (!asset.resource) { return; } const data = asset.data; const self = this; asset.resource.meshInstances.forEach((meshInstance, i) => { if (data.mapping) { const handleMaterial = function(asset2) { if (asset2.resource) { meshInstance.material = asset2.resource; } else { asset2.once("load", handleMaterial); assets.load(asset2); } asset2.once("remove", (asset3) => { if (meshInstance.material === asset3.resource) { meshInstance.material = self.defaultMaterial; } }); }; if (!data.mapping[i]) { meshInstance.material = self.defaultMaterial; return; } const id = data.mapping[i].material; const url = data.mapping[i].path; let material; if (id !== void 0) { if (!id) { meshInstance.material = self.defaultMaterial; } else { material = assets.get(id); if (material) { handleMaterial(material); } else { assets.once(`add:${id}`, handleMaterial); } } } else if (url) { const path2 = asset.getAbsoluteUrl(data.mapping[i].path); material = assets.getByUrl(path2); if (material) { handleMaterial(material); } else { assets.once(`add:url:${path2}`, handleMaterial); } } } }); } addParser(parser, decider) { this._parsers.push({ parser, decider }); } } export { ModelHandler };