UNPKG

@realsee/dnalogel

Version:
1,107 lines 63.3 kB
import { Loader as oe, LoaderUtils as J, FileLoader as Le, TextureLoader as Ie, RepeatWrapping as ue, ClampToEdgeWrapping as fe, Texture as le, MeshPhongMaterial as N, MeshLambertMaterial as Pe, Color as F, sRGBEncoding as U, EquirectangularReflectionMapping as Fe, Matrix4 as m, Group as pe, Bone as ce, PropertyBinding as X, Object3D as ee, OrthographicCamera as Me, PerspectiveCamera as Se, PointLight as ve, MathUtils as x, SpotLight as Re, DirectionalLight as Oe, SkinnedMesh as Be, Mesh as be, LineBasicMaterial as ke, Line as De, Vector3 as G, Skeleton as Ce, AmbientLight as Ue, BufferGeometry as V, Float32BufferAttribute as O, Uint16BufferAttribute as Xe, Matrix3 as Ge, Vector4 as Ve, BufferAttribute as je, AnimationClip as ze, Quaternion as j, Euler as B, VectorKeyframeTrack as He, QuaternionKeyframeTrack as _e, NumberKeyframeTrack as Ke } from "three"; import { Zlib as he } from "../libs/inflate.js"; import { NURBSCurve as me } from "../libs/NURBSCurve.js"; var qe = function() { var v, y, T; function z(e) { oe.call(this, e); } z.prototype = Object.assign(Object.create(oe.prototype), { constructor: z, load: function(e, t, r, n) { var a = this, i = a.path === "" ? J.extractUrlBase(e) : a.path, s = new Le(this.manager); s.setPath(a.path), s.setResponseType("arraybuffer"), s.load( e, function(o) { try { t(a.parse(o, i)); } catch (f) { n ? n(f) : console.error(f), a.manager.itemError(e); } }, r, n ); }, parse: function(e, t) { if (ge(e)) v = new Y().parse(e); else { var r = ne(e); if (!ye(r)) throw new Error("THREE.FBXLoader: Unknown format."); if (te(r) < 7e3) throw new Error("THREE.FBXLoader: FBX version not supported, FileVersion: " + te(r)); v = new W().parse(r); } var n = new Ie(this.manager).setPath(this.resourcePath || t).setCrossOrigin(this.crossOrigin); return new H(n, this.manager).parse(v); } }); function H(e, t) { this.textureLoader = e, this.manager = t; } H.prototype = { constructor: H, parse: function() { y = this.parseConnections(); var e = this.parseImages(), t = this.parseTextures(e), r = this.parseMaterials(t), n = this.parseDeformers(), a = new _().parse(n); return this.parseScene(n, a, r), T; }, // Parses FBXTree.Connections which holds parent-child connections between objects (e.g. material -> texture, model->geometry ) // and details the connection type parseConnections: function() { var e = /* @__PURE__ */ new Map(); if ("Connections" in v) { var t = v.Connections.connections; t.forEach(function(r) { var n = r[0], a = r[1], i = r[2]; e.has(n) || e.set(n, { parents: [], children: [] }); var s = { ID: a, relationship: i }; e.get(n).parents.push(s), e.has(a) || e.set(a, { parents: [], children: [] }); var o = { ID: n, relationship: i }; e.get(a).children.push(o); }); } return e; }, // Parse FBXTree.Objects.Video for embedded image data // These images are connected to textures in FBXTree.Objects.Textures // via FBXTree.Connections. parseImages: function() { var e = {}, t = {}; if ("Video" in v.Objects) { var r = v.Objects.Video; for (var n in r) { var a = r[n], i = parseInt(n); if (e[i] = a.RelativeFilename || a.Filename, "Content" in a) { var s = a.Content instanceof ArrayBuffer && a.Content.byteLength > 0, o = typeof a.Content == "string" && a.Content !== ""; if (s || o) { var f = this.parseImage(r[n]); t[a.RelativeFilename || a.Filename] = f; } } } } for (var i in e) { var l = e[i]; t[l] !== void 0 ? e[i] = t[l] : e[i] = e[i].split("\\").pop(); } return e; }, // Parse embedded image data in FBXTree.Video.Content parseImage: function(e) { var t = e.Content, r = e.RelativeFilename || e.Filename, n = r.slice(r.lastIndexOf(".") + 1).toLowerCase(), a; switch (n) { case "bmp": a = "image/bmp"; break; case "jpg": case "jpeg": a = "image/jpeg"; break; case "png": a = "image/png"; break; case "tif": a = "image/tiff"; break; case "tga": this.manager.getHandler(".tga") === null && console.warn("FBXLoader: TGA loader not found, skipping ", r), a = "image/tga"; break; default: console.warn('FBXLoader: Image type "' + n + '" is not supported.'); return; } if (typeof t == "string") return "data:" + a + ";base64," + t; var i = new Uint8Array(t); return window.URL.createObjectURL(new Blob([i], { type: a })); }, // Parse nodes in FBXTree.Objects.Texture // These contain details such as UV scaling, cropping, rotation etc and are connected // to images in FBXTree.Objects.Video parseTextures: function(e) { var t = /* @__PURE__ */ new Map(); if ("Texture" in v.Objects) { var r = v.Objects.Texture; for (var n in r) { var a = this.parseTexture(r[n], e); t.set(parseInt(n), a); } } return t; }, // Parse individual node in FBXTree.Objects.Texture parseTexture: function(e, t) { var r = this.loadTexture(e, t); r.ID = e.id, r.name = e.attrName; var n = e.WrapModeU, a = e.WrapModeV, i = n !== void 0 ? n.value : 0, s = a !== void 0 ? a.value : 0; if (r.wrapS = i === 0 ? ue : fe, r.wrapT = s === 0 ? ue : fe, "Scaling" in e) { var o = e.Scaling.value; r.repeat.x = o[0], r.repeat.y = o[1]; } return r; }, // load a texture specified as a blob or data URI, or via an external URL using TextureLoader loadTexture: function(e, t) { var r, n = this.textureLoader.path, a = y.get(e.id).children; a !== void 0 && a.length > 0 && t[a[0].ID] !== void 0 && (r = t[a[0].ID], (r.indexOf("blob:") === 0 || r.indexOf("data:") === 0) && this.textureLoader.setPath(void 0)); var i, s = e.FileName.slice(-3).toLowerCase(); if (s === "tga") { var o = this.manager.getHandler(".tga"); o === null ? (console.warn("FBXLoader: TGA loader not found, creating placeholder texture for", e.RelativeFilename), i = new le()) : i = o.load(r); } else s === "psd" ? (console.warn("FBXLoader: PSD textures are not supported, creating placeholder texture for", e.RelativeFilename), i = new le()) : i = this.textureLoader.load(r); return this.textureLoader.setPath(n), i; }, // Parse nodes in FBXTree.Objects.Material parseMaterials: function(e) { var t = /* @__PURE__ */ new Map(); if ("Material" in v.Objects) { var r = v.Objects.Material; for (var n in r) { var a = this.parseMaterial(r[n], e); a !== null && t.set(parseInt(n), a); } } return t; }, // Parse single node in FBXTree.Objects.Material // Materials are connected to texture maps in FBXTree.Objects.Textures // FBX format currently only supports Lambert and Phong shading models parseMaterial: function(e, t) { var r = e.id, n = e.attrName, a = e.ShadingModel; if (typeof a == "object" && (a = a.value), !y.has(r)) return null; var i = this.parseParameters(e, t, r), s; switch (a.toLowerCase()) { case "phong": s = new N(); break; case "lambert": s = new Pe(); break; default: console.warn('THREE.FBXLoader: unknown material type "%s". Defaulting to MeshPhongMaterial.', a), s = new N(); break; } return s.setValues(i), s.name = n, s; }, // Parse FBX material and return parameters suitable for a three.js material // Also parse the texture map and return any textures associated with the material parseParameters: function(e, t, r) { var n = {}; e.BumpFactor && (n.bumpScale = e.BumpFactor.value), e.Diffuse ? n.color = new F().fromArray(e.Diffuse.value) : e.DiffuseColor && e.DiffuseColor.type === "Color" && (n.color = new F().fromArray(e.DiffuseColor.value)), e.DisplacementFactor && (n.displacementScale = e.DisplacementFactor.value), e.Emissive ? n.emissive = new F().fromArray(e.Emissive.value) : e.EmissiveColor && e.EmissiveColor.type === "Color" && (n.emissive = new F().fromArray(e.EmissiveColor.value)), e.EmissiveFactor && (n.emissiveIntensity = parseFloat(e.EmissiveFactor.value)), e.Opacity && (n.opacity = parseFloat(e.Opacity.value)), n.opacity < 1 && (n.transparent = !0), e.ReflectionFactor && (n.reflectivity = e.ReflectionFactor.value), e.Shininess && (n.shininess = e.Shininess.value), e.Specular ? n.specular = new F().fromArray(e.Specular.value) : e.SpecularColor && e.SpecularColor.type === "Color" && (n.specular = new F().fromArray(e.SpecularColor.value)); var a = this; return y.get(r).children.forEach(function(i) { var s = i.relationship; switch (s) { case "Bump": n.bumpMap = a.getTexture(t, i.ID); break; case "Maya|TEX_ao_map": n.aoMap = a.getTexture(t, i.ID); break; case "DiffuseColor": case "Maya|TEX_color_map": n.map = a.getTexture(t, i.ID), n.map.encoding = U; break; case "DisplacementColor": n.displacementMap = a.getTexture(t, i.ID); break; case "EmissiveColor": n.emissiveMap = a.getTexture(t, i.ID), n.emissiveMap.encoding = U; break; case "NormalMap": case "Maya|TEX_normal_map": n.normalMap = a.getTexture(t, i.ID); break; case "ReflectionColor": n.envMap = a.getTexture(t, i.ID), n.envMap.mapping = Fe, n.envMap.encoding = U; break; case "SpecularColor": n.specularMap = a.getTexture(t, i.ID), n.specularMap.encoding = U; break; case "TransparentColor": case "TransparencyFactor": n.alphaMap = a.getTexture(t, i.ID), n.transparent = !0; break; case "AmbientColor": case "ShininessExponent": case "SpecularFactor": case "VectorDisplacementColor": default: console.warn("THREE.FBXLoader: %s map is not supported in three.js, skipping texture.", s); break; } }), n; }, // get a texture from the textureMap for use by a material. getTexture: function(e, t) { return "LayeredTexture" in v.Objects && t in v.Objects.LayeredTexture && (console.warn("THREE.FBXLoader: layered textures are not supported in three.js. Discarding all but first layer."), t = y.get(t).children[0].ID), e.get(t); }, // Parse nodes in FBXTree.Objects.Deformer // Deformer node can contain skinning or Vertex Cache animation data, however only skinning is supported here // Generates map of Skeleton-like objects for use later when generating and binding skeletons. parseDeformers: function() { var e = {}, t = {}; if ("Deformer" in v.Objects) { var r = v.Objects.Deformer; for (var n in r) { var a = r[n], i = y.get(parseInt(n)); if (a.attrType === "Skin") { var s = this.parseSkeleton(i, r); s.ID = n, i.parents.length > 1 && console.warn("THREE.FBXLoader: skeleton attached to more than one geometry is not supported."), s.geometryID = i.parents[0].ID, e[n] = s; } else if (a.attrType === "BlendShape") { var o = { id: n }; o.rawTargets = this.parseMorphTargets(i, r), o.id = n, i.parents.length > 1 && console.warn("THREE.FBXLoader: morph target attached to more than one geometry is not supported."), t[n] = o; } } } return { skeletons: e, morphTargets: t }; }, // Parse single nodes in FBXTree.Objects.Deformer // The top level skeleton node has type 'Skin' and sub nodes have type 'Cluster' // Each skin node represents a skeleton and each cluster node represents a bone parseSkeleton: function(e, t) { var r = []; return e.children.forEach(function(n) { var a = t[n.ID]; if (a.attrType === "Cluster") { var i = { ID: n.ID, indices: [], weights: [], transformLink: new m().fromArray(a.TransformLink.a) // transform: new Matrix4().fromArray( boneNode.Transform.a ), // linkMode: boneNode.Mode, }; "Indexes" in a && (i.indices = a.Indexes.a, i.weights = a.Weights.a), r.push(i); } }), { rawBones: r, bones: [] }; }, // The top level morph deformer node has type "BlendShape" and sub nodes have type "BlendShapeChannel" parseMorphTargets: function(e, t) { for (var r = [], n = 0; n < e.children.length; n++) { var a = e.children[n], i = t[a.ID], s = { name: i.attrName, initialWeight: i.DeformPercent, id: i.id, fullWeights: i.FullWeights.a }; if (i.attrType !== "BlendShapeChannel") return; s.geoID = y.get(parseInt(a.ID)).children.filter(function(o) { return o.relationship === void 0; })[0].ID, r.push(s); } return r; }, // create the main Group() to be returned by the loader parseScene: function(e, t, r) { T = new pe(); var n = this.parseModels(e.skeletons, t, r), a = v.Objects.Model, i = this; n.forEach(function(o) { var f = a[o.ID]; i.setLookAtProperties(o, f); var l = y.get(o.ID).parents; l.forEach(function(u) { var p = n.get(u.ID); p !== void 0 && p.add(o); }), o.parent === null && T.add(o); }), this.bindSkeleton(e.skeletons, t, n), this.createAmbientLight(), this.setupMorphMaterials(), T.traverse(function(o) { if (o.userData.transformData) { o.parent && (o.userData.transformData.parentMatrixWorld = o.parent.matrix); var f = re(o.userData.transformData); o.applyMatrix4(f); } }); var s = new K().parse(); T.children.length === 1 && T.children[0].isGroup && (T.children[0].animations = s, T = T.children[0]), T.animations = s; }, // parse nodes in FBXTree.Objects.Model parseModels: function(e, t, r) { var n = /* @__PURE__ */ new Map(), a = v.Objects.Model; for (var i in a) { var s = parseInt(i), o = a[i], f = y.get(s), l = this.buildSkeleton(f, e, s, o.attrName); if (!l) { switch (o.attrType) { case "Camera": l = this.createCamera(f); break; case "Light": l = this.createLight(f); break; case "Mesh": l = this.createMesh(f, t, r); break; case "NurbsCurve": l = this.createCurve(f, t); break; case "LimbNode": case "Root": l = new ce(); break; case "Null": default: l = new pe(); break; } l.name = o.attrName ? X.sanitizeNodeName(o.attrName) : "", l.ID = s; } this.getTransformData(l, o), n.set(s, l); } return n; }, buildSkeleton: function(e, t, r, n) { var a = null; return e.parents.forEach(function(i) { for (var s in t) { var o = t[s]; o.rawBones.forEach(function(f, l) { if (f.ID === i.ID) { var u = a; a = new ce(), a.matrixWorld.copy(f.transformLink), a.name = n ? X.sanitizeNodeName(n) : "", a.ID = r, o.bones[l] = a, u !== null && a.add(u); } }); } }), a; }, // create a PerspectiveCamera or OrthographicCamera createCamera: function(e) { var t, r; if (e.children.forEach(function(p) { var c = v.Objects.NodeAttribute[p.ID]; c !== void 0 && (r = c); }), r === void 0) t = new ee(); else { var n = 0; r.CameraProjectionType !== void 0 && r.CameraProjectionType.value === 1 && (n = 1); var a = 1; r.NearPlane !== void 0 && (a = r.NearPlane.value / 1e3); var i = 1e3; r.FarPlane !== void 0 && (i = r.FarPlane.value / 1e3); var s = window.innerWidth, o = window.innerHeight; r.AspectWidth !== void 0 && r.AspectHeight !== void 0 && (s = r.AspectWidth.value, o = r.AspectHeight.value); var f = s / o, l = 45; r.FieldOfView !== void 0 && (l = r.FieldOfView.value); var u = r.FocalLength ? r.FocalLength.value : null; switch (n) { case 0: t = new Se(l, f, a, i), u !== null && t.setFocalLength(u); break; case 1: t = new Me(-s / 2, s / 2, o / 2, -o / 2, a, i); break; default: console.warn("THREE.FBXLoader: Unknown camera type " + n + "."), t = new ee(); break; } } return t; }, // Create a DirectionalLight, PointLight or SpotLight createLight: function(e) { var t, r; if (e.children.forEach(function(u) { var p = v.Objects.NodeAttribute[u.ID]; p !== void 0 && (r = p); }), r === void 0) t = new ee(); else { var n; r.LightType === void 0 ? n = 0 : n = r.LightType.value; var a = 16777215; r.Color !== void 0 && (a = new F().fromArray(r.Color.value)); var i = r.Intensity === void 0 ? 1 : r.Intensity.value / 100; r.CastLightOnObject !== void 0 && r.CastLightOnObject.value === 0 && (i = 0); var s = 0; r.FarAttenuationEnd !== void 0 && (r.EnableFarAttenuation !== void 0 && r.EnableFarAttenuation.value === 0 ? s = 0 : s = r.FarAttenuationEnd.value); var o = 1; switch (n) { case 0: t = new ve(a, i, s, o); break; case 1: t = new Oe(a, i); break; case 2: var f = Math.PI / 3; r.InnerAngle !== void 0 && (f = x.degToRad(r.InnerAngle.value)); var l = 0; r.OuterAngle !== void 0 && (l = x.degToRad(r.OuterAngle.value), l = Math.max(l, 1)), t = new Re(a, i, s, f, l, o); break; default: console.warn("THREE.FBXLoader: Unknown light type " + r.LightType.value + ", defaulting to a PointLight."), t = new ve(a, i); break; } r.CastShadows !== void 0 && r.CastShadows.value === 1 && (t.castShadow = !0); } return t; }, createMesh: function(e, t, r) { var n, a = null, i = null, s = []; return e.children.forEach(function(o) { t.has(o.ID) && (a = t.get(o.ID)), r.has(o.ID) && s.push(r.get(o.ID)); }), s.length > 1 ? i = s : s.length > 0 ? i = s[0] : (i = new N({ color: 13421772 }), s.push(i)), "color" in a.attributes && s.forEach(function(o) { o.vertexColors = !0; }), a.FBX_Deformer ? (s.forEach(function(o) { o.skinning = !0; }), n = new Be(a, i), n.normalizeSkinWeights()) : n = new be(a, i), n; }, createCurve: function(e, t) { var r = e.children.reduce(function(a, i) { return t.has(i.ID) && (a = t.get(i.ID)), a; }, null), n = new ke({ color: 3342591, linewidth: 1 }); return new De(r, n); }, // parse the model node for transform data getTransformData: function(e, t) { var r = {}; "InheritType" in t && (r.inheritType = parseInt(t.InheritType.value)), "RotationOrder" in t ? r.eulerOrder = ae(t.RotationOrder.value) : r.eulerOrder = "ZYX", "Lcl_Translation" in t && (r.translation = t.Lcl_Translation.value), "PreRotation" in t && (r.preRotation = t.PreRotation.value), "Lcl_Rotation" in t && (r.rotation = t.Lcl_Rotation.value), "PostRotation" in t && (r.postRotation = t.PostRotation.value), "Lcl_Scaling" in t && (r.scale = t.Lcl_Scaling.value), "ScalingOffset" in t && (r.scalingOffset = t.ScalingOffset.value), "ScalingPivot" in t && (r.scalingPivot = t.ScalingPivot.value), "RotationOffset" in t && (r.rotationOffset = t.RotationOffset.value), "RotationPivot" in t && (r.rotationPivot = t.RotationPivot.value), e.userData.transformData = r; }, setLookAtProperties: function(e, t) { if ("LookAtProperty" in t) { var r = y.get(e.ID).children; r.forEach(function(n) { if (n.relationship === "LookAtProperty") { var a = v.Objects.Model[n.ID]; if ("Lcl_Translation" in a) { var i = a.Lcl_Translation.value; e.target !== void 0 ? (e.target.position.fromArray(i), T.add(e.target)) : e.lookAt(new G().fromArray(i)); } } }); } }, bindSkeleton: function(e, t, r) { var n = this.parsePoseNodes(); for (var a in e) { var i = e[a], s = y.get(parseInt(i.ID)).parents; s.forEach(function(o) { if (t.has(o.ID)) { var f = o.ID, l = y.get(f); l.parents.forEach(function(u) { if (r.has(u.ID)) { var p = r.get(u.ID); p.bind(new Ce(i.bones), n[u.ID]); } }); } }); } }, parsePoseNodes: function() { var e = {}; if ("Pose" in v.Objects) { var t = v.Objects.Pose; for (var r in t) if (t[r].attrType === "BindPose") { var n = t[r].PoseNode; Array.isArray(n) ? n.forEach(function(a) { e[a.Node] = new m().fromArray(a.Matrix.a); }) : e[n.Node] = new m().fromArray(n.Matrix.a); } } return e; }, // Parse ambient color in FBXTree.GlobalSettings - if it's not set to black (default), create an ambient light createAmbientLight: function() { if ("GlobalSettings" in v && "AmbientColor" in v.GlobalSettings) { var e = v.GlobalSettings.AmbientColor.value, t = e[0], r = e[1], n = e[2]; if (t !== 0 || r !== 0 || n !== 0) { var a = new F(t, r, n); T.add(new Ue(a, 1)); } } }, setupMorphMaterials: function() { var e = this; T.traverse(function(t) { t.isMesh && t.geometry.morphAttributes.position && t.geometry.morphAttributes.position.length && (Array.isArray(t.material) ? t.material.forEach(function(r, n) { e.setupMorphMaterial(t, r, n); }) : e.setupMorphMaterial(t, t.material)); }); }, setupMorphMaterial: function(e, t, r) { var n = e.uuid, a = t.uuid, i = !1; if (T.traverse(function(o) { o.isMesh && (Array.isArray(o.material) ? o.material.forEach(function(f) { f.uuid === a && o.uuid !== n && (i = !0); }) : o.material.uuid === a && o.uuid !== n && (i = !0)); }), i === !0) { var s = t.clone(); s.morphTargets = !0, r === void 0 ? e.material = s : e.material[r] = s; } else t.morphTargets = !0; } }; function _() { } _.prototype = { constructor: _, // Parse nodes in FBXTree.Objects.Geometry parse: function(e) { var t = /* @__PURE__ */ new Map(); if ("Geometry" in v.Objects) { var r = v.Objects.Geometry; for (var n in r) { var a = y.get(parseInt(n)), i = this.parseGeometry(a, r[n], e); t.set(parseInt(n), i); } } return t; }, // Parse single node in FBXTree.Objects.Geometry parseGeometry: function(e, t, r) { switch (t.attrType) { case "Mesh": return this.parseMeshGeometry(e, t, r); case "NurbsCurve": return this.parseNurbsGeometry(t); } }, // Parse single node mesh geometry in FBXTree.Objects.Geometry parseMeshGeometry: function(e, t, r) { var n = r.skeletons, a = [], i = e.parents.map(function(u) { return v.Objects.Model[u.ID]; }); if (i.length !== 0) { var s = e.children.reduce(function(u, p) { return n[p.ID] !== void 0 && (u = n[p.ID]), u; }, null); e.children.forEach(function(u) { r.morphTargets[u.ID] !== void 0 && a.push(r.morphTargets[u.ID]); }); var o = i[0], f = {}; "RotationOrder" in o && (f.eulerOrder = ae(o.RotationOrder.value)), "InheritType" in o && (f.inheritType = parseInt(o.InheritType.value)), "GeometricTranslation" in o && (f.translation = o.GeometricTranslation.value), "GeometricRotation" in o && (f.rotation = o.GeometricRotation.value), "GeometricScaling" in o && (f.scale = o.GeometricScaling.value); var l = re(f); return this.genGeometry(t, s, a, l); } }, // Generate a BufferGeometry from a node in FBXTree.Objects.Geometry genGeometry: function(e, t, r, n) { var a = new V(); e.attrName && (a.name = e.attrName); var i = this.parseGeoNode(e, t), s = this.genBuffers(i), o = new O(s.vertex, 3); if (o.applyMatrix4(n), a.setAttribute("position", o), s.colors.length > 0 && a.setAttribute("color", new O(s.colors, 3)), t && (a.setAttribute("skinIndex", new Xe(s.weightsIndices, 4)), a.setAttribute("skinWeight", new O(s.vertexWeights, 4)), a.FBX_Deformer = t), s.normal.length > 0) { var f = new Ge().getNormalMatrix(n), l = new O(s.normal, 3); l.applyNormalMatrix(f), a.setAttribute("normal", l); } if (s.uvs.forEach(function(w, g) { var d = "uv" + (g + 1).toString(); g === 0 && (d = "uv"), a.setAttribute(d, new O(s.uvs[g], 2)); }), i.material && i.material.mappingType !== "AllSame") { var u = s.materialIndex[0], p = 0; if (s.materialIndex.forEach(function(w, g) { w !== u && (a.addGroup(p, g - p, u), u = w, p = g); }), a.groups.length > 0) { var c = a.groups[a.groups.length - 1], h = c.start + c.count; h !== s.materialIndex.length && a.addGroup(h, s.materialIndex.length - h, u); } a.groups.length === 0 && a.addGroup(0, s.materialIndex.length, s.materialIndex[0]); } return this.addMorphTargets(a, e, r, n), a; }, parseGeoNode: function(e, t) { var r = {}; if (r.vertexPositions = e.Vertices !== void 0 ? e.Vertices.a : [], r.vertexIndices = e.PolygonVertexIndex !== void 0 ? e.PolygonVertexIndex.a : [], e.LayerElementColor && (r.color = this.parseVertexColors(e.LayerElementColor[0])), e.LayerElementMaterial && (r.material = this.parseMaterialIndices(e.LayerElementMaterial[0])), e.LayerElementNormal && (r.normal = this.parseNormals(e.LayerElementNormal[0])), e.LayerElementUV) { r.uv = []; for (var n = 0; e.LayerElementUV[n]; ) r.uv.push(this.parseUVs(e.LayerElementUV[n])), n++; } return r.weightTable = {}, t !== null && (r.skeleton = t, t.rawBones.forEach(function(a, i) { a.indices.forEach(function(s, o) { r.weightTable[s] === void 0 && (r.weightTable[s] = []), r.weightTable[s].push({ id: i, weight: a.weights[o] }); }); })), r; }, genBuffers: function(e) { var t = { vertex: [], normal: [], colors: [], uvs: [], materialIndex: [], vertexWeights: [], weightsIndices: [] }, r = 0, n = 0, a = !1, i = [], s = [], o = [], f = [], l = [], u = [], p = this; return e.vertexIndices.forEach(function(c, h) { var w = !1; c < 0 && (c = c ^ -1, w = !0); var g = [], d = []; if (i.push(c * 3, c * 3 + 1, c * 3 + 2), e.color) { var A = D(h, r, c, e.color); o.push(A[0], A[1], A[2]); } if (e.skeleton) { if (e.weightTable[c] !== void 0 && e.weightTable[c].forEach(function(I) { d.push(I.weight), g.push(I.id); }), d.length > 4) { a || (console.warn("THREE.FBXLoader: Vertex has more than 4 skinning weights assigned to vertex. Deleting additional weights."), a = !0); var L = [0, 0, 0, 0], S = [0, 0, 0, 0]; d.forEach(function(I, E) { var P = I, C = g[E]; S.forEach(function(se, Q, Ee) { if (P > se) { Ee[Q] = P, P = se; var xe = L[Q]; L[Q] = C, C = xe; } }); }), g = L, d = S; } for (; d.length < 4; ) d.push(0), g.push(0); for (var R = 0; R < 4; ++R) l.push(d[R]), u.push(g[R]); } if (e.normal) { var A = D(h, r, c, e.normal); s.push(A[0], A[1], A[2]); } if (e.material && e.material.mappingType !== "AllSame") var $ = D(h, r, c, e.material)[0]; e.uv && e.uv.forEach(function(I, E) { var P = D(h, r, c, I); f[E] === void 0 && (f[E] = []), f[E].push(P[0]), f[E].push(P[1]); }), n++, w && (p.genFace( t, e, i, $, s, o, f, l, u, n ), r++, n = 0, i = [], s = [], o = [], f = [], l = [], u = []); }), t; }, // Generate data for a single face in a geometry. If the face is a quad then split it into 2 tris genFace: function(e, t, r, n, a, i, s, o, f, l) { for (var u = 2; u < l; u++) e.vertex.push(t.vertexPositions[r[0]]), e.vertex.push(t.vertexPositions[r[1]]), e.vertex.push(t.vertexPositions[r[2]]), e.vertex.push(t.vertexPositions[r[(u - 1) * 3]]), e.vertex.push(t.vertexPositions[r[(u - 1) * 3 + 1]]), e.vertex.push(t.vertexPositions[r[(u - 1) * 3 + 2]]), e.vertex.push(t.vertexPositions[r[u * 3]]), e.vertex.push(t.vertexPositions[r[u * 3 + 1]]), e.vertex.push(t.vertexPositions[r[u * 3 + 2]]), t.skeleton && (e.vertexWeights.push(o[0]), e.vertexWeights.push(o[1]), e.vertexWeights.push(o[2]), e.vertexWeights.push(o[3]), e.vertexWeights.push(o[(u - 1) * 4]), e.vertexWeights.push(o[(u - 1) * 4 + 1]), e.vertexWeights.push(o[(u - 1) * 4 + 2]), e.vertexWeights.push(o[(u - 1) * 4 + 3]), e.vertexWeights.push(o[u * 4]), e.vertexWeights.push(o[u * 4 + 1]), e.vertexWeights.push(o[u * 4 + 2]), e.vertexWeights.push(o[u * 4 + 3]), e.weightsIndices.push(f[0]), e.weightsIndices.push(f[1]), e.weightsIndices.push(f[2]), e.weightsIndices.push(f[3]), e.weightsIndices.push(f[(u - 1) * 4]), e.weightsIndices.push(f[(u - 1) * 4 + 1]), e.weightsIndices.push(f[(u - 1) * 4 + 2]), e.weightsIndices.push(f[(u - 1) * 4 + 3]), e.weightsIndices.push(f[u * 4]), e.weightsIndices.push(f[u * 4 + 1]), e.weightsIndices.push(f[u * 4 + 2]), e.weightsIndices.push(f[u * 4 + 3])), t.color && (e.colors.push(i[0]), e.colors.push(i[1]), e.colors.push(i[2]), e.colors.push(i[(u - 1) * 3]), e.colors.push(i[(u - 1) * 3 + 1]), e.colors.push(i[(u - 1) * 3 + 2]), e.colors.push(i[u * 3]), e.colors.push(i[u * 3 + 1]), e.colors.push(i[u * 3 + 2])), t.material && t.material.mappingType !== "AllSame" && (e.materialIndex.push(n), e.materialIndex.push(n), e.materialIndex.push(n)), t.normal && (e.normal.push(a[0]), e.normal.push(a[1]), e.normal.push(a[2]), e.normal.push(a[(u - 1) * 3]), e.normal.push(a[(u - 1) * 3 + 1]), e.normal.push(a[(u - 1) * 3 + 2]), e.normal.push(a[u * 3]), e.normal.push(a[u * 3 + 1]), e.normal.push(a[u * 3 + 2])), t.uv && t.uv.forEach(function(p, c) { e.uvs[c] === void 0 && (e.uvs[c] = []), e.uvs[c].push(s[c][0]), e.uvs[c].push(s[c][1]), e.uvs[c].push(s[c][(u - 1) * 2]), e.uvs[c].push(s[c][(u - 1) * 2 + 1]), e.uvs[c].push(s[c][u * 2]), e.uvs[c].push(s[c][u * 2 + 1]); }); }, addMorphTargets: function(e, t, r, n) { if (r.length !== 0) { e.morphTargetsRelative = !0, e.morphAttributes.position = []; var a = this; r.forEach(function(i) { i.rawTargets.forEach(function(s) { var o = v.Objects.Geometry[s.geoID]; o !== void 0 && a.genMorphGeometry(e, t, o, n, s.name); }); }); } }, // a morph geometry node is similar to a standard node, and the node is also contained // in FBXTree.Objects.Geometry, however it can only have attributes for position, normal // and a special attribute Index defining which vertices of the original geometry are affected // Normal and position attributes only have data for the vertices that are affected by the morph genMorphGeometry: function(e, t, r, n, a) { for (var i = t.PolygonVertexIndex !== void 0 ? t.PolygonVertexIndex.a : [], s = r.Vertices !== void 0 ? r.Vertices.a : [], o = r.Indexes !== void 0 ? r.Indexes.a : [], f = e.attributes.position.count * 3, l = new Float32Array(f), u = 0; u < o.length; u++) { var p = o[u] * 3; l[p] = s[u * 3], l[p + 1] = s[u * 3 + 1], l[p + 2] = s[u * 3 + 2]; } var c = { vertexIndices: i, vertexPositions: l }, h = this.genBuffers(c), w = new O(h.vertex, 3); w.name = a || r.attrName, w.applyMatrix4(n), e.morphAttributes.position.push(w); }, // Parse normal from FBXTree.Objects.Geometry.LayerElementNormal if it exists parseNormals: function(e) { var t = e.MappingInformationType, r = e.ReferenceInformationType, n = e.Normals.a, a = []; return r === "IndexToDirect" && ("NormalIndex" in e ? a = e.NormalIndex.a : "NormalsIndex" in e && (a = e.NormalsIndex.a)), { dataSize: 3, buffer: n, indices: a, mappingType: t, referenceType: r }; }, // Parse UVs from FBXTree.Objects.Geometry.LayerElementUV if it exists parseUVs: function(e) { var t = e.MappingInformationType, r = e.ReferenceInformationType, n = e.UV.a, a = []; return r === "IndexToDirect" && (a = e.UVIndex.a), { dataSize: 2, buffer: n, indices: a, mappingType: t, referenceType: r }; }, // Parse Vertex Colors from FBXTree.Objects.Geometry.LayerElementColor if it exists parseVertexColors: function(e) { var t = e.MappingInformationType, r = e.ReferenceInformationType, n = e.Colors.a, a = []; return r === "IndexToDirect" && (a = e.ColorIndex.a), { dataSize: 4, buffer: n, indices: a, mappingType: t, referenceType: r }; }, // Parse mapping and material data in FBXTree.Objects.Geometry.LayerElementMaterial if it exists parseMaterialIndices: function(e) { var t = e.MappingInformationType, r = e.ReferenceInformationType; if (t === "NoMappingInformation") return { dataSize: 1, buffer: [0], indices: [0], mappingType: "AllSame", referenceType: r }; for (var n = e.Materials.a, a = [], i = 0; i < n.length; ++i) a.push(i); return { dataSize: 1, buffer: n, indices: a, mappingType: t, referenceType: r }; }, // Generate a NurbGeometry from a node in FBXTree.Objects.Geometry parseNurbsGeometry: function(e) { if (me === void 0) return console.error( "THREE.FBXLoader: The loader relies on NURBSCurve for any nurbs present in the model. Nurbs will show up as empty geometry." ), new V(); var t = parseInt(e.Order); if (isNaN(t)) return console.error("THREE.FBXLoader: Invalid Order %s given for geometry ID: %s", e.Order, e.id), new V(); for (var r = t - 1, n = e.KnotVector.a, a = [], i = e.Points.a, s = 0, o = i.length; s < o; s += 4) a.push(new Ve().fromArray(i, s)); var f, l; if (e.Form === "Closed") a.push(a[0]); else if (e.Form === "Periodic") { f = r, l = n.length - 1 - f; for (var s = 0; s < r; ++s) a.push(a[s]); } var u = new me(r, n, a, f, l), p = u.getPoints(a.length * 7), c = new Float32Array(p.length * 3); p.forEach(function(w, g) { w.toArray(c, g * 3); }); var h = new V(); return h.setAttribute("position", new je(c, 3)), h; } }; function K() { } K.prototype = { constructor: K, // take raw animation clips and turn them into three.js animation clips parse: function() { var e = [], t = this.parseClips(); if (t !== void 0) for (var r in t) { var n = t[r], a = this.addClip(n); e.push(a); } return e; }, parseClips: function() { if (v.Objects.AnimationCurve !== void 0) { var e = this.parseAnimationCurveNodes(); this.parseAnimationCurves(e); var t = this.parseAnimationLayers(e), r = this.parseAnimStacks(t); return r; } }, // parse nodes in FBXTree.Objects.AnimationCurveNode // each AnimationCurveNode holds data for an animation transform for a model (e.g. left arm rotation ) // and is referenced by an AnimationLayer parseAnimationCurveNodes: function() { var e = v.Objects.AnimationCurveNode, t = /* @__PURE__ */ new Map(); for (var r in e) { var n = e[r]; if (n.attrName.match(/S|R|T|DeformPercent/) !== null) { var a = { id: n.id, attr: n.attrName, curves: {} }; t.set(a.id, a); } } return t; }, // parse nodes in FBXTree.Objects.AnimationCurve and connect them up to // previously parsed AnimationCurveNodes. Each AnimationCurve holds data for a single animated // axis ( e.g. times and values of x rotation) parseAnimationCurves: function(e) { var t = v.Objects.AnimationCurve; for (var r in t) { var n = { id: t[r].id, times: t[r].KeyTime.a.map(de), values: t[r].KeyValueFloat.a }, a = y.get(n.id); if (a !== void 0) { var i = a.parents[0].ID, s = a.parents[0].relationship; s.match(/X/) ? e.get(i).curves.x = n : s.match(/Y/) ? e.get(i).curves.y = n : s.match(/Z/) ? e.get(i).curves.z = n : s.match(/d|DeformPercent/) && e.has(i) && (e.get(i).curves.morph = n); } } }, // parse nodes in FBXTree.Objects.AnimationLayer. Each layers holds references // to various AnimationCurveNodes and is referenced by an AnimationStack node // note: theoretically a stack can have multiple layers, however in practice there always seems to be one per stack parseAnimationLayers: function(e) { var t = v.Objects.AnimationLayer, r = /* @__PURE__ */ new Map(); for (var n in t) { var a = [], i = y.get(parseInt(n)); if (i !== void 0) { var s = i.children; s.forEach(function(o, f) { if (e.has(o.ID)) { var l = e.get(o.ID); if (l.curves.x !== void 0 || l.curves.y !== void 0 || l.curves.z !== void 0) { if (a[f] === void 0) { var u = y.get(o.ID).parents.filter(function(d) { return d.relationship !== void 0; })[0].ID; if (u !== void 0) { var p = v.Objects.Model[u.toString()]; if (p === void 0) { console.warn("THREE.FBXLoader: Encountered a unused curve.", o); return; } var c = { modelName: p.attrName ? X.sanitizeNodeName(p.attrName) : "", ID: p.id, initialPosition: [0, 0, 0], initialRotation: [0, 0, 0], initialScale: [1, 1, 1] }; T.traverse(function(d) { d.ID === p.id && (c.transform = d.matrix, d.userData.transformData && (c.eulerOrder = d.userData.transformData.eulerOrder)); }), c.transform || (c.transform = new m()), "PreRotation" in p && (c.preRotation = p.PreRotation.value), "PostRotation" in p && (c.postRotation = p.PostRotation.value), a[f] = c; } } a[f] && (a[f][l.attr] = l); } else if (l.curves.morph !== void 0) { if (a[f] === void 0) { var h = y.get(o.ID).parents.filter(function(S) { return S.relationship !== void 0; })[0].ID, w = y.get(h).parents[0].ID, g = y.get(w).parents[0].ID, u = y.get(g).parents[0].ID, p = v.Objects.Model[u], c = { modelName: p.attrName ? X.sanitizeNodeName(p.attrName) : "", morphName: v.Objects.Deformer[h].attrName }; a[f] = c; } a[f][l.attr] = l; } } }), r.set(parseInt(n), a); } } return r; }, // parse nodes in FBXTree.Objects.AnimationStack. These are the top level node in the animation // hierarchy. Each Stack node will be used to create a AnimationClip parseAnimStacks: function(e) { var t = v.Objects.AnimationStack, r = {}; for (var n in t) { var a = y.get(parseInt(n)).children; a.length > 1 && console.warn( "THREE.FBXLoader: Encountered an animation stack with multiple layers, this is currently not supported. Ignoring subsequent layers." ); var i = e.get(a[0].ID); r[n] = { name: t[n].attrName, layer: i }; } return r; }, addClip: function(e) { var t = [], r = this; return e.layer.forEach(function(n) { t = t.concat(r.generateTracks(n)); }), new ze(e.name, -1, t); }, generateTracks: function(e) { var t = [], r = new G(), n = new j(), a = new G(); if (e.transform && e.transform.decompose(r, n, a), r = r.toArray(), n = new B().setFromQuaternion(n, e.eulerOrder).toArray(), a = a.toArray(), e.T !== void 0 && Object.keys(e.T.curves).length > 0) { var i = this.generateVectorTrack(e.modelName, e.T.curves, r, "position"); i !== void 0 && t.push(i); } if (e.R !== void 0 && Object.keys(e.R.curves).length > 0) { var s = this.generateRotationTrack( e.modelName, e.R.curves, n, e.preRotation, e.postRotation, e.eulerOrder ); s !== void 0 && t.push(s); } if (e.S !== void 0 && Object.keys(e.S.curves).length > 0) { var o = this.generateVectorTrack(e.modelName, e.S.curves, a, "scale"); o !== void 0 && t.push(o); } if (e.DeformPercent !== void 0) { var f = this.generateMorphTrack(e); f !== void 0 && t.push(f); } return t; }, generateVectorTrack: function(e, t, r, n) { var a = this.getTimesForAllAxes(t), i = this.getKeyframeTrackValues(a, t, r); return new He(e + "." + n, a, i); }, generateRotationTrack: function(e, t, r, n, a, i) { t.x !== void 0 && (this.interpolateRotations(t.x), t.x.values = t.x.values.map(x.degToRad)), t.y !== void 0 && (this.interpolateRotations(t.y), t.y.values = t.y.values.map(x.degToRad)), t.z !== void 0 && (this.interpolateRotations(t.z), t.z.values = t.z.values.map(x.degToRad)); var s = this.getTimesForAllAxes(t), o = this.getKeyframeTrackValues(s, t, r); n !== void 0 && (n = n.map(x.degToRad), n.push(i), n = new B().fromArray(n), n = new j().setFromEuler(n)), a !== void 0 && (a = a.map(x.degToRad), a.push(i), a = new B().fromArray(a), a = new j().setFromEuler(a).inverse()); for (var f = new j(), l = new B(), u = [], p = 0; p < o.length; p += 3) l.set(o[p], o[p + 1], o[p + 2], i), f.setFromEuler(l), n !== void 0 && f.premultiply(n), a !== void 0 && f.multiply(a), f.toArray(u, p / 3 * 4); return new _e(e + ".quaternion", s, u); }, generateMorphTrack: function(e) { var t = e.DeformPercent.curves.morph, r = t.values.map(function(a) { return a / 100; }), n = T.getObjectByName(e.modelName).morphTargetDictionary[e.morphName]; return new Ke(e.modelName + ".morphTargetInfluences[" + n + "]", t.times, r); }, // For all animated objects, times are defined separately for each axis // Here we'll combine the times into one sorted array without duplicates getTimesForAllAxes: function(e) { var t = []; return e.x !== void 0 && (t = t.concat(e.x.times)), e.y !== void 0 && (t = t.concat(e.y.times)), e.z !== void 0 && (t = t.concat(e.z.times)), t = t.sort(function(r, n) { return r - n; }).filter(function(r, n, a) { return a.indexOf(r) == n; }), t; }, getKeyframeTrackValues: function(e, t, r) { var n = r, a = [], i = -1, s = -1, o = -1; return e.forEach(function(f) { if (t.x && (i = t.x.times.indexOf(f)), t.y && (s = t.y.times.indexOf(f)), t.z && (o = t.z.times.indexOf(f)), i !== -1) { var l = t.x.values[i]; a.push(l), n[0] = l; } else a.push(n[0]); if (s !== -1) { var u = t.y.values[s]; a.push(u), n[1] = u; } else a.push(n[1]); if (o !== -1) { var p = t.z.values[o]; a.push(p), n[2] = p; } else a.push(n[2]); }), a; }, // Rotations are defined as Euler angles which can have values of any size // These will be converted to quaternions which don't support values greater than // PI, so we'll interpolate large rotations interpolateRotations: function(e) { for (var t = 1; t < e.values.length; t++) { var r = e.values[t - 1], n = e.values[t] - r, a = Math.abs(n); if (a >= 180) { for (var i = a / 180, s = n / i, o = r + s, f = e.times[t - 1], l = e.times[t] - f, u = l / i, p = f + u, c = [], h = []; p < e.times[t]; ) c.push(p), p += u, h.push(o), o += s; e.times = ie(e.times, t, c), e.values = ie(e.values, t, h); } } } }; function W() { } W.prototype = { constructor: W, getPrevNode: function() { return this.nodeStack[this.currentIndent - 2]; }, getCurrentNode: function() { return this.nodeStack[this.currentIndent - 1]; }, getCurrentProp: function() { return this.currentProp; }, pushStack: function(e) { this.nodeStack.push(e), this.currentIndent += 1; }, popStack: function() { this.nodeStack.pop(), this.currentIndent -= 1; }, setCurrentProp: function(e, t) { this.currentProp = e, this.currentPropName = t; }, parse: function(e) { this.currentIndent = 0, this.allNodes = new k(), this.nodeStack = [], this.currentProp = [], this.currentPropName = ""; var t = this, r = e.split(/[\r\n]+/); return r.forEach(function(n, a) { var i = n.match(/^[\s\t]*;/), s = n.match(/^[\s\t]*$/); if (!(i || s)) { var o = n.match("^\\t{" + t.currentIndent + "}(\\w+):(.*){", ""), f = n.match("^\\t{" + t.currentIndent + "}(\\w+):[\\s\\t\\r\\n](.*)"), l = n.match("^\\t{" + (t.currentIndent - 1) + "}}"); o ? t.parseNodeBegin(n, o) : f ? t.parseNodeProperty(n, f, r[++a]) : l ? t.popStack() : n.match(/^[^\s\t}]/) && t.parseNodePropertyContinued(n); } }), this.allNodes; }, parseNodeBegin: function(e, t) { var r = t[1].trim().replace(/^"/, "").replace(/"$/, ""), n = t[2].split(",").map(function(o) { return o.trim().replace(/^"/, "").replace(/"$/, ""); }), a = { name: r }, i = this.parseNodeAttr(n), s = this.getCurrentNode(); this.currentIndent === 0 ? this.allNodes.add(r, a) : r in s ? (r === "PoseNode" ? s.PoseNode.push(a) : s[r].id !== void 0 && (s[r] = {}, s[r][s[r].id] = s[r]), i.id !== "" && (s[r][i.id] = a)) : typeof i.id == "number" ? (s[r] = {}, s[r][i.id] = a) : r !== "Properties70" && (r === "PoseNode" ? s[r] = [a] : s[r] = a), typeof i.id == "number" && (a.id = i.id), i.name !== "" && (a.attrName = i.name), i.type !== "" && (a.attrType = i.type), this.pushStack(a); }, parseNodeAttr: function(e) { var t = e[0]; e[0] !== "" && (t = parseInt(e[0]), isNaN(t) && (t = e[0])); var r = "", n = ""; return e.length > 1 && (r = e[1].replace(/^(\w+)::/, ""), n = e[2]), { id: t, name: r, type: n }; }, parseNodeProperty: function(e, t, r) { var n = t[1].replace(/^"/, "").replace(/"$/, "").trim(), a = t[2].replace(/^"/, "").replace(/"$/, "").trim(); n === "Content" && a === "," && (a = r.replace(/"/g, "").replace(/,$/, "").trim()); var i = this.getCurrentNode(), s = i.name; if (s === "Properties70") { this.parseNodeSpecialProperty(e, n, a); return; } if (n === "C") { var o = a.split(",").slice(1), f = parseInt(o[0]), l = parseInt(o[1]), u = a.split(",").slice(3); u = u.map(function(p) { return p.trim().replace(/^"/, ""); }), n = "connections", a = [f, l], Te(a, u), i[n] === void 0 && (i[n] = []); } n === "Node" && (i.id = a), n in i && Array.isArray(i[n]) ? i[n].push(a) : n !== "a" ? i[n] = a : i.a = a, this.setCurrentProp(i, n), n === "a" && a.slice(-1) !== "," && (i.a = q(a)); }, parseNodePropertyContinued: function(e) { var t = this.getCurrentNode(); t.a += e, e.slice(-1) !== "," && (t.a = q(t.a)); }, // parse "Property70" parseNodeSpecialProperty: function(e, t, r) { var n = r.split('",').map(function(l) { return l.trim().replace(/^\"