@vctrl/hooks
Version:
vctrl/hooks is a React hooks package designed to simplify 3D model loading and management within React applications. It's part of the vectreal-core ecosystem and is primarily used in the vctrl/viewer React component and the official website application.
1,249 lines (1,247 loc) • 50.4 kB
JavaScript
import { PlaneGeometry as oe, ShaderMaterial as ae, Uniform as ce, SRGBColorSpace as se, Mesh as le, PerspectiveCamera as ue, Scene as j, WebGLRenderer as fe, CanvasTexture as he, Color as pe, Matrix4 as te, Vector3 as B, Quaternion as de, BufferAttribute as S, REVISION as xe, CompressedTexture as k, Source as ge, NoColorSpace as Te, MathUtils as q, RGBAFormat as me, DoubleSide as Me, PropertyBinding as P, InterpolateDiscrete as ye, NearestFilter as we, NearestMipmapNearestFilter as Ee, NearestMipmapLinearFilter as Ie, LinearFilter as Re, LinearMipmapNearestFilter as Ae, LinearMipmapLinearFilter as be, ClampToEdgeWrapping as Ne, RepeatWrapping as Se, MirroredRepeatWrapping as Le, InterpolateLinear as _e } from "three";
let F, H, _, D;
function V(a, e = 1 / 0, s = null) {
H || (H = new oe(2, 2, 1, 1)), _ || (_ = new ae({
uniforms: { blitTexture: new ce(a) },
vertexShader: `
varying vec2 vUv;
void main(){
vUv = uv;
gl_Position = vec4(position.xy * 1.0,0.,.999999);
}`,
fragmentShader: `
uniform sampler2D blitTexture;
varying vec2 vUv;
void main(){
gl_FragColor = vec4(vUv.xy, 0, 1);
#ifdef IS_SRGB
gl_FragColor = sRGBTransferOETF( texture2D( blitTexture, vUv) );
#else
gl_FragColor = texture2D( blitTexture, vUv);
#endif
}`
})), _.uniforms.blitTexture.value = a, _.defines.IS_SRGB = a.colorSpace == se, _.needsUpdate = !0, D || (D = new le(H, _), D.frustumCulled = !1);
const r = new ue(), t = new j();
t.add(D), s === null && (s = F = new fe({ antialias: !1 }));
const i = Math.min(a.image.width, e), n = Math.min(a.image.height, e);
s.setSize(i, n), s.clear(), s.render(t, r);
const o = document.createElement("canvas"), c = o.getContext("2d");
o.width = i, o.height = n, c.drawImage(s.domElement, 0, 0, i, n);
const l = new he(o);
return l.minFilter = a.minFilter, l.magFilter = a.magFilter, l.wrapS = a.wrapS, l.wrapT = a.wrapT, l.name = a.name, F && (F.forceContextLoss(), F.dispose(), F = null), l;
}
const X = {
POSITION: [
"byte",
"byte normalized",
"unsigned byte",
"unsigned byte normalized",
"short",
"short normalized",
"unsigned short",
"unsigned short normalized"
],
NORMAL: [
"byte normalized",
"short normalized"
],
TANGENT: [
"byte normalized",
"short normalized"
],
TEXCOORD: [
"byte",
"byte normalized",
"unsigned byte",
"short",
"short normalized",
"unsigned short"
]
};
class ne {
constructor() {
this.pluginCallbacks = [], this.register(function(e) {
return new ze(e);
}), this.register(function(e) {
return new ke(e);
}), this.register(function(e) {
return new Ke(e);
}), this.register(function(e) {
return new je(e);
}), this.register(function(e) {
return new qe(e);
}), this.register(function(e) {
return new We(e);
}), this.register(function(e) {
return new He(e);
}), this.register(function(e) {
return new Ve(e);
}), this.register(function(e) {
return new Ye(e);
}), this.register(function(e) {
return new Xe(e);
}), this.register(function(e) {
return new Je(e);
}), this.register(function(e) {
return new Qe(e);
}), this.register(function(e) {
return new Ze(e);
}), this.register(function(e) {
return new $e(e);
});
}
register(e) {
return this.pluginCallbacks.indexOf(e) === -1 && this.pluginCallbacks.push(e), this;
}
unregister(e) {
return this.pluginCallbacks.indexOf(e) !== -1 && this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(e), 1), this;
}
/**
* Parse scenes and generate GLTF output
* @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
* @param {Function} onDone Callback on completed
* @param {Function} onError Callback on errors
* @param {Object} options options
*/
parse(e, s, r, t) {
const i = new Pe(), n = [];
for (let o = 0, c = this.pluginCallbacks.length; o < c; o++)
n.push(this.pluginCallbacks[o](i));
i.setPlugins(n), i.write(e, s, t).catch(r);
}
parseAsync(e, s) {
const r = this;
return new Promise(function(t, i) {
r.parse(e, t, i, s);
});
}
}
const T = {
POINTS: 0,
LINES: 1,
LINE_LOOP: 2,
LINE_STRIP: 3,
TRIANGLES: 4,
BYTE: 5120,
UNSIGNED_BYTE: 5121,
SHORT: 5122,
UNSIGNED_SHORT: 5123,
INT: 5124,
UNSIGNED_INT: 5125,
FLOAT: 5126,
ARRAY_BUFFER: 34962,
ELEMENT_ARRAY_BUFFER: 34963,
NEAREST: 9728,
LINEAR: 9729,
NEAREST_MIPMAP_NEAREST: 9984,
LINEAR_MIPMAP_NEAREST: 9985,
NEAREST_MIPMAP_LINEAR: 9986,
LINEAR_MIPMAP_LINEAR: 9987,
CLAMP_TO_EDGE: 33071,
MIRRORED_REPEAT: 33648,
REPEAT: 10497
}, Y = "KHR_mesh_quantization", A = {};
A[we] = T.NEAREST;
A[Ee] = T.NEAREST_MIPMAP_NEAREST;
A[Ie] = T.NEAREST_MIPMAP_LINEAR;
A[Re] = T.LINEAR;
A[Ae] = T.LINEAR_MIPMAP_NEAREST;
A[be] = T.LINEAR_MIPMAP_LINEAR;
A[Ne] = T.CLAMP_TO_EDGE;
A[Se] = T.REPEAT;
A[Le] = T.MIRRORED_REPEAT;
const J = {
scale: "scale",
position: "translation",
quaternion: "rotation",
morphTargetInfluences: "weights"
}, Ce = new pe(), Q = 12, Ue = 1179937895, ve = 2, Z = 8, Fe = 1313821514, Oe = 5130562;
function O(a, e) {
return a.length === e.length && a.every(function(s, r) {
return s === e[r];
});
}
function Ge(a) {
return new TextEncoder().encode(a).buffer;
}
function De(a) {
return O(a.elements, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
}
function Be(a, e, s) {
const r = {
min: new Array(a.itemSize).fill(Number.POSITIVE_INFINITY),
max: new Array(a.itemSize).fill(Number.NEGATIVE_INFINITY)
};
for (let t = e; t < e + s; t++)
for (let i = 0; i < a.itemSize; i++) {
let n;
a.itemSize > 4 ? n = a.array[t * a.itemSize + i] : (i === 0 ? n = a.getX(t) : i === 1 ? n = a.getY(t) : i === 2 ? n = a.getZ(t) : i === 3 && (n = a.getW(t)), a.normalized === !0 && (n = q.normalize(n, a.array))), r.min[i] = Math.min(r.min[i], n), r.max[i] = Math.max(r.max[i], n);
}
return r;
}
function ie(a) {
return Math.ceil(a / 4) * 4;
}
function K(a, e = 0) {
const s = ie(a.byteLength);
if (s !== a.byteLength) {
const r = new Uint8Array(s);
if (r.set(new Uint8Array(a)), e !== 0)
for (let t = a.byteLength; t < s; t++)
r[t] = e;
return r.buffer;
}
return a;
}
function $() {
return typeof document > "u" && typeof OffscreenCanvas < "u" ? new OffscreenCanvas(1, 1) : document.createElement("canvas");
}
function ee(a, e) {
if (a.toBlob !== void 0)
return new Promise((r) => a.toBlob(r, e));
let s;
return e === "image/jpeg" ? s = 0.92 : e === "image/webp" && (s = 0.8), a.convertToBlob({
type: e,
quality: s
});
}
class Pe {
constructor() {
this.plugins = [], this.options = {}, this.pending = [], this.buffers = [], this.byteOffset = 0, this.buffers = [], this.nodeMap = /* @__PURE__ */ new Map(), this.skins = [], this.extensionsUsed = {}, this.extensionsRequired = {}, this.uids = /* @__PURE__ */ new Map(), this.uid = 0, this.json = {
asset: {
version: "2.0",
generator: "THREE.GLTFExporter r" + xe
}
}, this.cache = {
meshes: /* @__PURE__ */ new Map(),
attributes: /* @__PURE__ */ new Map(),
attributesNormalized: /* @__PURE__ */ new Map(),
materials: /* @__PURE__ */ new Map(),
textures: /* @__PURE__ */ new Map(),
images: /* @__PURE__ */ new Map()
};
}
setPlugins(e) {
this.plugins = e;
}
/**
* Parse scenes and generate GLTF output
* @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
* @param {Function} onDone Callback on completed
* @param {Object} options options
*/
async write(e, s, r = {}) {
this.options = Object.assign({
// default options
binary: !1,
trs: !1,
onlyVisible: !0,
maxTextureSize: 1 / 0,
animations: [],
includeCustomExtensions: !1
}, r), this.options.animations.length > 0 && (this.options.trs = !0), this.processInput(e), await Promise.all(this.pending);
const t = this, i = t.buffers, n = t.json;
r = t.options;
const o = t.extensionsUsed, c = t.extensionsRequired, l = new Blob(i, { type: "application/octet-stream" }), h = Object.keys(o), u = Object.keys(c);
if (h.length > 0 && (n.extensionsUsed = h), u.length > 0 && (n.extensionsRequired = u), n.buffers && n.buffers.length > 0 && (n.buffers[0].byteLength = l.size), r.binary === !0) {
const m = new FileReader();
m.readAsArrayBuffer(l), m.onloadend = function() {
const f = K(m.result), p = new DataView(new ArrayBuffer(Z));
p.setUint32(0, f.byteLength, !0), p.setUint32(4, Oe, !0);
const d = K(Ge(JSON.stringify(n)), 32), g = new DataView(new ArrayBuffer(Z));
g.setUint32(0, d.byteLength, !0), g.setUint32(4, Fe, !0);
const y = new ArrayBuffer(Q), b = new DataView(y);
b.setUint32(0, Ue, !0), b.setUint32(4, ve, !0);
const G = Q + g.byteLength + d.byteLength + p.byteLength + f.byteLength;
b.setUint32(8, G, !0);
const x = new Blob([
y,
g,
d,
p,
f
], { type: "application/octet-stream" }), M = new FileReader();
M.readAsArrayBuffer(x), M.onloadend = function() {
s(M.result);
};
};
} else if (n.buffers && n.buffers.length > 0) {
const m = new FileReader();
m.readAsDataURL(l), m.onloadend = function() {
const f = m.result;
n.buffers[0].uri = f, s(n);
};
} else
s(n);
}
/**
* Serializes a userData.
*
* @param {THREE.Object3D|THREE.Material} object
* @param {Object} objectDef
*/
serializeUserData(e, s) {
if (Object.keys(e.userData).length === 0) return;
const r = this.options, t = this.extensionsUsed;
try {
const i = JSON.parse(JSON.stringify(e.userData));
if (r.includeCustomExtensions && i.gltfExtensions) {
s.extensions === void 0 && (s.extensions = {});
for (const n in i.gltfExtensions)
s.extensions[n] = i.gltfExtensions[n], t[n] = !0;
delete i.gltfExtensions;
}
Object.keys(i).length > 0 && (s.extras = i);
} catch (i) {
console.warn("THREE.GLTFExporter: userData of '" + e.name + "' won't be serialized because of JSON.stringify error - " + i.message);
}
}
/**
* Returns ids for buffer attributes.
* @param {Object} object
* @return {Integer}
*/
getUID(e, s = !1) {
if (this.uids.has(e) === !1) {
const t = /* @__PURE__ */ new Map();
t.set(!0, this.uid++), t.set(!1, this.uid++), this.uids.set(e, t);
}
return this.uids.get(e).get(s);
}
/**
* Checks if normal attribute values are normalized.
*
* @param {BufferAttribute} normal
* @returns {Boolean}
*/
isNormalizedNormalAttribute(e) {
if (this.cache.attributesNormalized.has(e)) return !1;
const r = new B();
for (let t = 0, i = e.count; t < i; t++)
if (Math.abs(r.fromBufferAttribute(e, t).length() - 1) > 5e-4) return !1;
return !0;
}
/**
* Creates normalized normal buffer attribute.
*
* @param {BufferAttribute} normal
* @returns {BufferAttribute}
*
*/
createNormalizedNormalAttribute(e) {
const s = this.cache;
if (s.attributesNormalized.has(e)) return s.attributesNormalized.get(e);
const r = e.clone(), t = new B();
for (let i = 0, n = r.count; i < n; i++)
t.fromBufferAttribute(r, i), t.x === 0 && t.y === 0 && t.z === 0 ? t.setX(1) : t.normalize(), r.setXYZ(i, t.x, t.y, t.z);
return s.attributesNormalized.set(e, r), r;
}
/**
* Applies a texture transform, if present, to the map definition. Requires
* the KHR_texture_transform extension.
*
* @param {Object} mapDef
* @param {THREE.Texture} texture
*/
applyTextureTransform(e, s) {
let r = !1;
const t = {};
(s.offset.x !== 0 || s.offset.y !== 0) && (t.offset = s.offset.toArray(), r = !0), s.rotation !== 0 && (t.rotation = s.rotation, r = !0), (s.repeat.x !== 1 || s.repeat.y !== 1) && (t.scale = s.repeat.toArray(), r = !0), r && (e.extensions = e.extensions || {}, e.extensions.KHR_texture_transform = t, this.extensionsUsed.KHR_texture_transform = !0);
}
buildMetalRoughTexture(e, s) {
if (e === s) return e;
function r(f) {
return f.colorSpace === se ? function(d) {
return d < 0.04045 ? d * 0.0773993808 : Math.pow(d * 0.9478672986 + 0.0521327014, 2.4);
} : function(d) {
return d;
};
}
console.warn("THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures."), e instanceof k && (e = V(e)), s instanceof k && (s = V(s));
const t = e ? e.image : null, i = s ? s.image : null, n = Math.max(t ? t.width : 0, i ? i.width : 0), o = Math.max(t ? t.height : 0, i ? i.height : 0), c = $();
c.width = n, c.height = o;
const l = c.getContext("2d", {
willReadFrequently: !0
});
l.fillStyle = "#00ffff", l.fillRect(0, 0, n, o);
const h = l.getImageData(0, 0, n, o);
if (t) {
l.drawImage(t, 0, 0, n, o);
const f = r(e), p = l.getImageData(0, 0, n, o).data;
for (let d = 2; d < p.length; d += 4)
h.data[d] = f(p[d] / 256) * 256;
}
if (i) {
l.drawImage(i, 0, 0, n, o);
const f = r(s), p = l.getImageData(0, 0, n, o).data;
for (let d = 1; d < p.length; d += 4)
h.data[d] = f(p[d] / 256) * 256;
}
l.putImageData(h, 0, 0);
const m = (e || s).clone();
return m.source = new ge(c), m.colorSpace = Te, m.channel = (e || s).channel, e && s && e.channel !== s.channel && console.warn("THREE.GLTFExporter: UV channels for metalnessMap and roughnessMap textures must match."), m;
}
/**
* Process a buffer to append to the default one.
* @param {ArrayBuffer} buffer
* @return {Integer}
*/
processBuffer(e) {
const s = this.json, r = this.buffers;
return s.buffers || (s.buffers = [{ byteLength: 0 }]), r.push(e), 0;
}
/**
* Process and generate a BufferView
* @param {BufferAttribute} attribute
* @param {number} componentType
* @param {number} start
* @param {number} count
* @param {number} target (Optional) Target usage of the BufferView
* @return {Object}
*/
processBufferView(e, s, r, t, i) {
const n = this.json;
n.bufferViews || (n.bufferViews = []);
let o;
switch (s) {
case T.BYTE:
case T.UNSIGNED_BYTE:
o = 1;
break;
case T.SHORT:
case T.UNSIGNED_SHORT:
o = 2;
break;
default:
o = 4;
}
let c = e.itemSize * o;
i === T.ARRAY_BUFFER && (c = Math.ceil(c / 4) * 4);
const l = ie(t * c), h = new DataView(new ArrayBuffer(l));
let u = 0;
for (let p = r; p < r + t; p++) {
for (let d = 0; d < e.itemSize; d++) {
let g;
e.itemSize > 4 ? g = e.array[p * e.itemSize + d] : (d === 0 ? g = e.getX(p) : d === 1 ? g = e.getY(p) : d === 2 ? g = e.getZ(p) : d === 3 && (g = e.getW(p)), e.normalized === !0 && (g = q.normalize(g, e.array))), s === T.FLOAT ? h.setFloat32(u, g, !0) : s === T.INT ? h.setInt32(u, g, !0) : s === T.UNSIGNED_INT ? h.setUint32(u, g, !0) : s === T.SHORT ? h.setInt16(u, g, !0) : s === T.UNSIGNED_SHORT ? h.setUint16(u, g, !0) : s === T.BYTE ? h.setInt8(u, g) : s === T.UNSIGNED_BYTE && h.setUint8(u, g), u += o;
}
u % c !== 0 && (u += c - u % c);
}
const m = {
buffer: this.processBuffer(h.buffer),
byteOffset: this.byteOffset,
byteLength: l
};
return i !== void 0 && (m.target = i), i === T.ARRAY_BUFFER && (m.byteStride = c), this.byteOffset += l, n.bufferViews.push(m), {
id: n.bufferViews.length - 1,
byteLength: 0
};
}
/**
* Process and generate a BufferView from an image Blob.
* @param {Blob} blob
* @return {Promise<Integer>}
*/
processBufferViewImage(e) {
const s = this, r = s.json;
return r.bufferViews || (r.bufferViews = []), new Promise(function(t) {
const i = new FileReader();
i.readAsArrayBuffer(e), i.onloadend = function() {
const n = K(i.result), o = {
buffer: s.processBuffer(n),
byteOffset: s.byteOffset,
byteLength: n.byteLength
};
s.byteOffset += n.byteLength, t(r.bufferViews.push(o) - 1);
};
});
}
/**
* Process attribute to generate an accessor
* @param {BufferAttribute} attribute Attribute to process
* @param {THREE.BufferGeometry} geometry (Optional) Geometry used for truncated draw range
* @param {Integer} start (Optional)
* @param {Integer} count (Optional)
* @return {Integer|null} Index of the processed accessor on the "accessors" array
*/
processAccessor(e, s, r, t) {
const i = this.json, n = {
1: "SCALAR",
2: "VEC2",
3: "VEC3",
4: "VEC4",
9: "MAT3",
16: "MAT4"
};
let o;
if (e.array.constructor === Float32Array)
o = T.FLOAT;
else if (e.array.constructor === Int32Array)
o = T.INT;
else if (e.array.constructor === Uint32Array)
o = T.UNSIGNED_INT;
else if (e.array.constructor === Int16Array)
o = T.SHORT;
else if (e.array.constructor === Uint16Array)
o = T.UNSIGNED_SHORT;
else if (e.array.constructor === Int8Array)
o = T.BYTE;
else if (e.array.constructor === Uint8Array)
o = T.UNSIGNED_BYTE;
else
throw new Error("THREE.GLTFExporter: Unsupported bufferAttribute component type: " + e.array.constructor.name);
if (r === void 0 && (r = 0), (t === void 0 || t === 1 / 0) && (t = e.count), t === 0) return null;
const c = Be(e, r, t);
let l;
s !== void 0 && (l = e === s.index ? T.ELEMENT_ARRAY_BUFFER : T.ARRAY_BUFFER);
const h = this.processBufferView(e, o, r, t, l), u = {
bufferView: h.id,
byteOffset: h.byteOffset,
componentType: o,
count: t,
max: c.max,
min: c.min,
type: n[e.itemSize]
};
return e.normalized === !0 && (u.normalized = !0), i.accessors || (i.accessors = []), i.accessors.push(u) - 1;
}
/**
* Process image
* @param {Image} image to process
* @param {Integer} format of the image (RGBAFormat)
* @param {Boolean} flipY before writing out the image
* @param {String} mimeType export format
* @return {Integer} Index of the processed texture in the "images" array
*/
processImage(e, s, r, t = "image/png") {
if (e !== null) {
const i = this, n = i.cache, o = i.json, c = i.options, l = i.pending;
n.images.has(e) || n.images.set(e, {});
const h = n.images.get(e), u = t + ":flipY/" + r.toString();
if (h[u] !== void 0) return h[u];
o.images || (o.images = []);
const m = { mimeType: t }, f = $();
f.width = Math.min(e.width, c.maxTextureSize), f.height = Math.min(e.height, c.maxTextureSize);
const p = f.getContext("2d", {
willReadFrequently: !0
});
if (r === !0 && (p.translate(0, f.height), p.scale(1, -1)), e.data !== void 0) {
s !== me && console.error("GLTFExporter: Only RGBAFormat is supported.", s), (e.width > c.maxTextureSize || e.height > c.maxTextureSize) && console.warn("GLTFExporter: Image size is bigger than maxTextureSize", e);
const g = new Uint8ClampedArray(e.height * e.width * 4);
for (let y = 0; y < g.length; y += 4)
g[y + 0] = e.data[y + 0], g[y + 1] = e.data[y + 1], g[y + 2] = e.data[y + 2], g[y + 3] = e.data[y + 3];
p.putImageData(new ImageData(g, e.width, e.height), 0, 0);
} else if (typeof HTMLImageElement < "u" && e instanceof HTMLImageElement || typeof HTMLCanvasElement < "u" && e instanceof HTMLCanvasElement || typeof ImageBitmap < "u" && e instanceof ImageBitmap || typeof OffscreenCanvas < "u" && e instanceof OffscreenCanvas)
p.drawImage(e, 0, 0, f.width, f.height);
else
throw new Error("THREE.GLTFExporter: Invalid image type. Use HTMLImageElement, HTMLCanvasElement, ImageBitmap or OffscreenCanvas.");
c.binary === !0 ? l.push(
ee(f, t).then((g) => i.processBufferViewImage(g)).then((g) => {
m.bufferView = g;
})
) : f.toDataURL !== void 0 ? m.uri = f.toDataURL(t) : l.push(
ee(f, t).then((g) => new FileReader().readAsDataURL(g)).then((g) => {
m.uri = g;
})
);
const d = o.images.push(m) - 1;
return h[u] = d, d;
} else
throw new Error("THREE.GLTFExporter: No valid image data found. Unable to process texture.");
}
/**
* Process sampler
* @param {Texture} map Texture to process
* @return {Integer} Index of the processed texture in the "samplers" array
*/
processSampler(e) {
const s = this.json;
s.samplers || (s.samplers = []);
const r = {
magFilter: A[e.magFilter],
minFilter: A[e.minFilter],
wrapS: A[e.wrapS],
wrapT: A[e.wrapT]
};
return s.samplers.push(r) - 1;
}
/**
* Process texture
* @param {Texture} map Map to process
* @return {Integer} Index of the processed texture in the "textures" array
*/
processTexture(e) {
const r = this.options, t = this.cache, i = this.json;
if (t.textures.has(e)) return t.textures.get(e);
i.textures || (i.textures = []), e instanceof k && (e = V(e, r.maxTextureSize));
let n = e.userData.mimeType;
n === "image/webp" && (n = "image/png");
const o = {
sampler: this.processSampler(e),
source: this.processImage(e.image, e.format, e.flipY, n)
};
e.name && (o.name = e.name), this._invokeAll(function(l) {
l.writeTexture && l.writeTexture(e, o);
});
const c = i.textures.push(o) - 1;
return t.textures.set(e, c), c;
}
/**
* Process material
* @param {THREE.Material} material Material to process
* @return {Integer|null} Index of the processed material in the "materials" array
*/
processMaterial(e) {
const s = this.cache, r = this.json;
if (s.materials.has(e)) return s.materials.get(e);
if (e.isShaderMaterial)
return console.warn("GLTFExporter: THREE.ShaderMaterial not supported."), null;
r.materials || (r.materials = []);
const t = { pbrMetallicRoughness: {} };
e.isMeshStandardMaterial !== !0 && e.isMeshBasicMaterial !== !0 && console.warn("GLTFExporter: Use MeshStandardMaterial or MeshBasicMaterial for best results.");
const i = e.color.toArray().concat([e.opacity]);
if (O(i, [1, 1, 1, 1]) || (t.pbrMetallicRoughness.baseColorFactor = i), e.isMeshStandardMaterial ? (t.pbrMetallicRoughness.metallicFactor = e.metalness, t.pbrMetallicRoughness.roughnessFactor = e.roughness) : (t.pbrMetallicRoughness.metallicFactor = 0.5, t.pbrMetallicRoughness.roughnessFactor = 0.5), e.metalnessMap || e.roughnessMap) {
const o = this.buildMetalRoughTexture(e.metalnessMap, e.roughnessMap), c = {
index: this.processTexture(o),
channel: o.channel
};
this.applyTextureTransform(c, o), t.pbrMetallicRoughness.metallicRoughnessTexture = c;
}
if (e.map) {
const o = {
index: this.processTexture(e.map),
texCoord: e.map.channel
};
this.applyTextureTransform(o, e.map), t.pbrMetallicRoughness.baseColorTexture = o;
}
if (e.emissive) {
const o = e.emissive;
if (Math.max(o.r, o.g, o.b) > 0 && (t.emissiveFactor = e.emissive.toArray()), e.emissiveMap) {
const l = {
index: this.processTexture(e.emissiveMap),
texCoord: e.emissiveMap.channel
};
this.applyTextureTransform(l, e.emissiveMap), t.emissiveTexture = l;
}
}
if (e.normalMap) {
const o = {
index: this.processTexture(e.normalMap),
texCoord: e.normalMap.channel
};
e.normalScale && e.normalScale.x !== 1 && (o.scale = e.normalScale.x), this.applyTextureTransform(o, e.normalMap), t.normalTexture = o;
}
if (e.aoMap) {
const o = {
index: this.processTexture(e.aoMap),
texCoord: e.aoMap.channel
};
e.aoMapIntensity !== 1 && (o.strength = e.aoMapIntensity), this.applyTextureTransform(o, e.aoMap), t.occlusionTexture = o;
}
e.transparent ? t.alphaMode = "BLEND" : e.alphaTest > 0 && (t.alphaMode = "MASK", t.alphaCutoff = e.alphaTest), e.side === Me && (t.doubleSided = !0), e.name !== "" && (t.name = e.name), this.serializeUserData(e, t), this._invokeAll(function(o) {
o.writeMaterial && o.writeMaterial(e, t);
});
const n = r.materials.push(t) - 1;
return s.materials.set(e, n), n;
}
/**
* Process mesh
* @param {THREE.Mesh} mesh Mesh to process
* @return {Integer|null} Index of the processed mesh in the "meshes" array
*/
processMesh(e) {
const s = this.cache, r = this.json, t = [e.geometry.uuid];
if (Array.isArray(e.material))
for (let x = 0, M = e.material.length; x < M; x++)
t.push(e.material[x].uuid);
else
t.push(e.material.uuid);
const i = t.join(":");
if (s.meshes.has(i)) return s.meshes.get(i);
const n = e.geometry;
let o;
e.isLineSegments ? o = T.LINES : e.isLineLoop ? o = T.LINE_LOOP : e.isLine ? o = T.LINE_STRIP : e.isPoints ? o = T.POINTS : o = e.material.wireframe ? T.LINES : T.TRIANGLES;
const c = {}, l = {}, h = [], u = [], m = {
uv: "TEXCOORD_0",
uv1: "TEXCOORD_1",
uv2: "TEXCOORD_2",
uv3: "TEXCOORD_3",
color: "COLOR_0",
skinWeight: "WEIGHTS_0",
skinIndex: "JOINTS_0"
}, f = n.getAttribute("normal");
f !== void 0 && !this.isNormalizedNormalAttribute(f) && (console.warn("THREE.GLTFExporter: Creating normalized normal attribute from the non-normalized one."), n.setAttribute("normal", this.createNormalizedNormalAttribute(f)));
let p = null;
for (let x in n.attributes) {
if (x.slice(0, 5) === "morph") continue;
const M = n.attributes[x];
if (x = m[x] || x.toUpperCase(), /^(POSITION|NORMAL|TANGENT|TEXCOORD_\d+|COLOR_\d+|JOINTS_\d+|WEIGHTS_\d+)$/.test(x) || (x = "_" + x), s.attributes.has(this.getUID(M))) {
l[x] = s.attributes.get(this.getUID(M));
continue;
}
p = null;
const E = M.array;
x === "JOINTS_0" && !(E instanceof Uint16Array) && !(E instanceof Uint8Array) && (console.warn('GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.'), p = new S(new Uint16Array(E), M.itemSize, M.normalized));
const R = this.processAccessor(p || M, n);
R !== null && (x.startsWith("_") || this.detectMeshQuantization(x, M), l[x] = R, s.attributes.set(this.getUID(M), R));
}
if (f !== void 0 && n.setAttribute("normal", f), Object.keys(l).length === 0) return null;
if (e.morphTargetInfluences !== void 0 && e.morphTargetInfluences.length > 0) {
const x = [], M = [], w = {};
if (e.morphTargetDictionary !== void 0)
for (const E in e.morphTargetDictionary)
w[e.morphTargetDictionary[E]] = E;
for (let E = 0; E < e.morphTargetInfluences.length; ++E) {
const R = {};
let W = !1;
for (const C in n.morphAttributes) {
if (C !== "position" && C !== "normal") {
W || (console.warn("GLTFExporter: Only POSITION and NORMAL morph are supported."), W = !0);
continue;
}
const N = n.morphAttributes[C][E], z = C.toUpperCase(), U = n.attributes[C];
if (s.attributes.has(this.getUID(N, !0))) {
R[z] = s.attributes.get(this.getUID(N, !0));
continue;
}
const v = N.clone();
if (!n.morphTargetsRelative)
for (let I = 0, re = N.count; I < re; I++)
for (let L = 0; L < N.itemSize; L++)
L === 0 && v.setX(I, N.getX(I) - U.getX(I)), L === 1 && v.setY(I, N.getY(I) - U.getY(I)), L === 2 && v.setZ(I, N.getZ(I) - U.getZ(I)), L === 3 && v.setW(I, N.getW(I) - U.getW(I));
R[z] = this.processAccessor(v, n), s.attributes.set(this.getUID(U, !0), R[z]);
}
u.push(R), x.push(e.morphTargetInfluences[E]), e.morphTargetDictionary !== void 0 && M.push(w[E]);
}
c.weights = x, M.length > 0 && (c.extras = {}, c.extras.targetNames = M);
}
const d = Array.isArray(e.material);
if (d && n.groups.length === 0) return null;
let g = !1;
if (d && n.index === null) {
const x = [];
for (let M = 0, w = n.attributes.position.count; M < w; M++)
x[M] = M;
n.setIndex(x), g = !0;
}
const y = d ? e.material : [e.material], b = d ? n.groups : [{ materialIndex: 0, start: void 0, count: void 0 }];
for (let x = 0, M = b.length; x < M; x++) {
const w = {
mode: o,
attributes: l
};
if (this.serializeUserData(n, w), u.length > 0 && (w.targets = u), n.index !== null) {
let R = this.getUID(n.index);
(b[x].start !== void 0 || b[x].count !== void 0) && (R += ":" + b[x].start + ":" + b[x].count), s.attributes.has(R) ? w.indices = s.attributes.get(R) : (w.indices = this.processAccessor(n.index, n, b[x].start, b[x].count), s.attributes.set(R, w.indices)), w.indices === null && delete w.indices;
}
const E = this.processMaterial(y[b[x].materialIndex]);
E !== null && (w.material = E), h.push(w);
}
g === !0 && n.setIndex(null), c.primitives = h, r.meshes || (r.meshes = []), this._invokeAll(function(x) {
x.writeMesh && x.writeMesh(e, c);
});
const G = r.meshes.push(c) - 1;
return s.meshes.set(i, G), G;
}
/**
* If a vertex attribute with a
* [non-standard data type](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview)
* is used, it is checked whether it is a valid data type according to the
* [KHR_mesh_quantization](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_mesh_quantization/README.md)
* extension.
* In this case the extension is automatically added to the list of used extensions.
*
* @param {string} attributeName
* @param {THREE.BufferAttribute} attribute
*/
detectMeshQuantization(e, s) {
if (this.extensionsUsed[Y]) return;
let r;
switch (s.array.constructor) {
case Int8Array:
r = "byte";
break;
case Uint8Array:
r = "unsigned byte";
break;
case Int16Array:
r = "short";
break;
case Uint16Array:
r = "unsigned short";
break;
default:
return;
}
s.normalized && (r += " normalized");
const t = e.split("_", 1)[0];
X[t] && X[t].includes(r) && (this.extensionsUsed[Y] = !0, this.extensionsRequired[Y] = !0);
}
/**
* Process camera
* @param {THREE.Camera} camera Camera to process
* @return {Integer} Index of the processed mesh in the "camera" array
*/
processCamera(e) {
const s = this.json;
s.cameras || (s.cameras = []);
const r = e.isOrthographicCamera, t = {
type: r ? "orthographic" : "perspective"
};
return r ? t.orthographic = {
xmag: e.right * 2,
ymag: e.top * 2,
zfar: e.far <= 0 ? 1e-3 : e.far,
znear: e.near < 0 ? 0 : e.near
} : t.perspective = {
aspectRatio: e.aspect,
yfov: q.degToRad(e.fov),
zfar: e.far <= 0 ? 1e-3 : e.far,
znear: e.near < 0 ? 0 : e.near
}, e.name !== "" && (t.name = e.type), s.cameras.push(t) - 1;
}
/**
* Creates glTF animation entry from AnimationClip object.
*
* Status:
* - Only properties listed in PATH_PROPERTIES may be animated.
*
* @param {THREE.AnimationClip} clip
* @param {THREE.Object3D} root
* @return {number|null}
*/
processAnimation(e, s) {
const r = this.json, t = this.nodeMap;
r.animations || (r.animations = []), e = ne.Utils.mergeMorphTargetTracks(e.clone(), s);
const i = e.tracks, n = [], o = [];
for (let c = 0; c < i.length; ++c) {
const l = i[c], h = P.parseTrackName(l.name);
let u = P.findNode(s, h.nodeName);
const m = J[h.propertyName];
if (h.objectName === "bones" && (u.isSkinnedMesh === !0 ? u = u.skeleton.getBoneByName(h.objectIndex) : u = void 0), !u || !m) {
console.warn('THREE.GLTFExporter: Could not export animation track "%s".', l.name);
continue;
}
const f = 1;
let p = l.values.length / l.times.length;
m === J.morphTargetInfluences && (p /= u.morphTargetInfluences.length);
let d;
l.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline === !0 ? (d = "CUBICSPLINE", p /= 3) : l.getInterpolation() === ye ? d = "STEP" : d = "LINEAR", o.push({
input: this.processAccessor(new S(l.times, f)),
output: this.processAccessor(new S(l.values, p)),
interpolation: d
}), n.push({
sampler: o.length - 1,
target: {
node: t.get(u),
path: m
}
});
}
return r.animations.push({
name: e.name || "clip_" + r.animations.length,
samplers: o,
channels: n
}), r.animations.length - 1;
}
/**
* @param {THREE.Object3D} object
* @return {number|null}
*/
processSkin(e) {
const s = this.json, r = this.nodeMap, t = s.nodes[r.get(e)], i = e.skeleton;
if (i === void 0) return null;
const n = e.skeleton.bones[0];
if (n === void 0) return null;
const o = [], c = new Float32Array(i.bones.length * 16), l = new te();
for (let u = 0; u < i.bones.length; ++u)
o.push(r.get(i.bones[u])), l.copy(i.boneInverses[u]), l.multiply(e.bindMatrix).toArray(c, u * 16);
return s.skins === void 0 && (s.skins = []), s.skins.push({
inverseBindMatrices: this.processAccessor(new S(c, 16)),
joints: o,
skeleton: r.get(n)
}), t.skin = s.skins.length - 1;
}
/**
* Process Object3D node
* @param {THREE.Object3D} node Object3D to processNode
* @return {Integer} Index of the node in the nodes list
*/
processNode(e) {
const s = this.json, r = this.options, t = this.nodeMap;
s.nodes || (s.nodes = []);
const i = {};
if (r.trs) {
const o = e.quaternion.toArray(), c = e.position.toArray(), l = e.scale.toArray();
O(o, [0, 0, 0, 1]) || (i.rotation = o), O(c, [0, 0, 0]) || (i.translation = c), O(l, [1, 1, 1]) || (i.scale = l);
} else
e.matrixAutoUpdate && e.updateMatrix(), De(e.matrix) === !1 && (i.matrix = e.matrix.elements);
if (e.name !== "" && (i.name = String(e.name)), this.serializeUserData(e, i), e.isMesh || e.isLine || e.isPoints) {
const o = this.processMesh(e);
o !== null && (i.mesh = o);
} else e.isCamera && (i.camera = this.processCamera(e));
if (e.isSkinnedMesh && this.skins.push(e), e.children.length > 0) {
const o = [];
for (let c = 0, l = e.children.length; c < l; c++) {
const h = e.children[c];
if (h.visible || r.onlyVisible === !1) {
const u = this.processNode(h);
u !== null && o.push(u);
}
}
o.length > 0 && (i.children = o);
}
this._invokeAll(function(o) {
o.writeNode && o.writeNode(e, i);
});
const n = s.nodes.push(i) - 1;
return t.set(e, n), n;
}
/**
* Process Scene
* @param {Scene} node Scene to process
*/
processScene(e) {
const s = this.json, r = this.options;
s.scenes || (s.scenes = [], s.scene = 0);
const t = {};
e.name !== "" && (t.name = e.name), s.scenes.push(t);
const i = [];
for (let n = 0, o = e.children.length; n < o; n++) {
const c = e.children[n];
if (c.visible || r.onlyVisible === !1) {
const l = this.processNode(c);
l !== null && i.push(l);
}
}
i.length > 0 && (t.nodes = i), this.serializeUserData(e, t);
}
/**
* Creates a Scene to hold a list of objects and parse it
* @param {Array} objects List of objects to process
*/
processObjects(e) {
const s = new j();
s.name = "AuxScene";
for (let r = 0; r < e.length; r++)
s.children.push(e[r]);
this.processScene(s);
}
/**
* @param {THREE.Object3D|Array<THREE.Object3D>} input
*/
processInput(e) {
const s = this.options;
e = e instanceof Array ? e : [e], this._invokeAll(function(t) {
t.beforeParse && t.beforeParse(e);
});
const r = [];
for (let t = 0; t < e.length; t++)
e[t] instanceof j ? this.processScene(e[t]) : r.push(e[t]);
r.length > 0 && this.processObjects(r);
for (let t = 0; t < this.skins.length; ++t)
this.processSkin(this.skins[t]);
for (let t = 0; t < s.animations.length; ++t)
this.processAnimation(s.animations[t], e[0]);
this._invokeAll(function(t) {
t.afterParse && t.afterParse(e);
});
}
_invokeAll(e) {
for (let s = 0, r = this.plugins.length; s < r; s++)
e(this.plugins[s]);
}
}
class ze {
constructor(e) {
this.writer = e, this.name = "KHR_lights_punctual";
}
writeNode(e, s) {
if (!e.isLight) return;
if (!e.isDirectionalLight && !e.isPointLight && !e.isSpotLight) {
console.warn("THREE.GLTFExporter: Only directional, point, and spot lights are supported.", e);
return;
}
const r = this.writer, t = r.json, i = r.extensionsUsed, n = {};
e.name && (n.name = e.name), n.color = e.color.toArray(), n.intensity = e.intensity, e.isDirectionalLight ? n.type = "directional" : e.isPointLight ? (n.type = "point", e.distance > 0 && (n.range = e.distance)) : e.isSpotLight && (n.type = "spot", e.distance > 0 && (n.range = e.distance), n.spot = {}, n.spot.innerConeAngle = (1 - e.penumbra) * e.angle, n.spot.outerConeAngle = e.angle), e.decay !== void 0 && e.decay !== 2 && console.warn("THREE.GLTFExporter: Light decay may be lost. glTF is physically-based, and expects light.decay=2."), e.target && (e.target.parent !== e || e.target.position.x !== 0 || e.target.position.y !== 0 || e.target.position.z !== -1) && console.warn("THREE.GLTFExporter: Light direction may be lost. For best results, make light.target a child of the light with position 0,0,-1."), i[this.name] || (t.extensions = t.extensions || {}, t.extensions[this.name] = { lights: [] }, i[this.name] = !0);
const o = t.extensions[this.name].lights;
o.push(n), s.extensions = s.extensions || {}, s.extensions[this.name] = { light: o.length - 1 };
}
}
class ke {
constructor(e) {
this.writer = e, this.name = "KHR_materials_unlit";
}
writeMaterial(e, s) {
if (!e.isMeshBasicMaterial) return;
const t = this.writer.extensionsUsed;
s.extensions = s.extensions || {}, s.extensions[this.name] = {}, t[this.name] = !0, s.pbrMetallicRoughness.metallicFactor = 0, s.pbrMetallicRoughness.roughnessFactor = 0.9;
}
}
class He {
constructor(e) {
this.writer = e, this.name = "KHR_materials_clearcoat";
}
writeMaterial(e, s) {
if (!e.isMeshPhysicalMaterial || e.clearcoat === 0) return;
const r = this.writer, t = r.extensionsUsed, i = {};
if (i.clearcoatFactor = e.clearcoat, e.clearcoatMap) {
const n = {
index: r.processTexture(e.clearcoatMap),
texCoord: e.clearcoatMap.channel
};
r.applyTextureTransform(n, e.clearcoatMap), i.clearcoatTexture = n;
}
if (i.clearcoatRoughnessFactor = e.clearcoatRoughness, e.clearcoatRoughnessMap) {
const n = {
index: r.processTexture(e.clearcoatRoughnessMap),
texCoord: e.clearcoatRoughnessMap.channel
};
r.applyTextureTransform(n, e.clearcoatRoughnessMap), i.clearcoatRoughnessTexture = n;
}
if (e.clearcoatNormalMap) {
const n = {
index: r.processTexture(e.clearcoatNormalMap),
texCoord: e.clearcoatNormalMap.channel
};
e.clearcoatNormalScale.x !== 1 && (n.scale = e.clearcoatNormalScale.x), r.applyTextureTransform(n, e.clearcoatNormalMap), i.clearcoatNormalTexture = n;
}
s.extensions = s.extensions || {}, s.extensions[this.name] = i, t[this.name] = !0;
}
}
class Ve {
constructor(e) {
this.writer = e, this.name = "KHR_materials_dispersion";
}
writeMaterial(e, s) {
if (!e.isMeshPhysicalMaterial || e.dispersion === 0) return;
const t = this.writer.extensionsUsed, i = {};
i.dispersion = e.dispersion, s.extensions = s.extensions || {}, s.extensions[this.name] = i, t[this.name] = !0;
}
}
class Ye {
constructor(e) {
this.writer = e, this.name = "KHR_materials_iridescence";
}
writeMaterial(e, s) {
if (!e.isMeshPhysicalMaterial || e.iridescence === 0) return;
const r = this.writer, t = r.extensionsUsed, i = {};
if (i.iridescenceFactor = e.iridescence, e.iridescenceMap) {
const n = {
index: r.processTexture(e.iridescenceMap),
texCoord: e.iridescenceMap.channel
};
r.applyTextureTransform(n, e.iridescenceMap), i.iridescenceTexture = n;
}
if (i.iridescenceIor = e.iridescenceIOR, i.iridescenceThicknessMinimum = e.iridescenceThicknessRange[0], i.iridescenceThicknessMaximum = e.iridescenceThicknessRange[1], e.iridescenceThicknessMap) {
const n = {
index: r.processTexture(e.iridescenceThicknessMap),
texCoord: e.iridescenceThicknessMap.channel
};
r.applyTextureTransform(n, e.iridescenceThicknessMap), i.iridescenceThicknessTexture = n;
}
s.extensions = s.extensions || {}, s.extensions[this.name] = i, t[this.name] = !0;
}
}
class Ke {
constructor(e) {
this.writer = e, this.name = "KHR_materials_transmission";
}
writeMaterial(e, s) {
if (!e.isMeshPhysicalMaterial || e.transmission === 0) return;
const r = this.writer, t = r.extensionsUsed, i = {};
if (i.transmissionFactor = e.transmission, e.transmissionMap) {
const n = {
index: r.processTexture(e.transmissionMap),
texCoord: e.transmissionMap.channel
};
r.applyTextureTransform(n, e.transmissionMap), i.transmissionTexture = n;
}
s.extensions = s.extensions || {}, s.extensions[this.name] = i, t[this.name] = !0;
}
}
class je {
constructor(e) {
this.writer = e, this.name = "KHR_materials_volume";
}
writeMaterial(e, s) {
if (!e.isMeshPhysicalMaterial || e.transmission === 0) return;
const r = this.writer, t = r.extensionsUsed, i = {};
if (i.thicknessFactor = e.thickness, e.thicknessMap) {
const n = {
index: r.processTexture(e.thicknessMap),
texCoord: e.thicknessMap.channel
};
r.applyTextureTransform(n, e.thicknessMap), i.thicknessTexture = n;
}
e.attenuationDistance !== 1 / 0 && (i.attenuationDistance = e.attenuationDistance), i.attenuationColor = e.attenuationColor.toArray(), s.extensions = s.extensions || {}, s.extensions[this.name] = i, t[this.name] = !0;
}
}
class qe {
constructor(e) {
this.writer = e, this.name = "KHR_materials_ior";
}
writeMaterial(e, s) {
if (!e.isMeshPhysicalMaterial || e.ior === 1.5) return;
const t = this.writer.extensionsUsed, i = {};
i.ior = e.ior, s.extensions = s.extensions || {}, s.extensions[this.name] = i, t[this.name] = !0;
}
}
class We {
constructor(e) {
this.writer = e, this.name = "KHR_materials_specular";
}
writeMaterial(e, s) {
if (!e.isMeshPhysicalMaterial || e.specularIntensity === 1 && e.specularColor.equals(Ce) && !e.specularIntensityMap && !e.specularColorMap) return;
const r = this.writer, t = r.extensionsUsed, i = {};
if (e.specularIntensityMap) {
const n = {
index: r.processTexture(e.specularIntensityMap),
texCoord: e.specularIntensityMap.channel
};
r.applyTextureTransform(n, e.specularIntensityMap), i.specularTexture = n;
}
if (e.specularColorMap) {
const n = {
index: r.processTexture(e.specularColorMap),
texCoord: e.specularColorMap.channel
};
r.applyTextureTransform(n, e.specularColorMap), i.specularColorTexture = n;
}
i.specularFactor = e.specularIntensity, i.specularColorFactor = e.specularColor.toArray(), s.extensions = s.extensions || {}, s.extensions[this.name] = i, t[this.name] = !0;
}
}
class Xe {
constructor(e) {
this.writer = e, this.name = "KHR_materials_sheen";
}
writeMaterial(e, s) {
if (!e.isMeshPhysicalMaterial || e.sheen == 0) return;
const r = this.writer, t = r.extensionsUsed, i = {};
if (e.sheenRoughnessMap) {
const n = {
index: r.processTexture(e.sheenRoughnessMap),
texCoord: e.sheenRoughnessMap.channel
};
r.applyTextureTransform(n, e.sheenRoughnessMap), i.sheenRoughnessTexture = n;
}
if (e.sheenColorMap) {
const n = {
index: r.processTexture(e.sheenColorMap),
texCoord: e.sheenColorMap.channel
};
r.applyTextureTransform(n, e.sheenColorMap), i.sheenColorTexture = n;
}
i.sheenRoughnessFactor = e.sheenRoughness, i.sheenColorFactor = e.sheenColor.toArray(), s.extensions = s.extensions || {}, s.extensions[this.name] = i, t[this.name] = !0;
}
}
class Je {
constructor(e) {
this.writer = e, this.name = "KHR_materials_anisotropy";
}
writeMaterial(e, s) {
if (!e.isMeshPhysicalMaterial || e.anisotropy == 0) return;
const r = this.writer, t = r.extensionsUsed, i = {};
if (e.anisotropyMap) {
const n = { index: r.processTexture(e.anisotropyMap) };
r.applyTextureTransform(n, e.anisotropyMap), i.anisotropyTexture = n;
}
i.anisotropyStrength = e.anisotropy, i.anisotropyRotation = e.anisotropyRotation, s.extensions = s.extensions || {}, s.extensions[this.name] = i, t[this.name] = !0;
}
}
class Qe {
constructor(e) {
this.writer = e, this.name = "KHR_materials_emissive_strength";
}
writeMaterial(e, s) {
if (!e.isMeshStandardMaterial || e.emissiveIntensity === 1) return;
const t = this.writer.extensionsUsed, i = {};
i.emissiveStrength = e.emissiveIntensity, s.extensions = s.extensions || {}, s.extensions[this.name] = i, t[this.name] = !0;
}
}
class Ze {
constructor(e) {
this.writer = e, this.name = "EXT_materials_bump";
}
writeMaterial(e, s) {
if (!e.isMeshStandardMaterial || e.bumpScale === 1 && !e.bumpMap) return;
const r = this.writer, t = r.extensionsUsed, i = {};
if (e.bumpMap) {
const n = {
index: r.processTexture(e.bumpMap),
texCoord: e.bumpMap.channel
};
r.applyTextureTransform(n, e.bumpMap), i.bumpTexture = n;
}
i.bumpFactor = e.bumpScale, s.extensions = s.extensions || {}, s.extensions[this.name] = i, t[this.name] = !0;
}
}
class $e {
constructor(e) {
this.writer = e, this.name = "EXT_mesh_gpu_instancing";
}
writeNode(e, s) {
if (!e.isInstancedMesh) return;
const r = this.writer, t = e, i = new Float32Array(t.count * 3), n = new Float32Array(t.count * 4), o = new Float32Array(t.count * 3), c = new te(), l = new B(), h = new de(), u = new B();
for (let f = 0; f < t.count; f++)
t.getMatrixAt(f, c), c.decompose(l, h, u), l.toArray(i, f * 3), h.toArray(n, f * 4), u.toArray(o, f * 3);
const m = {
TRANSLATION: r.processAccessor(new S(i, 3)),
ROTATION: r.processAccessor(new S(n, 4)),
SCALE: r.processAccessor(new S(o, 3))
};
t.instanceColor && (m._COLOR_0 = r.processAccessor(t.instanceColor)), s.extensions = s.extensions || {}, s.extensions[this.name] = { attributes: m }, r.extensionsUsed[this.name] = !0, r.extensionsRequired[this.name] = !0;
}
}
ne.Utils = {
insertKeyframe: function(a, e) {
const r = a.getValueSize(), t = new a.TimeBufferType(a.times.length + 1), i = new a.ValueBufferType(a.values.length + r), n = a.createInterpolant(new a.ValueBufferType(r));
let o;
if (a.times.length === 0) {
t[0] = e;
for (let c = 0; c < r; c++)
i[c] = 0;
o = 0;
} else if (e < a.times[0]) {
if (Math.abs(a.times[0] - e) < 1e-3) return 0;
t[0] = e, t.set(a.times, 1), i.set(n.evaluate(e), 0), i.set(a.values, r), o = 0;
} else if (e > a.times[a.times.length - 1]) {
if (Math.abs(a.times[a.times.length - 1] - e) < 1e-3)
return a.times.length - 1;
t[t.length - 1] = e, t.set(a.times, 0), i.set(a.values, 0), i.set(n.evaluate(e), a.values.length), o = t.length - 1;
} else
for (let c = 0; c < a.times.length; c++) {
if (Math.abs(a.times[c] - e) < 1e-3) return c;
if (a.times[c] < e && a.times[c + 1] > e) {
t.set(a.times.slice(0, c + 1), 0), t[c + 1] = e, t.set(a.times.slice(c + 1), c + 2), i.set(a.values.slice(0, (c + 1) * r), 0), i.set(n.evaluate(e), (c + 1) * r), i.set(a.values.slice((c + 1) * r), (c + 2) * r), o = c + 1;
break;
}
}
return a.times = t, a.values = i, o;
},
mergeMorphTargetTracks: function(a, e) {
const s = [], r = {}, t = a.tracks;
for (let i = 0; i < t.length; ++i) {
let n = t[i];
const o = P.parseTrackName(n.name), c = P.findNode(e, o.nodeName);
if (o.propertyName !== "morphTargetInfluences" || o.propertyIndex === void 0) {
s.push(n);
continue;
}
if (n.createInterpolant !== n.InterpolantFactoryMethodDiscrete && n.createInterpolant !== n.InterpolantFactoryMethodLinear) {
if (n.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline)
throw new Error("THREE.GLTFExporter: Cannot merge tracks with glTF CUBICSPLINE interpolation.");
console.warn("THREE.GLTFExporter: Morph target interpolation mode not yet supported. Using LINEAR instead."), n = n.clone(), n.setInterpolation(_e);
}
const l = c.morphTargetInfluences.length, h = c.morphTargetDictionary[o.propertyIndex];
if (h === void 0)
throw new Error("THREE.GLTFExporter: Morph target name not found: " + o.propertyIndex);
let u;
if (r[c.uuid] === void 0) {
u = n.clone();
const f = new u.ValueBufferType(l * u.times.length);
for (let p = 0; p < u.times.length; p++)
f[p * l + h] = u.values[p];
u.name = (o.nodeName || "") + ".morphTargetInfluences", u.values = f, r[c.uuid] = u, s.push(u);
continue;
}
const m = n.cre