@threepipe/plugins-extra-importers
Version:
Extra Threepipe plugins for importing several file types.
1,558 lines • 575 kB
JavaScript
/**
* @license
* @threepipe/plugins-extra-importers v0.2.3
* Copyright 2022-2025 repalash <palash@shaders.app>
* Apache-2.0 License
* See ./dependencies.txt for any bundled third-party dependencies and licenses.
*/
import { Loader, LoaderUtils, FileLoader, Group, MeshPhongMaterial, DoubleSide, AdditiveBlending, BufferGeometry, Mesh, Float32BufferAttribute, Matrix4, TextureLoader, Color, SRGBColorSpace, BufferAttribute, MeshStandardMaterial, RepeatWrapping, ClampToEdgeWrapping, MirroredRepeatWrapping, LinearFilter, LinearMipmapLinearFilter, NearestFilter, DataTextureLoader, Vector3, Quaternion, MeshBasicMaterial, Scene, MathUtils, AnimationClip, VectorKeyframeTrack, QuaternionKeyframeTrack, MeshLambertMaterial, Vector2, FrontSide, PerspectiveCamera, OrthographicCamera, AmbientLight, SpotLight, PointLight, DirectionalLight, Bone, LineBasicMaterial, SkinnedMesh, Line, LineSegments, Skeleton, NumberKeyframeTrack, Int32BufferAttribute, PointsMaterial, Points, RawShaderMaterial, Object3D, SphereGeometry, BackSide, DataTexture, BoxGeometry, ConeGeometry, CylinderGeometry, ShapeUtils, Ray, ShaderMaterial, UniformsUtils, UniformsLib, BaseImporterPlugin, Importer, SkeletonHelper, PhysicalMaterial } from "threepipe";
class TDSLoader extends Loader {
constructor(manager) {
super(manager);
this.debug = false;
this.group = null;
this.materials = [];
this.meshes = [];
}
/**
* Load 3ds file from url.
*
* @method load
* @param {[type]} url URL for the file.
* @param {Function} onLoad onLoad callback, receives group Object3D as argument.
* @param {Function} onProgress onProgress callback.
* @param {Function} onError onError callback.
*/
load(url, onLoad, onProgress, onError) {
const scope = this;
const path = this.path === "" ? LoaderUtils.extractUrlBase(url) : this.path;
const loader = new FileLoader(this.manager);
loader.setPath(this.path);
loader.setResponseType("arraybuffer");
loader.setRequestHeader(this.requestHeader);
loader.setWithCredentials(this.withCredentials);
loader.load(url, function(data) {
try {
onLoad(scope.parse(data, path));
} catch (e) {
if (onError) {
onError(e);
} else {
console.error(e);
}
scope.manager.itemError(url);
}
}, onProgress, onError);
}
/**
* Parse arraybuffer data and load 3ds file.
*
* @method parse
* @param {ArrayBuffer} arraybuffer Arraybuffer data to be loaded.
* @param {String} path Path for external resources.
* @return {Group} Group loaded from 3ds file.
*/
parse(arraybuffer, path) {
this.group = new Group();
this.materials = [];
this.meshes = [];
this.readFile(arraybuffer, path);
for (let i = 0; i < this.meshes.length; i++) {
this.group.add(this.meshes[i]);
}
return this.group;
}
/**
* Decode file content to read 3ds data.
*
* @method readFile
* @param {ArrayBuffer} arraybuffer Arraybuffer data to be loaded.
* @param {String} path Path for external resources.
*/
readFile(arraybuffer, path) {
const data = new DataView(arraybuffer);
const chunk = new Chunk(data, 0, this.debugMessage);
if (chunk.id === MLIBMAGIC || chunk.id === CMAGIC || chunk.id === M3DMAGIC) {
let next = chunk.readChunk();
while (next) {
if (next.id === M3D_VERSION) {
const version = next.readDWord();
this.debugMessage("3DS file version: " + version);
} else if (next.id === MDATA) {
this.readMeshData(next, path);
} else {
this.debugMessage("Unknown main chunk: " + next.hexId);
}
next = chunk.readChunk();
}
}
this.debugMessage("Parsed " + this.meshes.length + " meshes");
}
/**
* Read mesh data chunk.
*
* @method readMeshData
* @param {Chunk} chunk to read mesh from
* @param {String} path Path for external resources.
*/
readMeshData(chunk, path) {
let next = chunk.readChunk();
while (next) {
if (next.id === MESH_VERSION) {
const version = +next.readDWord();
this.debugMessage("Mesh Version: " + version);
} else if (next.id === MASTER_SCALE) {
const scale = next.readFloat();
this.debugMessage("Master scale: " + scale);
this.group.scale.set(scale, scale, scale);
} else if (next.id === NAMED_OBJECT) {
this.debugMessage("Named Object");
this.readNamedObject(next);
} else if (next.id === MAT_ENTRY) {
this.debugMessage("Material");
this.readMaterialEntry(next, path);
} else {
this.debugMessage("Unknown MDATA chunk: " + next.hexId);
}
next = chunk.readChunk();
}
}
/**
* Read named object chunk.
*
* @method readNamedObject
* @param {Chunk} chunk Chunk in use.
*/
readNamedObject(chunk) {
const name = chunk.readString();
let next = chunk.readChunk();
while (next) {
if (next.id === N_TRI_OBJECT) {
const mesh = this.readMesh(next);
mesh.name = name;
this.meshes.push(mesh);
} else {
this.debugMessage("Unknown named object chunk: " + next.hexId);
}
next = chunk.readChunk();
}
}
/**
* Read material data chunk and add it to the material list.
*
* @method readMaterialEntry
* @param {Chunk} chunk Chunk in use.
* @param {String} path Path for external resources.
*/
readMaterialEntry(chunk, path) {
let next = chunk.readChunk();
const material = new MeshPhongMaterial();
while (next) {
if (next.id === MAT_NAME) {
material.name = next.readString();
this.debugMessage(" Name: " + material.name);
} else if (next.id === MAT_WIRE) {
this.debugMessage(" Wireframe");
material.wireframe = true;
} else if (next.id === MAT_WIRE_SIZE) {
const value = next.readByte();
material.wireframeLinewidth = value;
this.debugMessage(" Wireframe Thickness: " + value);
} else if (next.id === MAT_TWO_SIDE) {
material.side = DoubleSide;
this.debugMessage(" DoubleSided");
} else if (next.id === MAT_ADDITIVE) {
this.debugMessage(" Additive Blending");
material.blending = AdditiveBlending;
} else if (next.id === MAT_DIFFUSE) {
this.debugMessage(" Diffuse Color");
material.color = this.readColor(next);
} else if (next.id === MAT_SPECULAR) {
this.debugMessage(" Specular Color");
material.specular = this.readColor(next);
} else if (next.id === MAT_AMBIENT) {
this.debugMessage(" Ambient color");
material.color = this.readColor(next);
} else if (next.id === MAT_SHININESS) {
const shininess = this.readPercentage(next);
material.shininess = shininess * 100;
this.debugMessage(" Shininess : " + shininess);
} else if (next.id === MAT_TRANSPARENCY) {
const transparency = this.readPercentage(next);
material.opacity = 1 - transparency;
this.debugMessage(" Transparency : " + transparency);
material.transparent = material.opacity < 1 ? true : false;
} else if (next.id === MAT_TEXMAP) {
this.debugMessage(" ColorMap");
material.map = this.readMap(next, path);
} else if (next.id === MAT_BUMPMAP) {
this.debugMessage(" BumpMap");
material.bumpMap = this.readMap(next, path);
} else if (next.id === MAT_OPACMAP) {
this.debugMessage(" OpacityMap");
material.alphaMap = this.readMap(next, path);
} else if (next.id === MAT_SPECMAP) {
this.debugMessage(" SpecularMap");
material.specularMap = this.readMap(next, path);
} else {
this.debugMessage(" Unknown material chunk: " + next.hexId);
}
next = chunk.readChunk();
}
this.materials[material.name] = material;
}
/**
* Read mesh data chunk.
*
* @method readMesh
* @param {Chunk} chunk Chunk in use.
* @return {Mesh} The parsed mesh.
*/
readMesh(chunk) {
let next = chunk.readChunk();
const geometry = new BufferGeometry();
const material = new MeshPhongMaterial();
const mesh = new Mesh(geometry, material);
mesh.name = "mesh";
while (next) {
if (next.id === POINT_ARRAY) {
const points = next.readWord();
this.debugMessage(" Vertex: " + points);
const vertices = [];
for (let i = 0; i < points; i++) {
vertices.push(next.readFloat());
vertices.push(next.readFloat());
vertices.push(next.readFloat());
}
geometry.setAttribute("position", new Float32BufferAttribute(vertices, 3));
} else if (next.id === FACE_ARRAY) {
this.readFaceArray(next, mesh);
} else if (next.id === TEX_VERTS) {
const texels = next.readWord();
this.debugMessage(" UV: " + texels);
const uvs = [];
for (let i = 0; i < texels; i++) {
uvs.push(next.readFloat());
uvs.push(next.readFloat());
}
geometry.setAttribute("uv", new Float32BufferAttribute(uvs, 2));
} else if (next.id === MESH_MATRIX) {
this.debugMessage(" Tranformation Matrix (TODO)");
const values = [];
for (let i = 0; i < 12; i++) {
values[i] = next.readFloat();
}
const matrix = new Matrix4();
matrix.elements[0] = values[0];
matrix.elements[1] = values[6];
matrix.elements[2] = values[3];
matrix.elements[3] = values[9];
matrix.elements[4] = values[2];
matrix.elements[5] = values[8];
matrix.elements[6] = values[5];
matrix.elements[7] = values[11];
matrix.elements[8] = values[1];
matrix.elements[9] = values[7];
matrix.elements[10] = values[4];
matrix.elements[11] = values[10];
matrix.elements[12] = 0;
matrix.elements[13] = 0;
matrix.elements[14] = 0;
matrix.elements[15] = 1;
matrix.transpose();
const inverse = new Matrix4();
inverse.copy(matrix).invert();
geometry.applyMatrix4(inverse);
matrix.decompose(mesh.position, mesh.quaternion, mesh.scale);
} else {
this.debugMessage(" Unknown mesh chunk: " + next.hexId);
}
next = chunk.readChunk();
}
geometry.computeVertexNormals();
return mesh;
}
/**
* Read face array data chunk.
*
* @method readFaceArray
* @param {Chunk} chunk Chunk in use.
* @param {Mesh} mesh Mesh to be filled with the data read.
*/
readFaceArray(chunk, mesh) {
const faces = chunk.readWord();
this.debugMessage(" Faces: " + faces);
const index = [];
for (let i = 0; i < faces; ++i) {
index.push(chunk.readWord(), chunk.readWord(), chunk.readWord());
chunk.readWord();
}
mesh.geometry.setIndex(index);
let materialIndex = 0;
let start = 0;
while (!chunk.endOfChunk) {
const subchunk = chunk.readChunk();
if (subchunk.id === MSH_MAT_GROUP) {
this.debugMessage(" Material Group");
const group = this.readMaterialGroup(subchunk);
const count = group.index.length * 3;
mesh.geometry.addGroup(start, count, materialIndex);
start += count;
materialIndex++;
const material = this.materials[group.name];
if (Array.isArray(mesh.material) === false) mesh.material = [];
if (material !== void 0) {
mesh.material.push(material);
}
} else {
this.debugMessage(" Unknown face array chunk: " + subchunk.hexId);
}
}
if (mesh.material.length === 1) mesh.material = mesh.material[0];
}
/**
* Read texture map data chunk.
*
* @method readMap
* @param {Chunk} chunk Chunk in use.
* @param {String} path Path for external resources.
* @return {Texture} Texture read from this data chunk.
*/
readMap(chunk, path) {
let next = chunk.readChunk();
let texture = {};
const loader = new TextureLoader(this.manager);
loader.setPath(this.resourcePath || path).setCrossOrigin(this.crossOrigin);
while (next) {
if (next.id === MAT_MAPNAME) {
const name = next.readString();
texture = loader.load(name);
this.debugMessage(" File: " + path + name);
} else if (next.id === MAT_MAP_UOFFSET) {
texture.offset.x = next.readFloat();
this.debugMessage(" OffsetX: " + texture.offset.x);
} else if (next.id === MAT_MAP_VOFFSET) {
texture.offset.y = next.readFloat();
this.debugMessage(" OffsetY: " + texture.offset.y);
} else if (next.id === MAT_MAP_USCALE) {
texture.repeat.x = next.readFloat();
this.debugMessage(" RepeatX: " + texture.repeat.x);
} else if (next.id === MAT_MAP_VSCALE) {
texture.repeat.y = next.readFloat();
this.debugMessage(" RepeatY: " + texture.repeat.y);
} else {
this.debugMessage(" Unknown map chunk: " + next.hexId);
}
next = chunk.readChunk();
}
return texture;
}
/**
* Read material group data chunk.
*
* @method readMaterialGroup
* @param {Chunk} chunk Chunk in use.
* @return {Object} Object with name and index of the object.
*/
readMaterialGroup(chunk) {
const name = chunk.readString();
const numFaces = chunk.readWord();
this.debugMessage(" Name: " + name);
this.debugMessage(" Faces: " + numFaces);
const index = [];
for (let i = 0; i < numFaces; ++i) {
index.push(chunk.readWord());
}
return { name, index };
}
/**
* Read a color value.
*
* @method readColor
* @param {Chunk} chunk Chunk.
* @return {Color} Color value read..
*/
readColor(chunk) {
const subChunk = chunk.readChunk();
const color = new Color();
if (subChunk.id === COLOR_24 || subChunk.id === LIN_COLOR_24) {
const r = subChunk.readByte();
const g = subChunk.readByte();
const b = subChunk.readByte();
color.setRGB(r / 255, g / 255, b / 255);
this.debugMessage(" Color: " + color.r + ", " + color.g + ", " + color.b);
} else if (subChunk.id === COLOR_F || subChunk.id === LIN_COLOR_F) {
const r = subChunk.readFloat();
const g = subChunk.readFloat();
const b = subChunk.readFloat();
color.setRGB(r, g, b);
this.debugMessage(" Color: " + color.r + ", " + color.g + ", " + color.b);
} else {
this.debugMessage(" Unknown color chunk: " + subChunk.hexId);
}
return color;
}
/**
* Read percentage value.
*
* @method readPercentage
* @param {Chunk} chunk Chunk to read data from.
* @return {Number} Data read from the dataview.
*/
readPercentage(chunk) {
const subChunk = chunk.readChunk();
switch (subChunk.id) {
case INT_PERCENTAGE:
return subChunk.readShort() / 100;
case FLOAT_PERCENTAGE:
return subChunk.readFloat();
default:
this.debugMessage(" Unknown percentage chunk: " + subChunk.hexId);
return 0;
}
}
/**
* Print debug message to the console.
*
* Is controlled by a flag to show or hide debug messages.
*
* @method debugMessage
* @param {Object} message Debug message to print to the console.
*/
debugMessage(message) {
if (this.debug) {
console.log(message);
}
}
}
class Chunk {
/**
* Create a new chunk
*
* @class Chunk
* @param {DataView} data DataView to read from.
* @param {Number} position in data.
* @param {Function} debugMessage logging callback.
*/
constructor(data, position, debugMessage) {
this.data = data;
this.offset = position;
this.position = position;
this.debugMessage = debugMessage;
if (this.debugMessage instanceof Function) {
this.debugMessage = function() {
};
}
this.id = this.readWord();
this.size = this.readDWord();
this.end = this.offset + this.size;
if (this.end > data.byteLength) {
this.debugMessage("Bad chunk size for chunk at " + position);
}
}
/**
* read a sub cchunk.
*
* @method readChunk
* @return {Chunk | null} next sub chunk
*/
readChunk() {
if (this.endOfChunk) {
return null;
}
try {
const next = new Chunk(this.data, this.position, this.debugMessage);
this.position += next.size;
return next;
} catch (e) {
this.debugMessage("Unable to read chunk at " + this.position);
return null;
}
}
/**
* return the ID of this chunk as Hex
*
* @method idToString
* @return {String} hex-string of id
*/
get hexId() {
return this.id.toString(16);
}
get endOfChunk() {
return this.position >= this.end;
}
/**
* Read byte value.
*
* @method readByte
* @return {Number} Data read from the dataview.
*/
readByte() {
const v = this.data.getUint8(this.position, true);
this.position += 1;
return v;
}
/**
* Read 32 bit float value.
*
* @method readFloat
* @return {Number} Data read from the dataview.
*/
readFloat() {
try {
const v = this.data.getFloat32(this.position, true);
this.position += 4;
return v;
} catch (e) {
this.debugMessage(e + " " + this.position + " " + this.data.byteLength);
return 0;
}
}
/**
* Read 32 bit signed integer value.
*
* @method readInt
* @return {Number} Data read from the dataview.
*/
readInt() {
const v = this.data.getInt32(this.position, true);
this.position += 4;
return v;
}
/**
* Read 16 bit signed integer value.
*
* @method readShort
* @return {Number} Data read from the dataview.
*/
readShort() {
const v = this.data.getInt16(this.position, true);
this.position += 2;
return v;
}
/**
* Read 64 bit unsigned integer value.
*
* @method readDWord
* @return {Number} Data read from the dataview.
*/
readDWord() {
const v = this.data.getUint32(this.position, true);
this.position += 4;
return v;
}
/**
* Read 32 bit unsigned integer value.
*
* @method readWord
* @return {Number} Data read from the dataview.
*/
readWord() {
const v = this.data.getUint16(this.position, true);
this.position += 2;
return v;
}
/**
* Read NULL terminated ASCII string value from chunk-pos.
*
* @method readString
* @return {String} Data read from the dataview.
*/
readString() {
let s = "";
let c = this.readByte();
while (c) {
s += String.fromCharCode(c);
c = this.readByte();
}
return s;
}
}
const M3DMAGIC = 19789;
const MLIBMAGIC = 15786;
const CMAGIC = 49725;
const M3D_VERSION = 2;
const COLOR_F = 16;
const COLOR_24 = 17;
const LIN_COLOR_24 = 18;
const LIN_COLOR_F = 19;
const INT_PERCENTAGE = 48;
const FLOAT_PERCENTAGE = 49;
const MDATA = 15677;
const MESH_VERSION = 15678;
const MASTER_SCALE = 256;
const MAT_ENTRY = 45055;
const MAT_NAME = 40960;
const MAT_AMBIENT = 40976;
const MAT_DIFFUSE = 40992;
const MAT_SPECULAR = 41008;
const MAT_SHININESS = 41024;
const MAT_TRANSPARENCY = 41040;
const MAT_TWO_SIDE = 41089;
const MAT_ADDITIVE = 41091;
const MAT_WIRE = 41093;
const MAT_WIRE_SIZE = 41095;
const MAT_TEXMAP = 41472;
const MAT_OPACMAP = 41488;
const MAT_BUMPMAP = 41520;
const MAT_SPECMAP = 41476;
const MAT_MAPNAME = 41728;
const MAT_MAP_USCALE = 41812;
const MAT_MAP_VSCALE = 41814;
const MAT_MAP_UOFFSET = 41816;
const MAT_MAP_VOFFSET = 41818;
const NAMED_OBJECT = 16384;
const N_TRI_OBJECT = 16640;
const POINT_ARRAY = 16656;
const FACE_ARRAY = 16672;
const MSH_MAT_GROUP = 16688;
const TEX_VERTS = 16704;
const MESH_MATRIX = 16736;
/*!
fflate - fast JavaScript compression/decompression
<https://101arrowz.github.io/fflate>
Licensed under MIT. https://github.com/101arrowz/fflate/blob/master/LICENSE
version 0.6.9
*/
var durl = function(c) {
return URL.createObjectURL(new Blob([c], { type: "text/javascript" }));
};
try {
URL.revokeObjectURL(durl(""));
} catch (e) {
durl = function(c) {
return "data:application/javascript;charset=UTF-8," + encodeURI(c);
};
}
var u8 = Uint8Array, u16 = Uint16Array, u32 = Uint32Array;
var fleb = new u8([
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
1,
1,
2,
2,
2,
2,
3,
3,
3,
3,
4,
4,
4,
4,
5,
5,
5,
5,
0,
/* unused */
0,
0,
/* impossible */
0
]);
var fdeb = new u8([
0,
0,
0,
0,
1,
1,
2,
2,
3,
3,
4,
4,
5,
5,
6,
6,
7,
7,
8,
8,
9,
9,
10,
10,
11,
11,
12,
12,
13,
13,
/* unused */
0,
0
]);
var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
var freb = function(eb, start) {
var b = new u16(31);
for (var i = 0; i < 31; ++i) {
b[i] = start += 1 << eb[i - 1];
}
var r = new u32(b[30]);
for (var i = 1; i < 30; ++i) {
for (var j = b[i]; j < b[i + 1]; ++j) {
r[j] = j - b[i] << 5 | i;
}
}
return [b, r];
};
var _a = freb(fleb, 2), fl = _a[0], revfl = _a[1];
fl[28] = 258, revfl[258] = 28;
var _b = freb(fdeb, 0), fd = _b[0];
var rev = new u16(32768);
for (var i = 0; i < 32768; ++i) {
var x = (i & 43690) >>> 1 | (i & 21845) << 1;
x = (x & 52428) >>> 2 | (x & 13107) << 2;
x = (x & 61680) >>> 4 | (x & 3855) << 4;
rev[i] = ((x & 65280) >>> 8 | (x & 255) << 8) >>> 1;
}
var hMap = function(cd, mb, r) {
var s = cd.length;
var i = 0;
var l = new u16(mb);
for (; i < s; ++i)
++l[cd[i] - 1];
var le = new u16(mb);
for (i = 0; i < mb; ++i) {
le[i] = le[i - 1] + l[i - 1] << 1;
}
var co;
if (r) {
co = new u16(1 << mb);
var rvb = 15 - mb;
for (i = 0; i < s; ++i) {
if (cd[i]) {
var sv = i << 4 | cd[i];
var r_1 = mb - cd[i];
var v = le[cd[i] - 1]++ << r_1;
for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
co[rev[v] >>> rvb] = sv;
}
}
}
} else {
co = new u16(s);
for (i = 0; i < s; ++i) {
if (cd[i]) {
co[i] = rev[le[cd[i] - 1]++] >>> 15 - cd[i];
}
}
}
return co;
};
var flt = new u8(288);
for (var i = 0; i < 144; ++i)
flt[i] = 8;
for (var i = 144; i < 256; ++i)
flt[i] = 9;
for (var i = 256; i < 280; ++i)
flt[i] = 7;
for (var i = 280; i < 288; ++i)
flt[i] = 8;
var fdt = new u8(32);
for (var i = 0; i < 32; ++i)
fdt[i] = 5;
var flrm = /* @__PURE__ */ hMap(flt, 9, 1);
var fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
var max = function(a) {
var m = a[0];
for (var i = 1; i < a.length; ++i) {
if (a[i] > m)
m = a[i];
}
return m;
};
var bits = function(d, p, m) {
var o = p / 8 | 0;
return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
};
var bits16 = function(d, p) {
var o = p / 8 | 0;
return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
};
var shft = function(p) {
return (p / 8 | 0) + (p & 7 && 1);
};
var slc = function(v, s, e) {
if (s == null || s < 0)
s = 0;
if (e == null || e > v.length)
e = v.length;
var n = new (v instanceof u16 ? u16 : v instanceof u32 ? u32 : u8)(e - s);
n.set(v.subarray(s, e));
return n;
};
var inflt = function(dat, buf, st) {
var sl = dat.length;
if (!sl || st && !st.l && sl < 5)
return buf || new u8(0);
var noBuf = !buf || st;
var noSt = !st || st.i;
if (!st)
st = {};
if (!buf)
buf = new u8(sl * 3);
var cbuf = function(l2) {
var bl = buf.length;
if (l2 > bl) {
var nbuf = new u8(Math.max(bl * 2, l2));
nbuf.set(buf);
buf = nbuf;
}
};
var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;
var tbts = sl * 8;
do {
if (!lm) {
st.f = final = bits(dat, pos, 1);
var type = bits(dat, pos + 1, 3);
pos += 3;
if (!type) {
var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
if (t > sl) {
if (noSt)
throw "unexpected EOF";
break;
}
if (noBuf)
cbuf(bt + l);
buf.set(dat.subarray(s, t), bt);
st.b = bt += l, st.p = pos = t * 8;
continue;
} else if (type == 1)
lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
else if (type == 2) {
var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
var tl = hLit + bits(dat, pos + 5, 31) + 1;
pos += 14;
var ldt = new u8(tl);
var clt = new u8(19);
for (var i = 0; i < hcLen; ++i) {
clt[clim[i]] = bits(dat, pos + i * 3, 7);
}
pos += hcLen * 3;
var clb = max(clt), clbmsk = (1 << clb) - 1;
var clm = hMap(clt, clb, 1);
for (var i = 0; i < tl; ) {
var r = clm[bits(dat, pos, clbmsk)];
pos += r & 15;
var s = r >>> 4;
if (s < 16) {
ldt[i++] = s;
} else {
var c = 0, n = 0;
if (s == 16)
n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];
else if (s == 17)
n = 3 + bits(dat, pos, 7), pos += 3;
else if (s == 18)
n = 11 + bits(dat, pos, 127), pos += 7;
while (n--)
ldt[i++] = c;
}
}
var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
lbt = max(lt);
dbt = max(dt);
lm = hMap(lt, lbt, 1);
dm = hMap(dt, dbt, 1);
} else
throw "invalid block type";
if (pos > tbts) {
if (noSt)
throw "unexpected EOF";
break;
}
}
if (noBuf)
cbuf(bt + 131072);
var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
var lpos = pos;
for (; ; lpos = pos) {
var c = lm[bits16(dat, pos) & lms], sym = c >>> 4;
pos += c & 15;
if (pos > tbts) {
if (noSt)
throw "unexpected EOF";
break;
}
if (!c)
throw "invalid length/literal";
if (sym < 256)
buf[bt++] = sym;
else if (sym == 256) {
lpos = pos, lm = null;
break;
} else {
var add = sym - 254;
if (sym > 264) {
var i = sym - 257, b = fleb[i];
add = bits(dat, pos, (1 << b) - 1) + fl[i];
pos += b;
}
var d = dm[bits16(dat, pos) & dms], dsym = d >>> 4;
if (!d)
throw "invalid distance";
pos += d & 15;
var dt = fd[dsym];
if (dsym > 3) {
var b = fdeb[dsym];
dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
}
if (pos > tbts) {
if (noSt)
throw "unexpected EOF";
break;
}
if (noBuf)
cbuf(bt + 131072);
var end = bt + add;
for (; bt < end; bt += 4) {
buf[bt] = buf[bt - dt];
buf[bt + 1] = buf[bt + 1 - dt];
buf[bt + 2] = buf[bt + 2 - dt];
buf[bt + 3] = buf[bt + 3 - dt];
}
bt = end;
}
}
st.l = lm, st.p = lpos, st.b = bt;
if (lm)
final = 1, st.m = lbt, st.d = dm, st.n = dbt;
} while (!final);
return bt == buf.length ? buf : slc(buf, 0, bt);
};
var et$1 = /* @__PURE__ */ new u8(0);
var b2 = function(d, b) {
return d[b] | d[b + 1] << 8;
};
var b4 = function(d, b) {
return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
};
var b8 = function(d, b) {
return b4(d, b) + b4(d, b + 4) * 4294967296;
};
var zlv = function(d) {
if ((d[0] & 15) != 8 || d[0] >>> 4 > 7 || (d[0] << 8 | d[1]) % 31)
throw "invalid zlib data";
if (d[1] & 32)
throw "invalid zlib data: preset dictionaries not supported";
};
function inflateSync(data, out) {
return inflt(data, out);
}
function unzlibSync(data, out) {
return inflt((zlv(data), data.subarray(2, -4)), out);
}
var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
var tds = 0;
try {
td.decode(et$1, { stream: true });
tds = 1;
} catch (e) {
}
var dutf8 = function(d) {
for (var r = "", i = 0; ; ) {
var c = d[i++];
var eb = (c > 127) + (c > 223) + (c > 239);
if (i + eb > d.length)
return [r, slc(d, i - 1)];
if (!eb)
r += String.fromCharCode(c);
else if (eb == 3) {
c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | d[i++] & 63) - 65536, r += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023);
} else if (eb & 1)
r += String.fromCharCode((c & 31) << 6 | d[i++] & 63);
else
r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63);
}
};
function strFromU8(dat, latin1) {
if (latin1) {
var r = "";
for (var i = 0; i < dat.length; i += 16384)
r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));
return r;
} else if (td)
return td.decode(dat);
else {
var _a2 = dutf8(dat), out = _a2[0], ext = _a2[1];
if (ext.length)
throw "invalid utf-8 data";
return out;
}
}
var slzh = function(d, b) {
return b + 30 + b2(d, b + 26) + b2(d, b + 28);
};
var zh = function(d, b, z) {
var fnl = b2(d, b + 28), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl, bs = b4(d, b + 20);
var _a2 = z && bs == 4294967295 ? z64e(d, es) : [bs, b4(d, b + 24), b4(d, b + 42)], sc = _a2[0], su = _a2[1], off = _a2[2];
return [b2(d, b + 10), sc, su, fn, es + b2(d, b + 30) + b2(d, b + 32), off];
};
var z64e = function(d, b) {
for (; b2(d, b) != 1; b += 4 + b2(d, b + 2))
;
return [b8(d, b + 12), b8(d, b + 4), b8(d, b + 20)];
};
function unzipSync(data) {
var files = {};
var e = data.length - 22;
for (; b4(data, e) != 101010256; --e) {
if (!e || data.length - e > 65558)
throw "invalid zip file";
}
var c = b2(data, e + 8);
if (!c)
return {};
var o = b4(data, e + 16);
var z = o == 4294967295;
if (z) {
e = b4(data, e - 12);
if (b4(data, e) != 101075792)
throw "invalid zip file";
c = b4(data, e + 32);
o = b4(data, e + 48);
}
for (var i = 0; i < c; ++i) {
var _a2 = zh(data, o, z), c_2 = _a2[0], sc = _a2[1], su = _a2[2], fn = _a2[3], no = _a2[4], off = _a2[5], b = slzh(data, off);
o = no;
if (!c_2)
files[fn] = slc(data, b, b + sc);
else if (c_2 == 8)
files[fn] = inflateSync(data.subarray(b, b + sc), new u8(su));
else
throw "unknown compression type " + c_2;
}
return files;
}
const COLOR_SPACE_3MF = SRGBColorSpace;
class ThreeMFLoader extends Loader {
constructor(manager) {
super(manager);
this.availableExtensions = [];
}
load(url, onLoad, onProgress, onError) {
const scope = this;
const loader = new FileLoader(scope.manager);
loader.setPath(scope.path);
loader.setResponseType("arraybuffer");
loader.setRequestHeader(scope.requestHeader);
loader.setWithCredentials(scope.withCredentials);
loader.load(url, function(buffer) {
try {
onLoad(scope.parse(buffer));
} catch (e) {
if (onError) {
onError(e);
} else {
console.error(e);
}
scope.manager.itemError(url);
}
}, onProgress, onError);
}
parse(data) {
const scope = this;
const textureLoader = new TextureLoader(this.manager);
function loadDocument(data2) {
let zip = null;
let file = null;
let relsName;
let modelRelsName;
const modelPartNames = [];
const texturesPartNames = [];
let modelRels;
const modelParts = {};
const printTicketParts = {};
const texturesParts = {};
const textDecoder = new TextDecoder();
try {
zip = unzipSync(new Uint8Array(data2));
} catch (e) {
if (e instanceof ReferenceError) {
console.error("THREE.3MFLoader: fflate missing and file is compressed.");
return null;
}
}
for (file in zip) {
if (file.match(/\_rels\/.rels$/)) {
relsName = file;
} else if (file.match(/3D\/_rels\/.*\.model\.rels$/)) {
modelRelsName = file;
} else if (file.match(/^3D\/.*\.model$/)) {
modelPartNames.push(file);
} else if (file.match(/^3D\/Textures?\/.*/)) {
texturesPartNames.push(file);
}
}
const relsView = zip[relsName];
const relsFileText = textDecoder.decode(relsView);
const rels = parseRelsXml(relsFileText);
if (modelRelsName) {
const relsView2 = zip[modelRelsName];
const relsFileText2 = textDecoder.decode(relsView2);
modelRels = parseRelsXml(relsFileText2);
}
for (let i = 0; i < modelPartNames.length; i++) {
const modelPart = modelPartNames[i];
const view = zip[modelPart];
const fileText = textDecoder.decode(view);
const xmlData = new DOMParser().parseFromString(fileText, "application/xml");
if (xmlData.documentElement.nodeName.toLowerCase() !== "model") {
console.error("THREE.3MFLoader: Error loading 3MF - no 3MF document found: ", modelPart);
}
const modelNode = xmlData.querySelector("model");
const extensions = {};
for (let i2 = 0; i2 < modelNode.attributes.length; i2++) {
const attr = modelNode.attributes[i2];
if (attr.name.match(/^xmlns:(.+)$/)) {
extensions[attr.value] = RegExp.$1;
}
}
const modelData = parseModelNode(modelNode);
modelData["xml"] = modelNode;
if (0 < Object.keys(extensions).length) {
modelData["extensions"] = extensions;
}
modelParts[modelPart] = modelData;
}
for (let i = 0; i < texturesPartNames.length; i++) {
const texturesPartName = texturesPartNames[i];
texturesParts[texturesPartName] = zip[texturesPartName].buffer;
}
return {
rels,
modelRels,
model: modelParts,
printTicket: printTicketParts,
texture: texturesParts
};
}
function parseRelsXml(relsFileText) {
const relationships = [];
const relsXmlData = new DOMParser().parseFromString(relsFileText, "application/xml");
const relsNodes = relsXmlData.querySelectorAll("Relationship");
for (let i = 0; i < relsNodes.length; i++) {
const relsNode = relsNodes[i];
const relationship = {
target: relsNode.getAttribute("Target"),
//required
id: relsNode.getAttribute("Id"),
//required
type: relsNode.getAttribute("Type")
//required
};
relationships.push(relationship);
}
return relationships;
}
function parseMetadataNodes(metadataNodes) {
const metadataData = {};
for (let i = 0; i < metadataNodes.length; i++) {
const metadataNode = metadataNodes[i];
const name = metadataNode.getAttribute("name");
const validNames = [
"Title",
"Designer",
"Description",
"Copyright",
"LicenseTerms",
"Rating",
"CreationDate",
"ModificationDate"
];
if (0 <= validNames.indexOf(name)) {
metadataData[name] = metadataNode.textContent;
}
}
return metadataData;
}
function parseBasematerialsNode(basematerialsNode) {
const basematerialsData = {
id: basematerialsNode.getAttribute("id"),
// required
basematerials: []
};
const basematerialNodes = basematerialsNode.querySelectorAll("base");
for (let i = 0; i < basematerialNodes.length; i++) {
const basematerialNode = basematerialNodes[i];
const basematerialData = parseBasematerialNode(basematerialNode);
basematerialData.index = i;
basematerialsData.basematerials.push(basematerialData);
}
return basematerialsData;
}
function parseTexture2DNode(texture2DNode) {
const texture2dData = {
id: texture2DNode.getAttribute("id"),
// required
path: texture2DNode.getAttribute("path"),
// required
contenttype: texture2DNode.getAttribute("contenttype"),
// required
tilestyleu: texture2DNode.getAttribute("tilestyleu"),
tilestylev: texture2DNode.getAttribute("tilestylev"),
filter: texture2DNode.getAttribute("filter")
};
return texture2dData;
}
function parseTextures2DGroupNode(texture2DGroupNode) {
const texture2DGroupData = {
id: texture2DGroupNode.getAttribute("id"),
// required
texid: texture2DGroupNode.getAttribute("texid"),
// required
displaypropertiesid: texture2DGroupNode.getAttribute("displaypropertiesid")
};
const tex2coordNodes = texture2DGroupNode.querySelectorAll("tex2coord");
const uvs = [];
for (let i = 0; i < tex2coordNodes.length; i++) {
const tex2coordNode = tex2coordNodes[i];
const u = tex2coordNode.getAttribute("u");
const v = tex2coordNode.getAttribute("v");
uvs.push(parseFloat(u), parseFloat(v));
}
texture2DGroupData["uvs"] = new Float32Array(uvs);
return texture2DGroupData;
}
function parseColorGroupNode(colorGroupNode) {
const colorGroupData = {
id: colorGroupNode.getAttribute("id"),
// required
displaypropertiesid: colorGroupNode.getAttribute("displaypropertiesid")
};
const colorNodes = colorGroupNode.querySelectorAll("color");
const colors = [];
const colorObject = new Color();
for (let i = 0; i < colorNodes.length; i++) {
const colorNode = colorNodes[i];
const color = colorNode.getAttribute("color");
colorObject.setStyle(color.substring(0, 7), COLOR_SPACE_3MF);
colors.push(colorObject.r, colorObject.g, colorObject.b);
}
colorGroupData["colors"] = new Float32Array(colors);
return colorGroupData;
}
function parseMetallicDisplaypropertiesNode(metallicDisplaypropetiesNode) {
const metallicDisplaypropertiesData = {
id: metallicDisplaypropetiesNode.getAttribute("id")
// required
};
const metallicNodes = metallicDisplaypropetiesNode.querySelectorAll("pbmetallic");
const metallicData = [];
for (let i = 0; i < metallicNodes.length; i++) {
const metallicNode = metallicNodes[i];
metallicData.push({
name: metallicNode.getAttribute("name"),
// required
metallicness: parseFloat(metallicNode.getAttribute("metallicness")),
// required
roughness: parseFloat(metallicNode.getAttribute("roughness"))
// required
});
}
metallicDisplaypropertiesData.data = metallicData;
return metallicDisplaypropertiesData;
}
function parseBasematerialNode(basematerialNode) {
const basematerialData = {};
basematerialData["name"] = basematerialNode.getAttribute("name");
basematerialData["displaycolor"] = basematerialNode.getAttribute("displaycolor");
basematerialData["displaypropertiesid"] = basematerialNode.getAttribute("displaypropertiesid");
return basematerialData;
}
function parseMeshNode(meshNode) {
const meshData = {};
const vertices = [];
const vertexNodes = meshNode.querySelectorAll("vertices vertex");
for (let i = 0; i < vertexNodes.length; i++) {
const vertexNode = vertexNodes[i];
const x = vertexNode.getAttribute("x");
const y = vertexNode.getAttribute("y");
const z = vertexNode.getAttribute("z");
vertices.push(parseFloat(x), parseFloat(y), parseFloat(z));
}
meshData["vertices"] = new Float32Array(vertices);
const triangleProperties = [];
const triangles = [];
const triangleNodes = meshNode.querySelectorAll("triangles triangle");
for (let i = 0; i < triangleNodes.length; i++) {
const triangleNode = triangleNodes[i];
const v1 = triangleNode.getAttribute("v1");
const v2 = triangleNode.getAttribute("v2");
const v3 = triangleNode.getAttribute("v3");
const p1 = triangleNode.getAttribute("p1");
const p2 = triangleNode.getAttribute("p2");
const p3 = triangleNode.getAttribute("p3");
const pid = triangleNode.getAttribute("pid");
const triangleProperty = {};
triangleProperty["v1"] = parseInt(v1, 10);
triangleProperty["v2"] = parseInt(v2, 10);
triangleProperty["v3"] = parseInt(v3, 10);
triangles.push(triangleProperty["v1"], triangleProperty["v2"], triangleProperty["v3"]);
if (p1) {
triangleProperty["p1"] = parseInt(p1, 10);
}
if (p2) {
triangleProperty["p2"] = parseInt(p2, 10);
}
if (p3) {
triangleProperty["p3"] = parseInt(p3, 10);
}
if (pid) {
triangleProperty["pid"] = pid;
}
if (0 < Object.keys(triangleProperty).length) {
triangleProperties.push(triangleProperty);
}
}
meshData["triangleProperties"] = triangleProperties;
meshData["triangles"] = new Uint32Array(triangles);
return meshData;
}
function parseComponentsNode(componentsNode) {
const components = [];
const componentNodes = componentsNode.querySelectorAll("component");
for (let i = 0; i < componentNodes.length; i++) {
const componentNode = componentNodes[i];
const componentData = parseComponentNode(componentNode);
components.push(componentData);
}
return components;
}
function parseComponentNode(componentNode) {
const componentData = {};
componentData["objectId"] = componentNode.getAttribute("objectid");
const transform = componentNode.getAttribute("transform");
if (transform) {
componentData["transform"] = parseTransform(transform);
}
return componentData;
}
function parseTransform(transform) {
const t = [];
transform.split(" ").forEach(function(s) {
t.push(parseFloat(s));
});
const matrix = new Matrix4();
matrix.set(
t[0],
t[3],
t[6],
t[9],
t[1],
t[4],
t[7],
t[10],
t[2],
t[5],
t[8],
t[11],
0,
0,
0,
1
);
return matrix;
}
function parseObjectNode(objectNode) {
const objectData = {
type: objectNode.getAttribute("type")
};
const id = objectNode.getAttribute("id");
if (id) {
objectData["id"] = id;
}
const pid = objectNode.getAttribute("pid");
if (pid) {
objectData["pid"] = pid;
}
const pindex = objectNode.getAttribute("pindex");
if (pindex) {
objectData["pindex"] = pindex;
}
const thumbnail = objectNode.getAttribute("thumbnail");
if (thumbnail) {
objectData["thumbnail"] = thumbnail;
}
const partnumber = objectNode.getAttribute("partnumber");
if (partnumber) {
objectData["partnumber"] = partnumber;
}
const name = objectNode.getAttribute("name");
if (name) {
objectData["name"] = name;
}
const meshNode = objectNode.querySelector("mesh");
if (meshNode) {
objectData["mesh"] = parseMeshNode(meshNode);
}
const componentsNode = objectNode.querySelector("components");
if (componentsNode) {
objectData["components"] = parseComponentsNode(componentsNode);
}
return objectData;
}
function parseResourcesNode(resourcesNode) {
const resourcesData = {};
resourcesData["basematerials"] = {};
const basematerialsNodes = resourcesNode.querySelectorAll("basematerials");
for (let i = 0; i < basematerialsNodes.length; i++) {
const basematerialsNode = basematerialsNodes[i];
const basematerialsData = parseBasematerialsNode(basematerialsNode);
resourcesData["basematerials"][basematerialsData["id"]] = basematerialsData;
}
resourcesData["texture2d"] = {};
const textures2DNodes = resourcesNode.querySelectorAll("texture2d");
for (let i = 0; i < textures2DNodes.length; i++) {
const textures2DNode = textures2DNodes[i];
const texture2DData = parseTexture2DNode(textures2DNode);
resourcesData["texture2d"][texture2DData["id"]] = texture2DData;
}
resourcesData["colorgroup"] = {};
const colorGroupNodes = resourcesNode.querySelectorAll("colorgroup");
for (let i = 0; i < colorGroupNodes.length; i++) {
const colorGroupNode = colorGroupNodes[i];
const colorGroupData = parseColorGroupNode(colorGroupNode);
resourcesData["colorgroup"][colorGroupData["id"]] = colorGroupData;
}
resourcesData["pbmetallicdisplayproperties"] = {};
const pbmetallicdisplaypropertiesNodes = resourcesNode.querySelectorAll("pbmetallicdisplayproperties");
for (let i = 0; i < pbmetallicdisplaypropertiesNodes.length; i++) {
const pbmetallicdisplaypropertiesNode = pbmetallicdisplaypropertiesNodes[i];
const pbmetallicdisplaypropertiesData = parseMetallicDisplaypropertiesNode(pbmetallicdisplaypropertiesNode);
resourcesData["pbmetallicdisplayproperties"][pbmetallicdisplaypropertiesData["id"]] = pbmetallicdisplaypropertiesData;
}
resourcesData["texture2dgroup"] = {};
const textures2DGroupNodes = resourcesNode.querySelectorAll("texture2dgroup");
for (let i = 0; i < textures2DGroupNodes.length; i++) {
const textures2DGroupNode = textures2DGroupNodes[i];
const textures2DGroupData = parseTextures2DGroupNode(textures2DGroupNode);
resourcesData["texture2dgroup"][textures2DGroupData["id"]] = textures2DGroupData;
}
resourcesData["object"] = {};
const objectNodes = resourcesNode.querySelectorAll("object");
for (let i = 0; i < objectNodes.length; i++) {
const objectNode = objectNodes[i];
const objectData = parseObjectNode(objectNode);
resourcesData["object"][objectData["id"]] = objectData;
}
return resourcesData;
}
function parseBuildNode(buildNode) {
const buildData = [];
const itemNodes = buildNode.querySelectorAll("item");
for (let i = 0; i < itemNodes.length; i++) {
const itemNode = itemNodes[i];
const buildItem = {
objectId: itemNode.getAttribute("objectid")
};
const transform = itemNode.getAttribute("transform");
if (transform) {
buildItem["transform"] = parseTransform(transform);
}
buildData.push(buildItem);
}
return buildData;
}
function parseModelNode(modelNode) {
const modelData = { unit: modelNode.getAttribute("unit") || "millimeter" };
const metadataNodes = modelNode.querySelectorAll("metadata");
if (metadataNodes) {
modelData["metadata"] = parseMetadataNodes(metadataNodes);
}
const resourcesNode = modelNode.querySelector("resources");
if (resourcesNode) {
modelData["resources"] = parseResourcesNode(resourcesNode);
}
const buildNode = modelNode.querySelector("build");
if (buildNode) {
modelData["build"] = parseBuildNode(buildNode);
}
return modelData;
}
function buildTexture(texture2dgroup, objects2, modelData, textureData) {
const texid = texture2dgroup.texid;
const texture2ds = modelData.resources.texture2d;
const texture2d = texture2ds[texid];
if (texture2d) {
const data2 = textureData[texture2d.path];
const type = texture2d.contenttype;
const blob = new Blob([data2], { type });
const sourceURI = URL.createObjectURL(blob);
const texture = textureLoader.load(sourceURI, function() {
URL.revokeObjectURL(sourceURI);
});
texture.colorSpace = COLOR_SPACE_3MF;
switch (texture2d.tilestyleu) {
case "wrap":
texture.wrapS = RepeatWrapping;
break;
case "mirror":
texture.wrapS = MirroredRepeatWrapping;
break;
case "none":
case "clamp":
texture.wrapS = ClampToEdgeWrapping;
break;
default:
texture.wrapS = RepeatWrapping;
}
switch (texture2d.tilestylev) {
case "wrap":
texture.wrapT = RepeatWrapping;
break;
case "mirror":
texture.wrapT = MirroredRepeatWrapping;
break;
case "none":
case "clamp":
texture.wrapT = ClampToEdgeWrapping;
break;
default:
texture.wrapT = RepeatWrapping;
}
switch (texture2d.filter) {
case "auto":
texture.magFilter = LinearFilter;
texture.minFilter = LinearMipmapLinearFilter;
break;
case "linear":
texture.magFilter = LinearFilter;
texture.minFilter = LinearFilter;
break;
case "nearest":
texture.magFilter = NearestFilter;
texture.minFilter = NearestFilter;
break;
default:
texture.magFilter = LinearFilter;
texture.minFilter = LinearMipmapLinearFilter;
}
return texture;
} else {
return null;
}
}
function buildBasematerialsMeshes(basematerials, triangleProperties, meshData, objects2, modelData, textureData, objectData) {
const objectPindex = objectData.pindex;
const materialMap = {};
for (let i = 0, l = triangleProperties.length; i < l; i++) {
const triangleProperty = triangleProperties[i];
const pindex = triangleProperty.p1 !== void 0 ? triangleProperty.p1 : objectPindex;
if (m