@renderlayer/loaders
Version:
@renderlayer/loaders
1,463 lines (1,451 loc) • 59.9 kB
JavaScript
import { InstancedBufferGeometry, BufferGeometry, BufferAttribute, InterleavedBufferAttribute, InstancedBufferAttribute, InterleavedBuffer } from '@renderlayer/buffers';
import { Vector3, Sphere, Color, Matrix4, Matrix3, Vector4, Vector2 } from '@renderlayer/math';
import { getTypedArray, createElementNS, SRGBColorSpace, ClampToEdgeWrapping, LinearFilter, LinearMipmapLinearFilter, UVMapping, CubeReflectionMapping, CubeRefractionMapping, EquirectangularReflectionMapping, EquirectangularRefractionMapping, CubeUVReflectionMapping, RepeatWrapping, MirroredRepeatWrapping, NearestFilter, NearestMipmapNearestFilter, NearestMipmapLinearFilter, LinearMipmapNearestFilter } from '@renderlayer/shared';
import { CubeTexture, DataTexture, Source, Texture } from '@renderlayer/textures';
import { ShadowMaterial, SpriteMaterial, RawShaderMaterial, ShaderMaterial, PointsMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshNormalMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshBasicMaterial, LineBasicMaterial, Material } from '@renderlayer/materials';
import { AnimationClip } from '@renderlayer/animation';
import { OrthographicCamera, PerspectiveCamera } from '@renderlayer/cameras';
import { Object3D } from '@renderlayer/core';
import { Scene, Fog, FogExp2 } from '@renderlayer/scenes';
import * as Geometries from '@renderlayer/geometries';
import { SpotLight, PointLight, DirectionalLight, AmbientLight } from '@renderlayer/lights';
import { Skeleton, Bone, Group, Sprite, Points, LineSegments, LineLoop, Line, LOD, InstancedMesh, Mesh, SkinnedMesh } from '@renderlayer/objects';
const Cache = {
enabled: false,
files: {},
// EP: use map
add: function(key, file) {
if (this.enabled === false)
return;
this.files[key] = file;
},
get: function(key) {
if (this.enabled === false)
return;
return this.files[key];
},
remove: function(key) {
delete this.files[key];
},
clear: function() {
this.files = {};
}
};
class LoadingManager {
constructor(onLoad, onProgress, onError) {
const scope = this;
let isLoading = false;
let itemsLoaded = 0;
let itemsTotal = 0;
let urlModifier = void 0;
const handlers = [];
this.onStart = void 0;
this.onLoad = onLoad;
this.onProgress = onProgress;
this.onError = onError;
this.itemStart = function(url) {
itemsTotal++;
if (isLoading === false) {
if (scope.onStart !== void 0) {
scope.onStart(url, itemsLoaded, itemsTotal);
}
}
isLoading = true;
};
this.itemEnd = function(url) {
itemsLoaded++;
if (scope.onProgress !== void 0) {
scope.onProgress(url, itemsLoaded, itemsTotal);
}
if (itemsLoaded === itemsTotal) {
isLoading = false;
if (scope.onLoad !== void 0) {
scope.onLoad();
}
}
};
this.itemError = function(url) {
if (scope.onError !== void 0) {
scope.onError(url);
}
};
this.resolveURL = function(url) {
if (urlModifier) {
return urlModifier(url);
}
return url;
};
this.setURLModifier = function(transform) {
urlModifier = transform;
return this;
};
this.addHandler = function(regex, loader) {
handlers.push(regex, loader);
return this;
};
this.removeHandler = function(regex) {
const index = handlers.indexOf(regex);
if (index !== -1) {
handlers.splice(index, 2);
}
return this;
};
this.getHandler = function(file) {
for (let i = 0, l = handlers.length; i < l; i += 2) {
const regex = handlers[i];
const loader = handlers[i + 1];
if (regex.global)
regex.lastIndex = 0;
if (regex.test(file)) {
return loader;
}
}
return null;
};
}
}
const DefaultLoadingManager = /* @__PURE__ */ new LoadingManager();
class Loader {
constructor(manager) {
this.manager = manager !== void 0 ? manager : DefaultLoadingManager;
this.crossOrigin = "anonymous";
this.withCredentials = false;
this.path = "";
this.resourcePath = "";
this.requestHeader = {};
}
load() {
}
loadAsync(url, onProgress) {
const scope = this;
return new Promise(function(resolve, reject) {
scope.load(url, resolve, onProgress, reject);
});
}
parse() {
}
setCrossOrigin(crossOrigin) {
this.crossOrigin = crossOrigin;
return this;
}
setWithCredentials(value) {
this.withCredentials = value;
return this;
}
setPath(path) {
this.path = path;
return this;
}
setResourcePath(resourcePath) {
this.resourcePath = resourcePath;
return this;
}
setRequestHeader(requestHeader) {
this.requestHeader = requestHeader;
return this;
}
}
const loading = {};
class HttpError extends Error {
constructor(message, response) {
super(message);
this.response = response;
}
}
class FileLoader extends Loader {
constructor(manager) {
super(manager);
}
load(url, onLoad, onProgress, onError) {
if (url === void 0)
url = "";
if (this.path !== void 0)
url = this.path + url;
url = this.manager.resolveURL(url);
const cached = Cache.get(url);
if (cached !== void 0) {
this.manager.itemStart(url);
setTimeout(() => {
if (onLoad)
onLoad(cached);
this.manager.itemEnd(url);
}, 0);
return cached;
}
if (loading[url] !== void 0) {
loading[url].push({
onLoad,
onProgress,
onError
});
return;
}
loading[url] = [];
loading[url].push({
onLoad,
onProgress,
onError
});
const req = new Request(url, {
headers: new Headers(this.requestHeader),
credentials: this.withCredentials ? "include" : "same-origin"
// An abort controller could be added within a future PR
});
const mimeType = this.mimeType;
const responseType = this.responseType;
fetch(req).then((response) => {
if (response.status === 200 || response.status === 0) {
if (response.status === 0) {
console.warn("FileLoader: HTTP Status 0 received.");
}
if (typeof ReadableStream === "undefined" || response.body === void 0 || response.body.getReader === void 0) {
return response;
}
const callbacks = loading[url];
const reader = response.body.getReader();
const contentLength = response.headers.get("Content-Length") || response.headers.get("X-File-Size");
const total = contentLength ? parseInt(contentLength) : 0;
const lengthComputable = total !== 0;
let loaded = 0;
const stream = new ReadableStream({
start(controller) {
readData();
function readData() {
reader.read().then(({ done, value }) => {
if (done) {
controller.close();
} else {
loaded += value.byteLength;
const event = new ProgressEvent("progress", {
lengthComputable,
loaded,
total
});
for (let i = 0, il = callbacks.length; i < il; i++) {
const callback = callbacks[i];
if (callback.onProgress)
callback.onProgress(event);
}
controller.enqueue(value);
readData();
}
});
}
}
});
return new Response(stream);
} else {
throw new HttpError(
`fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`,
response
);
}
}).then((response) => {
switch (responseType) {
case "arraybuffer":
return response.arrayBuffer();
case "blob":
return response.blob();
case "document":
return response.text().then((text) => {
const parser = new DOMParser();
return parser.parseFromString(text, mimeType);
});
case "json":
return response.json();
default:
if (mimeType === void 0) {
return response.text();
} else {
const re = /charset="?([^;"\s]*)"?/i;
const exec = re.exec(mimeType);
const label = exec && exec[1] ? exec[1].toLowerCase() : void 0;
const decoder = new TextDecoder(label);
return response.arrayBuffer().then((ab) => decoder.decode(ab));
}
}
}).then((data) => {
Cache.add(url, data);
const callbacks = loading[url];
delete loading[url];
for (let i = 0, il = callbacks.length; i < il; i++) {
const callback = callbacks[i];
if (callback.onLoad)
callback.onLoad(data);
}
}).catch((err) => {
const callbacks = loading[url];
if (callbacks === void 0) {
this.manager.itemError(url);
throw err;
}
delete loading[url];
for (let i = 0, il = callbacks.length; i < il; i++) {
const callback = callbacks[i];
if (callback.onError)
callback.onError(err);
}
this.manager.itemError(url);
}).finally(() => {
this.manager.itemEnd(url);
});
this.manager.itemStart(url);
}
setResponseType(value) {
this.responseType = value;
return this;
}
setMimeType(value) {
this.mimeType = value;
return this;
}
}
class BufferGeometryLoader extends Loader {
constructor(manager) {
super(manager);
}
load(url, onLoad, onProgress, onError) {
const scope = this;
const loader = new FileLoader(scope.manager);
loader.setPath(scope.path);
loader.setRequestHeader(scope.requestHeader);
loader.setWithCredentials(scope.withCredentials);
loader.load(
url,
function(text) {
try {
onLoad(scope.parse(JSON.parse(text)));
} catch (e) {
if (onError) {
onError(e);
} else {
console.error(e);
}
scope.manager.itemError(url);
}
},
onProgress,
onError
);
}
parse(json) {
const interleavedBufferMap = {};
const arrayBufferMap = {};
function getInterleavedBuffer(json2, uuid) {
if (interleavedBufferMap[uuid] !== void 0)
return interleavedBufferMap[uuid];
const interleavedBuffers = json2.interleavedBuffers;
const interleavedBuffer = interleavedBuffers[uuid];
const buffer = getArrayBuffer(json2, interleavedBuffer.buffer);
const array = getTypedArray(interleavedBuffer.type, buffer);
const ib = new InterleavedBuffer(array, interleavedBuffer.stride);
ib.uuid = interleavedBuffer.uuid;
interleavedBufferMap[uuid] = ib;
return ib;
}
function getArrayBuffer(json2, uuid) {
if (arrayBufferMap[uuid] !== void 0)
return arrayBufferMap[uuid];
const arrayBuffers = json2.arrayBuffers;
const arrayBuffer = arrayBuffers[uuid];
const ab = new Uint32Array(arrayBuffer).buffer;
arrayBufferMap[uuid] = ab;
return ab;
}
const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry();
const index = json.data.index;
if (index !== void 0) {
const typedArray = getTypedArray(index.type, index.array);
geometry.setIndex(new BufferAttribute(typedArray, 1));
}
const attributes = json.data.attributes;
for (const key in attributes) {
const attribute = attributes[key];
let bufferAttribute;
if (attribute.isInterleavedBufferAttribute) {
const interleavedBuffer = getInterleavedBuffer(json.data, attribute.data);
bufferAttribute = new InterleavedBufferAttribute(
interleavedBuffer,
attribute.itemSize,
attribute.offset,
attribute.normalized
);
} else {
const typedArray = getTypedArray(attribute.type, attribute.array);
const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute;
bufferAttribute = new bufferAttributeConstr(
typedArray,
attribute.itemSize,
attribute.normalized
);
}
if (attribute.name !== void 0)
bufferAttribute.name = attribute.name;
if (attribute.usage !== void 0)
bufferAttribute.setUsage(attribute.usage);
if (attribute.updateRange !== void 0) {
bufferAttribute.updateRange.offset = attribute.updateRange.offset;
bufferAttribute.updateRange.count = attribute.updateRange.count;
}
geometry.setAttribute(key, bufferAttribute);
}
const morphAttributes = json.data.morphAttributes;
if (morphAttributes) {
for (const key in morphAttributes) {
const attributeArray = morphAttributes[key];
const array = [];
for (let i = 0, il = attributeArray.length; i < il; i++) {
const attribute = attributeArray[i];
let bufferAttribute;
if (attribute.isInterleavedBufferAttribute) {
const interleavedBuffer = getInterleavedBuffer(json.data, attribute.data);
bufferAttribute = new InterleavedBufferAttribute(
interleavedBuffer,
attribute.itemSize,
attribute.offset,
attribute.normalized
);
} else {
const typedArray = getTypedArray(attribute.type, attribute.array);
bufferAttribute = new BufferAttribute(
typedArray,
attribute.itemSize,
attribute.normalized
);
}
if (attribute.name !== void 0)
bufferAttribute.name = attribute.name;
array.push(bufferAttribute);
}
geometry.morphAttributes[key] = array;
}
}
const morphTargetsRelative = json.data.morphTargetsRelative;
if (morphTargetsRelative) {
geometry.morphTargetsRelative = true;
}
const groups = json.data.groups || json.data.drawcalls || json.data.offsets;
if (groups !== void 0) {
for (let i = 0, n = groups.length; i !== n; ++i) {
const group = groups[i];
geometry.addGroup(group.start, group.count, group.materialIndex);
}
}
const boundingSphere = json.data.boundingSphere;
if (boundingSphere !== void 0) {
const center = new Vector3();
if (boundingSphere.center !== void 0) {
center.fromArray(boundingSphere.center);
}
geometry.boundingSphere = new Sphere(center, boundingSphere.radius);
}
if (json.name)
geometry.name = json.name;
if (json.userData)
geometry.userData = json.userData;
return geometry;
}
}
class ImageLoader extends Loader {
constructor(manager) {
super(manager);
}
load(url, onLoad, onProgress, onError) {
if (this.path !== void 0)
url = this.path + url;
url = this.manager.resolveURL(url);
const scope = this;
const cached = Cache.get(url);
if (cached !== void 0) {
scope.manager.itemStart(url);
setTimeout(function() {
if (onLoad)
onLoad(cached);
scope.manager.itemEnd(url);
}, 0);
return cached;
}
const image = createElementNS("img");
function onImageLoad() {
removeEventListeners();
Cache.add(url, this);
if (onLoad)
onLoad(this);
scope.manager.itemEnd(url);
}
function onImageError(event) {
removeEventListeners();
if (onError)
onError(event);
scope.manager.itemError(url);
scope.manager.itemEnd(url);
}
function removeEventListeners() {
image.removeEventListener("load", onImageLoad, false);
image.removeEventListener("error", onImageError, false);
}
image.addEventListener("load", onImageLoad, false);
image.addEventListener("error", onImageError, false);
if (url.slice(0, 5) !== "data:") {
if (this.crossOrigin !== void 0)
image.crossOrigin = this.crossOrigin;
}
scope.manager.itemStart(url);
image.src = url;
return image;
}
}
class CubeTextureLoader extends Loader {
constructor(manager) {
super(manager);
}
// EP: async interface ?
load(urls, onLoad, onProgress, onError) {
const texture = new CubeTexture();
texture.colorSpace = SRGBColorSpace;
const loader = new ImageLoader(this.manager);
loader.setCrossOrigin(this.crossOrigin);
loader.setPath(this.path);
let loaded = 0;
function loadTexture(i) {
loader.load(
urls[i],
function(image) {
texture.images[i] = image;
loaded++;
if (loaded === 6) {
texture.needsUpdate = true;
if (onLoad)
onLoad(texture);
}
},
void 0,
onError
);
}
for (let i = 0; i < urls.length; ++i) {
loadTexture(i);
}
return texture;
}
}
class DataTextureLoader extends Loader {
constructor(manager) {
super(manager);
}
load(url, onLoad, onProgress, onError) {
const scope = this;
const texture = new DataTexture();
const loader = new FileLoader(this.manager);
loader.setResponseType("arraybuffer");
loader.setRequestHeader(this.requestHeader);
loader.setPath(this.path);
loader.setWithCredentials(scope.withCredentials);
loader.load(
url,
function(buffer) {
let texData;
try {
texData = scope.parse(buffer);
} catch (error) {
if (onError !== void 0) {
onError(error);
} else {
console.error(error);
return;
}
}
if (texData.image !== void 0) {
texture.image = texData.image;
} else if (texData.data !== void 0) {
texture.image.width = texData.width;
texture.image.height = texData.height;
texture.image.data = texData.data;
}
texture.wrapS = texData.wrapS !== void 0 ? texData.wrapS : ClampToEdgeWrapping;
texture.wrapT = texData.wrapT !== void 0 ? texData.wrapT : ClampToEdgeWrapping;
texture.magFilter = texData.magFilter !== void 0 ? texData.magFilter : LinearFilter;
texture.minFilter = texData.minFilter !== void 0 ? texData.minFilter : LinearFilter;
texture.anisotropy = texData.anisotropy !== void 0 ? texData.anisotropy : 1;
if (texData.colorSpace !== void 0) {
texture.colorSpace = texData.colorSpace;
} else if (texData.encoding !== void 0) {
texture.encoding = texData.encoding;
}
if (texData.flipY !== void 0) {
texture.flipY = texData.flipY;
}
if (texData.format !== void 0) {
texture.format = texData.format;
}
if (texData.type !== void 0) {
texture.type = texData.type;
}
if (texData.mipmaps !== void 0) {
texture.mipmaps = texData.mipmaps;
texture.minFilter = LinearMipmapLinearFilter;
}
if (texData.mipmapCount === 1) {
texture.minFilter = LinearFilter;
}
if (texData.generateMipmaps !== void 0) {
texture.generateMipmaps = texData.generateMipmaps;
}
texture.needsUpdate = true;
if (onLoad)
onLoad(texture, texData);
},
onProgress,
onError
);
return texture;
}
}
class ImageBitmapLoader extends Loader {
constructor(manager) {
super(manager);
this.isImageBitmapLoader = true;
if (typeof createImageBitmap === "undefined") {
console.warn("ImageBitmapLoader: createImageBitmap() not supported.");
}
this.options = { premultiplyAlpha: "none" };
}
setOptions(options) {
this.options = options;
return this;
}
load(url, onLoad, onProgress, onError) {
if (url === void 0)
url = "";
if (this.path !== void 0)
url = this.path + url;
url = this.manager.resolveURL(url);
const scope = this;
const cached = Cache.get(url);
if (cached !== void 0) {
scope.manager.itemStart(url);
setTimeout(function() {
if (onLoad)
onLoad(cached);
scope.manager.itemEnd(url);
}, 0);
return cached;
}
const fetchOptions = {};
fetchOptions.credentials = this.crossOrigin === "anonymous" ? "same-origin" : "include";
fetchOptions.headers = this.requestHeader;
fetch(url, fetchOptions).then(function(res) {
return res.blob();
}).then(function(blob) {
return createImageBitmap(
blob,
Object.assign(scope.options, { colorSpaceConversion: "none" })
);
}).then(function(imageBitmap) {
Cache.add(url, imageBitmap);
if (onLoad)
onLoad(imageBitmap);
scope.manager.itemEnd(url);
}).catch(function(e) {
if (onError)
onError(e);
scope.manager.itemError(url);
scope.manager.itemEnd(url);
});
scope.manager.itemStart(url);
}
}
class LoaderUtils {
static decodeText(array) {
if (typeof TextDecoder !== "undefined") {
return new TextDecoder().decode(array);
}
let s = "";
for (let i = 0, il = array.length; i < il; i++) {
s += String.fromCharCode(array[i]);
}
try {
return decodeURIComponent(escape(s));
} catch (e) {
return s;
}
}
static extractUrlBase(url) {
const index = url.lastIndexOf("/");
if (index === -1)
return "./";
return url.slice(0, index + 1);
}
static resolveURL(url, path) {
if (typeof url !== "string" || url === "")
return "";
if (/^https?:\/\//i.test(path) && /^\//.test(url)) {
path = path.replace(/(^https?:\/\/[^/]+).*/i, "$1");
}
if (/^(https?:)?\/\//i.test(url))
return url;
if (/^data:.*,.*$/i.test(url))
return url;
if (/^blob:.*$/i.test(url))
return url;
if (/^file:.*$/i.test(url))
return url;
if (!path) {
path = document.baseURI || window.location.href;
}
try {
return new URL(url, path).href;
} catch (e) {
return "";
}
}
static withTrailingSlash(path) {
if (path[path.length - 1] !== "/") {
return `${path}/`;
}
return path;
}
}
class MaterialLoader extends Loader {
constructor(manager) {
super(manager);
this.textures = {};
}
load(url, onLoad, onProgress, onError) {
const scope = this;
const loader = new FileLoader(scope.manager);
loader.setPath(scope.path);
loader.setRequestHeader(scope.requestHeader);
loader.setWithCredentials(scope.withCredentials);
loader.load(
url,
function(text) {
try {
onLoad(scope.parse(JSON.parse(text)));
} catch (e) {
if (onError) {
onError(e);
} else {
console.error(e);
}
scope.manager.itemError(url);
}
},
onProgress,
onError
);
}
parse(json) {
const textures = this.textures;
function getTexture(name) {
if (textures[name] === void 0) {
console.warn("MaterialLoader: Undefined texture", name);
}
return textures[name];
}
const material = MaterialLoader.createMaterialFromType(json.type);
if (json.uuid !== void 0)
material.uuid = json.uuid;
if (json.name !== void 0)
material.name = json.name;
if (json.color !== void 0 && material.color !== void 0)
material.color.setHex(json.color);
if (json.roughness !== void 0)
material.roughness = json.roughness;
if (json.metalness !== void 0)
material.metalness = json.metalness;
if (json.sheen !== void 0)
material.sheen = json.sheen;
if (json.sheenColor !== void 0)
material.sheenColor = new Color().setHex(json.sheenColor);
if (json.sheenRoughness !== void 0)
material.sheenRoughness = json.sheenRoughness;
if (json.emissive !== void 0 && material.emissive !== void 0)
material.emissive.setHex(json.emissive);
if (json.specular !== void 0 && material.specular !== void 0)
material.specular.setHex(json.specular);
if (json.specularIntensity !== void 0)
material.specularIntensity = json.specularIntensity;
if (json.specularColor !== void 0 && material.specularColor !== void 0)
material.specularColor.setHex(json.specularColor);
if (json.shininess !== void 0)
material.shininess = json.shininess;
if (json.clearcoat !== void 0)
material.clearcoat = json.clearcoat;
if (json.clearcoatRoughness !== void 0)
material.clearcoatRoughness = json.clearcoatRoughness;
if (json.iridescence !== void 0)
material.iridescence = json.iridescence;
if (json.iridescenceIOR !== void 0)
material.iridescenceIOR = json.iridescenceIOR;
if (json.iridescenceThicknessRange !== void 0)
material.iridescenceThicknessRange = json.iridescenceThicknessRange;
if (json.transmission !== void 0)
material.transmission = json.transmission;
if (json.thickness !== void 0)
material.thickness = json.thickness;
if (json.attenuationDistance !== void 0)
material.attenuationDistance = json.attenuationDistance;
if (json.attenuationColor !== void 0 && material.attenuationColor !== void 0)
material.attenuationColor.setHex(json.attenuationColor);
if (json.anisotropy !== void 0)
material.anisotropy = json.anisotropy;
if (json.anisotropyRotation !== void 0)
material.anisotropyRotation = json.anisotropyRotation;
if (json.fog !== void 0)
material.fog = json.fog;
if (json.flatShading !== void 0)
material.flatShading = json.flatShading;
if (json.blending !== void 0)
material.blending = json.blending;
if (json.combine !== void 0)
material.combine = json.combine;
if (json.side !== void 0)
material.side = json.side;
if (json.shadowSide !== void 0)
material.shadowSide = json.shadowSide;
if (json.opacity !== void 0)
material.opacity = json.opacity;
if (json.transparent !== void 0)
material.transparent = json.transparent;
if (json.alphaTest !== void 0)
material.alphaTest = json.alphaTest;
if (json.alphaHash !== void 0)
material.alphaHash = json.alphaHash;
if (json.depthFunc !== void 0)
material.depthFunc = json.depthFunc;
if (json.depthTest !== void 0)
material.depthTest = json.depthTest;
if (json.depthWrite !== void 0)
material.depthWrite = json.depthWrite;
if (json.colorWrite !== void 0)
material.colorWrite = json.colorWrite;
if (json.blendSrc !== void 0)
material.blendSrc = json.blendSrc;
if (json.blendDst !== void 0)
material.blendDst = json.blendDst;
if (json.blendEquation !== void 0)
material.blendEquation = json.blendEquation;
if (json.blendSrcAlpha !== void 0)
material.blendSrcAlpha = json.blendSrcAlpha;
if (json.blendDstAlpha !== void 0)
material.blendDstAlpha = json.blendDstAlpha;
if (json.blendEquationAlpha !== void 0)
material.blendEquationAlpha = json.blendEquationAlpha;
if (json.blendColor !== void 0 && material.blendColor !== void 0)
material.blendColor.setHex(json.blendColor);
if (json.blendAlpha !== void 0)
material.blendAlpha = json.blendAlpha;
if (json.stencilWriteMask !== void 0)
material.stencilWriteMask = json.stencilWriteMask;
if (json.stencilFunc !== void 0)
material.stencilFunc = json.stencilFunc;
if (json.stencilRef !== void 0)
material.stencilRef = json.stencilRef;
if (json.stencilFuncMask !== void 0)
material.stencilFuncMask = json.stencilFuncMask;
if (json.stencilFail !== void 0)
material.stencilFail = json.stencilFail;
if (json.stencilZFail !== void 0)
material.stencilZFail = json.stencilZFail;
if (json.stencilZPass !== void 0)
material.stencilZPass = json.stencilZPass;
if (json.stencilWrite !== void 0)
material.stencilWrite = json.stencilWrite;
if (json.wireframe !== void 0)
material.wireframe = json.wireframe;
if (json.wireframeLinewidth !== void 0)
material.wireframeLinewidth = json.wireframeLinewidth;
if (json.rotation !== void 0)
material.rotation = json.rotation;
if (json.linewidth !== void 0)
material.linewidth = json.linewidth;
if (json.dashSize !== void 0)
material.dashSize = json.dashSize;
if (json.gapSize !== void 0)
material.gapSize = json.gapSize;
if (json.scale !== void 0)
material.scale = json.scale;
if (json.polygonOffset !== void 0)
material.polygonOffset = json.polygonOffset;
if (json.polygonOffsetFactor !== void 0)
material.polygonOffsetFactor = json.polygonOffsetFactor;
if (json.polygonOffsetUnits !== void 0)
material.polygonOffsetUnits = json.polygonOffsetUnits;
if (json.dithering !== void 0)
material.dithering = json.dithering;
if (json.alphaToCoverage !== void 0)
material.alphaToCoverage = json.alphaToCoverage;
if (json.premultipliedAlpha !== void 0)
material.premultipliedAlpha = json.premultipliedAlpha;
if (json.forceSinglePass !== void 0)
material.forceSinglePass = json.forceSinglePass;
if (json.visible !== void 0)
material.visible = json.visible;
if (json.toneMapped !== void 0)
material.toneMapped = json.toneMapped;
if (json.userData !== void 0)
material.userData = json.userData;
if (json.vertexColors !== void 0) {
if (typeof json.vertexColors === "number") {
material.vertexColors = json.vertexColors > 0 ? true : false;
} else {
material.vertexColors = json.vertexColors;
}
}
if (json.uniforms !== void 0) {
for (const name in json.uniforms) {
const uniform = json.uniforms[name];
material.uniforms[name] = {};
switch (uniform.type) {
case "t":
material.uniforms[name].value = getTexture(uniform.value);
break;
case "c":
material.uniforms[name].value = new Color().setHex(uniform.value);
break;
case "v2":
material.uniforms[name].value = new Vector2().fromArray(uniform.value);
break;
case "v3":
material.uniforms[name].value = new Vector3().fromArray(uniform.value);
break;
case "v4":
material.uniforms[name].value = new Vector4().fromArray(uniform.value);
break;
case "m3":
material.uniforms[name].value = new Matrix3().fromArray(uniform.value);
break;
case "m4":
material.uniforms[name].value = new Matrix4().fromArray(uniform.value);
break;
default:
material.uniforms[name].value = uniform.value;
}
}
}
if (json.defines !== void 0)
material.defines = json.defines;
if (json.vertexShader !== void 0)
material.vertexShader = json.vertexShader;
if (json.fragmentShader !== void 0)
material.fragmentShader = json.fragmentShader;
if (json.glslVersion !== void 0)
material.glslVersion = json.glslVersion;
if (json.extensions !== void 0) {
for (const key in json.extensions) {
material.extensions[key] = json.extensions[key];
}
}
if (json.lights !== void 0)
material.lights = json.lights;
if (json.clipping !== void 0)
material.clipping = json.clipping;
if (json.size !== void 0)
material.size = json.size;
if (json.sizeAttenuation !== void 0)
material.sizeAttenuation = json.sizeAttenuation;
if (json.map !== void 0)
material.map = getTexture(json.map);
if (json.matcap !== void 0)
material.matcap = getTexture(json.matcap);
if (json.alphaMap !== void 0)
material.alphaMap = getTexture(json.alphaMap);
if (json.bumpMap !== void 0)
material.bumpMap = getTexture(json.bumpMap);
if (json.bumpScale !== void 0)
material.bumpScale = json.bumpScale;
if (json.normalMap !== void 0)
material.normalMap = getTexture(json.normalMap);
if (json.normalMapType !== void 0)
material.normalMapType = json.normalMapType;
if (json.normalScale !== void 0) {
let normalScale = json.normalScale;
if (Array.isArray(normalScale) === false) {
normalScale = [normalScale, normalScale];
}
material.normalScale = new Vector2().fromArray(normalScale);
}
if (json.displacementMap !== void 0)
material.displacementMap = getTexture(json.displacementMap);
if (json.displacementScale !== void 0)
material.displacementScale = json.displacementScale;
if (json.displacementBias !== void 0)
material.displacementBias = json.displacementBias;
if (json.roughnessMap !== void 0)
material.roughnessMap = getTexture(json.roughnessMap);
if (json.metalnessMap !== void 0)
material.metalnessMap = getTexture(json.metalnessMap);
if (json.emissiveMap !== void 0)
material.emissiveMap = getTexture(json.emissiveMap);
if (json.emissiveIntensity !== void 0)
material.emissiveIntensity = json.emissiveIntensity;
if (json.specularMap !== void 0)
material.specularMap = getTexture(json.specularMap);
if (json.specularIntensityMap !== void 0)
material.specularIntensityMap = getTexture(json.specularIntensityMap);
if (json.specularColorMap !== void 0)
material.specularColorMap = getTexture(json.specularColorMap);
if (json.envMap !== void 0)
material.envMap = getTexture(json.envMap);
if (json.envMapIntensity !== void 0)
material.envMapIntensity = json.envMapIntensity;
if (json.reflectivity !== void 0)
material.reflectivity = json.reflectivity;
if (json.refractionRatio !== void 0)
material.refractionRatio = json.refractionRatio;
if (json.lightMap !== void 0)
material.lightMap = getTexture(json.lightMap);
if (json.lightMapIntensity !== void 0)
material.lightMapIntensity = json.lightMapIntensity;
if (json.aoMap !== void 0)
material.aoMap = getTexture(json.aoMap);
if (json.aoMapIntensity !== void 0)
material.aoMapIntensity = json.aoMapIntensity;
if (json.gradientMap !== void 0)
material.gradientMap = getTexture(json.gradientMap);
if (json.clearcoatMap !== void 0)
material.clearcoatMap = getTexture(json.clearcoatMap);
if (json.clearcoatRoughnessMap !== void 0)
material.clearcoatRoughnessMap = getTexture(json.clearcoatRoughnessMap);
if (json.clearcoatNormalMap !== void 0)
material.clearcoatNormalMap = getTexture(json.clearcoatNormalMap);
if (json.clearcoatNormalScale !== void 0)
material.clearcoatNormalScale = new Vector2().fromArray(json.clearcoatNormalScale);
if (json.iridescenceMap !== void 0)
material.iridescenceMap = getTexture(json.iridescenceMap);
if (json.iridescenceThicknessMap !== void 0)
material.iridescenceThicknessMap = getTexture(json.iridescenceThicknessMap);
if (json.transmissionMap !== void 0)
material.transmissionMap = getTexture(json.transmissionMap);
if (json.thicknessMap !== void 0)
material.thicknessMap = getTexture(json.thicknessMap);
if (json.anisotropyMap !== void 0)
material.anisotropyMap = getTexture(json.anisotropyMap);
if (json.sheenColorMap !== void 0)
material.sheenColorMap = getTexture(json.sheenColorMap);
if (json.sheenRoughnessMap !== void 0)
material.sheenRoughnessMap = getTexture(json.sheenRoughnessMap);
return material;
}
setTextures(value) {
this.textures = value;
return this;
}
static createMaterialFromType(type) {
const materialLib = {
ShadowMaterial,
SpriteMaterial,
RawShaderMaterial,
ShaderMaterial,
PointsMaterial,
MeshPhysicalMaterial,
MeshStandardMaterial,
// MeshPhongMaterial,
// MeshToonMaterial,
MeshNormalMaterial,
// MeshLambertMaterial,
MeshDepthMaterial,
MeshDistanceMaterial,
MeshBasicMaterial,
// MeshMatcapMaterial,
// LineDashedMaterial,
LineBasicMaterial,
Material
};
return new materialLib[type]();
}
}
class ObjectLoader extends Loader {
constructor(manager) {
super(manager);
}
load(url, onLoad, onProgress, onError) {
const scope = this;
const path = this.path === "" ? LoaderUtils.extractUrlBase(url) : this.path;
this.resourcePath = this.resourcePath || path;
const loader = new FileLoader(this.manager);
loader.setPath(this.path);
loader.setRequestHeader(this.requestHeader);
loader.setWithCredentials(this.withCredentials);
loader.load(
url,
function(text) {
let json = null;
try {
json = JSON.parse(text);
} catch (error) {
if (onError !== void 0)
onError(error);
console.error("ObjectLoader: Can't parse " + url + ".", error.message);
return;
}
const metadata = json.metadata;
if (metadata === void 0 || metadata.type === void 0 || metadata.type.toLowerCase() === "geometry") {
if (onError !== void 0)
onError(new Error("ObjectLoader: Can't load " + url));
console.error("ObjectLoader: Can't load " + url);
return;
}
scope.parse(json, onLoad);
},
onProgress,
onError
);
}
async loadAsync(url, onProgress) {
const scope = this;
const path = this.path === "" ? LoaderUtils.extractUrlBase(url) : this.path;
this.resourcePath = this.resourcePath || path;
const loader = new FileLoader(this.manager);
loader.setPath(this.path);
loader.setRequestHeader(this.requestHeader);
loader.setWithCredentials(this.withCredentials);
const text = await loader.loadAsync(url, onProgress);
const json = JSON.parse(text);
const metadata = json.metadata;
if (metadata === void 0 || metadata.type === void 0 || metadata.type.toLowerCase() === "geometry") {
throw new Error("ObjectLoader: Can't load " + url);
}
return await scope.parseAsync(json);
}
parse(json, onLoad) {
const animations = this.parseAnimations(json.animations);
const shapes = {};
const geometries = this.parseGeometries(json.geometries, shapes);
const images = this.parseImages(json.images, function() {
if (onLoad !== void 0)
onLoad(object);
});
const textures = this.parseTextures(json.textures, images);
const materials = this.parseMaterials(json.materials, textures);
const object = this.parseObject(json.object, geometries, materials, textures, animations);
const skeletons = this.parseSkeletons(json.skeletons, object);
this.bindSkeletons(object, skeletons);
if (onLoad !== void 0) {
let hasImages = false;
for (const uuid in images) {
if (images[uuid].data instanceof HTMLImageElement) {
hasImages = true;
break;
}
}
if (hasImages === false)
onLoad(object);
}
return object;
}
async parseAsync(json) {
const animations = this.parseAnimations(json.animations);
const shapes = {};
const geometries = this.parseGeometries(json.geometries, shapes);
const images = await this.parseImagesAsync(json.images);
const textures = this.parseTextures(json.textures, images);
const materials = this.parseMaterials(json.materials, textures);
const object = this.parseObject(json.object, geometries, materials, textures, animations);
const skeletons = this.parseSkeletons(json.skeletons, object);
this.bindSkeletons(object, skeletons);
return object;
}
// parseShapes(json) {
// const shapes = {};
// if (json !== undefined) {
// for (let i = 0, l = json.length; i < l; i++) {
// const shape = new Shape().fromJSON(json[i]);
// shapes[shape.uuid] = shape;
// }
// }
// return shapes;
// }
parseSkeletons(json, object) {
const skeletons = {};
const bones = {};
object.traverse(function(child) {
if (child.isBone)
bones[child.uuid] = child;
});
if (json !== void 0) {
for (let i = 0, l = json.length; i < l; i++) {
const skeleton = new Skeleton().fromJSON(json[i], bones);
skeletons[skeleton.uuid] = skeleton;
}
}
return skeletons;
}
parseGeometries(json, shapes) {
const geometries = {};
if (json !== void 0) {
const bufferGeometryLoader = new BufferGeometryLoader();
for (let i = 0, l = json.length; i < l; i++) {
let geometry;
const data = json[i];
switch (data.type) {
case "BufferGeometry":
case "InstancedBufferGeometry":
geometry = bufferGeometryLoader.parse(data);
break;
default:
if (data.type in Geometries) {
geometry = Geometries[data.type].fromJSON(data, shapes);
} else {
console.warn(`ObjectLoader: Unsupported geometry type "${data.type}"`);
}
}
geometry.uuid = data.uuid;
if (data.name !== void 0)
geometry.name = data.name;
if (data.userData !== void 0)
geometry.userData = data.userData;
geometries[data.uuid] = geometry;
}
}
return geometries;
}
parseMaterials(json, textures) {
const cache = {};
const materials = {};
if (json !== void 0) {
const loader = new MaterialLoader();
loader.setTextures(textures);
for (let i = 0, l = json.length; i < l; i++) {
const data = json[i];
if (cache[data.uuid] === void 0) {
cache[data.uuid] = loader.parse(data);
}
materials[data.uuid] = cache[data.uuid];
}
}
return materials;
}
parseAnimations(json) {
const animations = {};
if (json !== void 0) {
for (let i = 0; i < json.length; i++) {
const data = json[i];
const clip = AnimationClip.parse(data);
animations[clip.uuid] = clip;
}
}
return animations;
}
parseImages(json, onLoad) {
const scope = this;
const images = {};
let loader;
function loadImage(url) {
scope.manager.itemStart(url);
return loader.load(
url,
function() {
scope.manager.itemEnd(url);
},
void 0,
function() {
scope.manager.itemError(url);
scope.manager.itemEnd(url);
}
);
}
function deserializeImage(image) {
if (typeof image === "string") {
const url = image;
const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test(url) ? url : scope.resourcePath + url;
return loadImage(path);
} else {
if (image.data) {
return {
data: getTypedArray(image.type, image.data),
width: image.width,
height: image.height
};
} else {
return null;
}
}
}
if (json !== void 0 && json.length > 0) {
const manager = new LoadingManager(onLoad);
loader = new ImageLoader(manager);
loader.setCrossOrigin(this.crossOrigin);
for (let i = 0, il = json.length; i < il; i++) {
const image = json[i];
const url = image.url;
if (Array.isArray(url)) {
const imageArray = [];
for (let j = 0, jl = url.length; j < jl; j++) {
const currentUrl = url[j];
const deserializedImage = deserializeImage(currentUrl);
if (deserializedImage !== null) {
if (deserializedImage instanceof HTMLImageElement) {
imageArray.push(deserializedImage);
} else {
imageArray.push(
new DataTexture(
deserializedImage.data,
deserializedImage.width,
deserializedImage.height
)
);
}
}
}
images[image.uuid] = new Source(imageArray);
} else {
const deserializedImage = deserializeImage(image.url);
images[image.uuid] = new Source(deserializedImage);
}
}
}
return images;
}
async parseImagesAsync(json) {
const scope = this;
const images = {};
let loader;
async function deserializeImage(image) {
if (typeof image === "string") {
const url = image;
const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test(url) ? url : scope.resourcePath + url;
return await loader.loadAsync(path);
} else {
if (image.data) {
return {
data: getTypedArray(image.type, image.data),
width: image.width,
height: image.height
};
} else {
return null;
}
}
}
if (json !== void 0 && json.length > 0) {
loader = new ImageLoader(this.manager);
loader.setCrossOrigin(this.crossOrigin);
for (let i = 0, il = json.length; i < il; i++) {
const image = json[i];
const url = image.url;
if (Array.isArray(url)) {
const imageArray = [];
for (let j = 0, jl = url.length; j < jl; j++) {
const currentUrl = url[j];
const deserializedImage = await deserializeImage(currentUrl);
if (deserializedImage !== null) {
if (deserializedImage instanceof HTMLImageElement) {
imageArray.push(deserializedImage);
} else {
imageArray.push(
new DataTexture(
deserializedImage.data,
deserializedImage.width,
deserializedImage.height
)
);
}
}
}
images[image.uuid] = new Source(imageArray);
} else {
const deserializedImage = await deserializeImage(image.url);
images[image.uuid] = new Source(deserializedImage);
}
}
}
return images;
}
parseTextures(json, images) {
function parseConstant(value, type) {
if (typeof value === "number")
return value;
console.warn("ObjectLoader.parseTexture: Constant should be in numeric form.", value);
return type[value];
}
const textures = {};
if (json !== void 0) {
for (let i = 0, l = json.length; i < l; i++) {
const data = json[i];
if (data.image === void 0) {
console.warn('ObjectLoader: No "image" specified for', data.uuid);
}
if (images[data.image] === void 0) {
console.warn("ObjectLoader: Undefined image", data.image);
}
const source = images[data.image];
const image = source.data;
let texture;
if (Array.isArray(image)) {
texture = new CubeTexture();
if (image.length === 6)
texture.needsUpdate = true;
} else {
if (image && image.data) {
texture = new DataTexture();
} else {
texture = new Texture();
}
if (image)
texture.needsUpdate = true;
}
texture.source = source;
texture.uuid = data.uuid;
if (data.name !== void 0)
texture.name = data.name;
if (data.mapping !== void 0)
texture.mapping = parseConstant(data.mapping, TEXTURE_MAPPING);
if (data.channel !== void 0)
texture.channel = data.channel;
if (data.offset !== void 0)
texture.offset.fromArray(data.offset);
if (data.repeat !== void 0)
texture.repeat.fromArray(data.repeat);
if (data.center !== void 0)
texture.center.fromArray(data.center);
if (data.rotation !== void 0)
texture.rotation = data.rotation;
if (data.wrap !== void 0) {
texture.wrapS = parseConstant(data.wrap[0], TEXTURE_WRAPPING);
texture.wrapT = parseConstant(data.wrap[1], TEXTURE_WRAPPING);
}
if (data.format !== void 0)
texture.format = data.format;
if (data.internalFormat !== void 0)
texture.internalFormat = data.internalFormat;
if (data.type !== void 0)
texture.type = data.type;
if (data.colorSpace !== void 0)
texture.colorSpace = data.colorSpace;
if (data.encoding !== void 0)
texture.encoding = data.encoding;
if (data.minFilter !== void 0)
texture.minFilter = parseConstant(data.minFilter, TEXTURE_FILTER);
if (data.magFilter !== void 0)
texture.magFilter = parseConstant(data.magFilter, TEXTURE_FILTER);
if (data.anisotropy !== void 0)
texture.anisotropy = data.anisotropy;
if (data.flipY !== void 0)
texture.flipY = data.flipY;
if (data.generateMipmaps !== void 0)
texture.generateMipmaps = data.generateMipmaps;
if (data.premultiplyAlpha !== void 0)
texture.premultiplyAlpha = data.premultiplyAlpha;
if (data.unpackAlignment !== void 0)
texture.unpackAlignment = data.unpackAlignment;
if (data.compareFunction !== void 0)
texture.compareFunction = data.compareFunction;
if (data.userData !== void 0)
texture.userData = data.userData;
textures[data.uuid] = texture;
}
}
return textures;
}
parseObject(data, geometries, materials, textures, animations) {
let object;
function getGeometry(name) {
if (geometries[name] === void 0) {
console.warn("ObjectLoader: Undefined geometry", name);
}
return geometries[name];
}
function getMaterial(name) {
if (name === void 0