From a7ac6888fb779e0e2473fc1a20fc22ecee539a90 Mon Sep 17 00:00:00 2001 From: Cody Bennett <23324155+CodyJasonBennett@users.noreply.github.com> Date: Fri, 26 May 2023 11:38:59 -0500 Subject: [PATCH] fix: tree-shake loaders --- src/index.ts | 104 +- src/loaders/AssimpLoader.d.ts | 19 + src/loaders/AssimpLoader.js | 994 +++++++------- src/loaders/BasisTextureLoader.js | 756 +++++------ src/loaders/ColladaLoader.js | 2 +- src/loaders/FBXLoader.js | 4 +- src/loaders/GLTFLoader.js | 2 +- src/loaders/KTX2Loader.js | 598 ++++---- src/loaders/LDrawLoader.js | 6 +- src/loaders/NodeMaterialLoader.js | 3 + src/loaders/OBJLoader.js | 10 +- src/loaders/RGBMLoader.js | 2104 +++++++++++++++-------------- src/loaders/TiltLoader.js | 4 +- src/loaders/VRMLoader.d.ts | 19 + src/loaders/XLoader.d.ts | 19 + src/loaders/XLoader.js | 2 +- src/loaders/lwo/IFFParser.js | 51 +- src/loaders/lwo/LWO2Parser.js | 52 +- src/loaders/lwo/LWO3Parser.js | 55 +- 19 files changed, 2446 insertions(+), 2358 deletions(-) create mode 100644 src/loaders/AssimpLoader.d.ts create mode 100644 src/loaders/VRMLoader.d.ts create mode 100644 src/loaders/XLoader.d.ts diff --git a/src/index.ts b/src/index.ts index 2ca26da5..d97e6315 100644 --- a/src/index.ts +++ b/src/index.ts @@ -246,58 +246,62 @@ export * from './effects/OutlineEffect' export * from './effects/AnaglyphEffect' export * from './effects/AsciiEffect' export * from './effects/StereoEffect' -// export * from './loaders/FBXLoader' -// export * from './loaders/FontLoader' -// export * from './loaders/TGALoader' -// export * from './loaders/LUTCubeLoader' -// export * from './loaders/NRRDLoader' -// export * from './loaders/STLLoader' -// export * from './loaders/MTLLoader' -// export * from './loaders/XLoader' -// export * from './loaders/BVHLoader' -// export * from './loaders/KMZLoader' +export * from './loaders/FBXLoader' +// export * from './loaders/FontLoader' // +export * from './loaders/TGALoader' +export * from './loaders/LUTCubeLoader' +export * from './loaders/NRRDLoader' +export * from './loaders/STLLoader' +export * from './loaders/MTLLoader' +export * from './loaders/XLoader' +export * from './loaders/BVHLoader' +export * from './loaders/KMZLoader' // export * from './loaders/VRMLoader' -// export * from './loaders/VRMLLoader' -// export * from './loaders/KTX2Loader' -// export * from './loaders/LottieLoader' -// export * from './loaders/TTFLoader' -// export * from './loaders/RGBELoader' -// export * from './loaders/AssimpLoader' -// export * from './loaders/ColladaLoader' -// export * from './loaders/MDDLoader' -// export * from './loaders/EXRLoader' -// export * from './loaders/3MFLoader' -// export * from './loaders/XYZLoader' -// export * from './loaders/VTKLoader' -// export * from './loaders/LUT3dlLoader' -// export * from './loaders/DDSLoader' -// export * from './loaders/PVRLoader' -// export * from './loaders/GCodeLoader' -// export * from './loaders/BasisTextureLoader' -// export * from './loaders/TDSLoader' -// export * from './loaders/LDrawLoader' -// export * from './loaders/GLTFLoader' -// export * from './loaders/lwo/LWO3Parser' -// export * from './loaders/lwo/LWO2Parser' -// export * from './loaders/lwo/IFFParser' -// export * from './loaders/SVGLoader' -// export * from './loaders/3DMLoader' -// export * from './loaders/OBJLoader' -// export * from './loaders/AMFLoader' -// export * from './loaders/MMDLoader' -// export * from './loaders/MD2Loader' -// export * from './loaders/KTXLoader' -// export * from './loaders/TiltLoader' -// export * from './loaders/DRACOLoader' -// export * from './loaders/HDRCubeTextureLoader' -// export * from './loaders/PDBLoader' -// export * from './loaders/PRWMLoader' -// export * from './loaders/RGBMLoader' -// export * from './loaders/VOXLoader' +export * from './loaders/VRMLLoader' +// export * from './loaders/KTX2Loader' // +export * from './loaders/LottieLoader' +export * from './loaders/TTFLoader' +export * from './loaders/RGBELoader' +export * from './loaders/AssimpLoader' +export * from './loaders/ColladaLoader' +export * from './loaders/MDDLoader' +export * from './loaders/EXRLoader' +export * from './loaders/3MFLoader' +export * from './loaders/XYZLoader' +export * from './loaders/VTKLoader' +export * from './loaders/LUT3dlLoader' +export * from './loaders/DDSLoader' +export * from './loaders/PVRLoader' +export * from './loaders/GCodeLoader' +// export * from './loaders/BasisTextureLoader' // +export * from './loaders/TDSLoader' +export * from './loaders/LDrawLoader' +// export * from './loaders/GLTFLoader' // +// @ts-ignore +export * from './loaders/lwo/LWO3Parser' +// @ts-ignore +export * from './loaders/lwo/LWO2Parser' +// @ts-ignore +export * from './loaders/lwo/IFFParser' +export * from './loaders/SVGLoader' +export * from './loaders/3DMLoader' +export * from './loaders/OBJLoader' +export * from './loaders/AMFLoader' +export * from './loaders/MMDLoader' +export * from './loaders/MD2Loader' +export * from './loaders/KTXLoader' +export * from './loaders/TiltLoader' +export * from './loaders/DRACOLoader' +export * from './loaders/HDRCubeTextureLoader' +export * from './loaders/PDBLoader' +export * from './loaders/PRWMLoader' +export * from './loaders/RGBMLoader' +export * from './loaders/VOXLoader' +// @ts-ignore // export * from './loaders/NodeMaterialLoader' -// export * from './loaders/PCDLoader' -// export * from './loaders/LWOLoader' -// export * from './loaders/PLYLoader' +export * from './loaders/PCDLoader' +export * from './loaders/LWOLoader' +export * from './loaders/PLYLoader' export * from './lines/LineSegmentsGeometry' export * from './lines/LineGeometry' export * from './lines/Wireframe' diff --git a/src/loaders/AssimpLoader.d.ts b/src/loaders/AssimpLoader.d.ts new file mode 100644 index 00000000..34cdcb2a --- /dev/null +++ b/src/loaders/AssimpLoader.d.ts @@ -0,0 +1,19 @@ +import { Object3D, Loader, LoadingManager } from 'three' + +export interface Assimp { + animation: any + object: Object3D +} + +export class AssimpLoader extends Loader { + constructor(manager?: LoadingManager) + + load( + url: string, + onLoad: (result: Assimp) => void, + onProgress?: (event: ProgressEvent) => void, + onError?: (event: ErrorEvent) => void, + ): void + loadAsync(url: string, onProgress?: (event: ProgressEvent) => void): Promise + parse(buffer: ArrayBuffer, path: string): Assimp +} diff --git a/src/loaders/AssimpLoader.js b/src/loaders/AssimpLoader.js index 8052914c..2b82ea9e 100644 --- a/src/loaders/AssimpLoader.js +++ b/src/loaders/AssimpLoader.js @@ -18,14 +18,8 @@ import { Vector3, } from 'three' -var AssimpLoader = function (manager) { - Loader.call(this, manager) -} - -AssimpLoader.prototype = Object.assign(Object.create(Loader.prototype), { - constructor: AssimpLoader, - - load: function (url, onLoad, onProgress, onError) { +class AssimpLoader extends Loader { + load(url, onLoad, onProgress, onError) { var scope = this var path = scope.path === '' ? LoaderUtils.extractUrlBase(url) : scope.path @@ -54,50 +48,52 @@ AssimpLoader.prototype = Object.assign(Object.create(Loader.prototype), { onProgress, onError, ) - }, + } - parse: function (buffer, path) { + parse(buffer, path) { var textureLoader = new TextureLoader(this.manager) textureLoader.setPath(this.resourcePath || path).setCrossOrigin(this.crossOrigin) var Virtulous = {} - Virtulous.KeyFrame = function (time, matrix) { - this.time = time - this.matrix = matrix.clone() - this.position = new Vector3() - this.quaternion = new Quaternion() - this.scale = new Vector3(1, 1, 1) - this.matrix.decompose(this.position, this.quaternion, this.scale) - this.clone = function () { - var n = new Virtulous.KeyFrame(this.time, this.matrix) - return n - } + Virtulous.KeyFrame = class { + constructor(time, matrix) { + this.time = time + this.matrix = matrix.clone() + this.position = new Vector3() + this.quaternion = new Quaternion() + this.scale = new Vector3(1, 1, 1) + this.matrix.decompose(this.position, this.quaternion, this.scale) + this.clone = function () { + var n = new Virtulous.KeyFrame(this.time, this.matrix) + return n + } - this.lerp = function (nextKey, time) { - time -= this.time - var dist = nextKey.time - this.time - var l = time / dist - var l2 = 1 - l - var keypos = this.position - var keyrot = this.quaternion - // var keyscl = key.parentspaceScl || key.scl; - var key2pos = nextKey.position - var key2rot = nextKey.quaternion - // var key2scl = key2.parentspaceScl || key2.scl; - Virtulous.KeyFrame.tempAniPos.x = keypos.x * l2 + key2pos.x * l - Virtulous.KeyFrame.tempAniPos.y = keypos.y * l2 + key2pos.y * l - Virtulous.KeyFrame.tempAniPos.z = keypos.z * l2 + key2pos.z * l - // tempAniScale.x = keyscl[0] * l2 + key2scl[0] * l; - // tempAniScale.y = keyscl[1] * l2 + key2scl[1] * l; - // tempAniScale.z = keyscl[2] * l2 + key2scl[2] * l; - Virtulous.KeyFrame.tempAniQuat.set(keyrot.x, keyrot.y, keyrot.z, keyrot.w) - Virtulous.KeyFrame.tempAniQuat.slerp(key2rot, l) - return Virtulous.KeyFrame.tempAniMatrix.compose( - Virtulous.KeyFrame.tempAniPos, - Virtulous.KeyFrame.tempAniQuat, - Virtulous.KeyFrame.tempAniScale, - ) + this.lerp = function (nextKey, time) { + time -= this.time + var dist = nextKey.time - this.time + var l = time / dist + var l2 = 1 - l + var keypos = this.position + var keyrot = this.quaternion + // var keyscl = key.parentspaceScl || key.scl; + var key2pos = nextKey.position + var key2rot = nextKey.quaternion + // var key2scl = key2.parentspaceScl || key2.scl; + Virtulous.KeyFrame.tempAniPos.x = keypos.x * l2 + key2pos.x * l + Virtulous.KeyFrame.tempAniPos.y = keypos.y * l2 + key2pos.y * l + Virtulous.KeyFrame.tempAniPos.z = keypos.z * l2 + key2pos.z * l + // tempAniScale.x = keyscl[0] * l2 + key2scl[0] * l; + // tempAniScale.y = keyscl[1] * l2 + key2scl[1] * l; + // tempAniScale.z = keyscl[2] * l2 + key2scl[2] * l; + Virtulous.KeyFrame.tempAniQuat.set(keyrot.x, keyrot.y, keyrot.z, keyrot.w) + Virtulous.KeyFrame.tempAniQuat.slerp(key2rot, l) + return Virtulous.KeyFrame.tempAniMatrix.compose( + Virtulous.KeyFrame.tempAniPos, + Virtulous.KeyFrame.tempAniQuat, + Virtulous.KeyFrame.tempAniScale, + ) + } } } @@ -514,286 +510,310 @@ AssimpLoader.prototype = Object.assign(Object.create(Loader.prototype), { return undefined } - function aiMesh() { - this.mPrimitiveTypes = 0 - this.mNumVertices = 0 - this.mNumFaces = 0 - this.mNumBones = 0 - this.mMaterialIndex = 0 - this.mVertices = [] - this.mNormals = [] - this.mTangents = [] - this.mBitangents = [] - this.mColors = [[]] - this.mTextureCoords = [[]] - this.mFaces = [] - this.mBones = [] - this.hookupSkeletons = function (scene) { - if (this.mBones.length == 0) return - - var allBones = [] - var offsetMatrix = [] - var skeletonRoot = scene.findNode(this.mBones[0].mName) - - while (skeletonRoot.mParent && skeletonRoot.mParent.isBone) { - skeletonRoot = skeletonRoot.mParent - } - - var threeSkeletonRoot = skeletonRoot.toTHREE(scene) - var threeSkeletonRootBone = cloneTreeToBones(threeSkeletonRoot, scene) - this.threeNode.add(threeSkeletonRootBone) + class aiMesh { + constructor() { + this.mPrimitiveTypes = 0 + this.mNumVertices = 0 + this.mNumFaces = 0 + this.mNumBones = 0 + this.mMaterialIndex = 0 + this.mVertices = [] + this.mNormals = [] + this.mTangents = [] + this.mBitangents = [] + this.mColors = [[]] + this.mTextureCoords = [[]] + this.mFaces = [] + this.mBones = [] + this.hookupSkeletons = function (scene) { + if (this.mBones.length == 0) return + + var allBones = [] + var offsetMatrix = [] + var skeletonRoot = scene.findNode(this.mBones[0].mName) + + while (skeletonRoot.mParent && skeletonRoot.mParent.isBone) { + skeletonRoot = skeletonRoot.mParent + } - for (let i = 0; i < this.mBones.length; i++) { - var bone = findMatchingBone(threeSkeletonRootBone, this.mBones[i].mName) + var threeSkeletonRoot = skeletonRoot.toTHREE(scene) + var threeSkeletonRootBone = cloneTreeToBones(threeSkeletonRoot, scene) + this.threeNode.add(threeSkeletonRootBone) - if (bone) { - var tbone = bone - allBones.push(tbone) - //tbone.matrixAutoUpdate = false; - offsetMatrix.push(this.mBones[i].mOffsetMatrix.toTHREE()) - } else { - var skeletonRoot = scene.findNode(this.mBones[i].mName) - if (!skeletonRoot) return - var threeSkeletonRoot = skeletonRoot.toTHREE(scene) - var threeSkeletonRootBone = cloneTreeToBones(threeSkeletonRoot, scene) - this.threeNode.add(threeSkeletonRootBone) + for (let i = 0; i < this.mBones.length; i++) { var bone = findMatchingBone(threeSkeletonRootBone, this.mBones[i].mName) - var tbone = bone - allBones.push(tbone) - //tbone.matrixAutoUpdate = false; - offsetMatrix.push(this.mBones[i].mOffsetMatrix.toTHREE()) - } - } - var skeleton = new Skeleton(allBones, offsetMatrix) + if (bone) { + var tbone = bone + allBones.push(tbone) + //tbone.matrixAutoUpdate = false; + offsetMatrix.push(this.mBones[i].mOffsetMatrix.toTHREE()) + } else { + var skeletonRoot = scene.findNode(this.mBones[i].mName) + if (!skeletonRoot) return + var threeSkeletonRoot = skeletonRoot.toTHREE(scene) + var threeSkeletonRootBone = cloneTreeToBones(threeSkeletonRoot, scene) + this.threeNode.add(threeSkeletonRootBone) + var bone = findMatchingBone(threeSkeletonRootBone, this.mBones[i].mName) + var tbone = bone + allBones.push(tbone) + //tbone.matrixAutoUpdate = false; + offsetMatrix.push(this.mBones[i].mOffsetMatrix.toTHREE()) + } + } - this.threeNode.bind(skeleton, new Matrix4()) - this.threeNode.material.skinning = true - } + var skeleton = new Skeleton(allBones, offsetMatrix) - this.toTHREE = function (scene) { - if (this.threeNode) return this.threeNode - var geometry = new BufferGeometry() - var mat - if (scene.mMaterials[this.mMaterialIndex]) mat = scene.mMaterials[this.mMaterialIndex].toTHREE(scene) - else mat = new MeshLambertMaterial() - geometry.setIndex(new BufferAttribute(new Uint32Array(this.mIndexArray), 1)) - geometry.setAttribute('position', new BufferAttribute(this.mVertexBuffer, 3)) - if (this.mNormalBuffer && this.mNormalBuffer.length > 0) { - geometry.setAttribute('normal', new BufferAttribute(this.mNormalBuffer, 3)) - } - if (this.mColorBuffer && this.mColorBuffer.length > 0) { - geometry.setAttribute('color', new BufferAttribute(this.mColorBuffer, 4)) - } - if (this.mTexCoordsBuffers[0] && this.mTexCoordsBuffers[0].length > 0) { - geometry.setAttribute('uv', new BufferAttribute(new Float32Array(this.mTexCoordsBuffers[0]), 2)) - } - if (this.mTexCoordsBuffers[1] && this.mTexCoordsBuffers[1].length > 0) { - geometry.setAttribute('uv1', new BufferAttribute(new Float32Array(this.mTexCoordsBuffers[1]), 2)) + this.threeNode.bind(skeleton, new Matrix4()) + this.threeNode.material.skinning = true } - if (this.mTangentBuffer && this.mTangentBuffer.length > 0) { - geometry.setAttribute('tangents', new BufferAttribute(this.mTangentBuffer, 3)) - } - if (this.mBitangentBuffer && this.mBitangentBuffer.length > 0) { - geometry.setAttribute('bitangents', new BufferAttribute(this.mBitangentBuffer, 3)) - } - if (this.mBones.length > 0) { - var weights = [] - var bones = [] - for (let i = 0; i < this.mBones.length; i++) { - for (let j = 0; j < this.mBones[i].mWeights.length; j++) { - var weight = this.mBones[i].mWeights[j] - if (weight) { - if (!weights[weight.mVertexId]) weights[weight.mVertexId] = [] - if (!bones[weight.mVertexId]) bones[weight.mVertexId] = [] - weights[weight.mVertexId].push(weight.mWeight) - bones[weight.mVertexId].push(parseInt(i)) + this.toTHREE = function (scene) { + if (this.threeNode) return this.threeNode + var geometry = new BufferGeometry() + var mat + if (scene.mMaterials[this.mMaterialIndex]) mat = scene.mMaterials[this.mMaterialIndex].toTHREE(scene) + else mat = new MeshLambertMaterial() + geometry.setIndex(new BufferAttribute(new Uint32Array(this.mIndexArray), 1)) + geometry.setAttribute('position', new BufferAttribute(this.mVertexBuffer, 3)) + if (this.mNormalBuffer && this.mNormalBuffer.length > 0) { + geometry.setAttribute('normal', new BufferAttribute(this.mNormalBuffer, 3)) + } + if (this.mColorBuffer && this.mColorBuffer.length > 0) { + geometry.setAttribute('color', new BufferAttribute(this.mColorBuffer, 4)) + } + if (this.mTexCoordsBuffers[0] && this.mTexCoordsBuffers[0].length > 0) { + geometry.setAttribute('uv', new BufferAttribute(new Float32Array(this.mTexCoordsBuffers[0]), 2)) + } + if (this.mTexCoordsBuffers[1] && this.mTexCoordsBuffers[1].length > 0) { + geometry.setAttribute('uv1', new BufferAttribute(new Float32Array(this.mTexCoordsBuffers[1]), 2)) + } + if (this.mTangentBuffer && this.mTangentBuffer.length > 0) { + geometry.setAttribute('tangents', new BufferAttribute(this.mTangentBuffer, 3)) + } + if (this.mBitangentBuffer && this.mBitangentBuffer.length > 0) { + geometry.setAttribute('bitangents', new BufferAttribute(this.mBitangentBuffer, 3)) + } + if (this.mBones.length > 0) { + var weights = [] + var bones = [] + + for (let i = 0; i < this.mBones.length; i++) { + for (let j = 0; j < this.mBones[i].mWeights.length; j++) { + var weight = this.mBones[i].mWeights[j] + if (weight) { + if (!weights[weight.mVertexId]) weights[weight.mVertexId] = [] + if (!bones[weight.mVertexId]) bones[weight.mVertexId] = [] + weights[weight.mVertexId].push(weight.mWeight) + bones[weight.mVertexId].push(parseInt(i)) + } } } - } - for (let i in bones) { - sortWeights(bones[i], weights[i]) - } + for (let i in bones) { + sortWeights(bones[i], weights[i]) + } - var _weights = [] - var _bones = [] - - for (let i = 0; i < weights.length; i++) { - for (let j = 0; j < 4; j++) { - if (weights[i] && bones[i]) { - _weights.push(weights[i][j]) - _bones.push(bones[i][j]) - } else { - _weights.push(0) - _bones.push(0) + var _weights = [] + var _bones = [] + + for (let i = 0; i < weights.length; i++) { + for (let j = 0; j < 4; j++) { + if (weights[i] && bones[i]) { + _weights.push(weights[i][j]) + _bones.push(bones[i][j]) + } else { + _weights.push(0) + _bones.push(0) + } } } + + geometry.setAttribute('skinWeight', new BufferAttribute(new Float32Array(_weights), BONESPERVERT)) + geometry.setAttribute('skinIndex', new BufferAttribute(new Float32Array(_bones), BONESPERVERT)) } - geometry.setAttribute('skinWeight', new BufferAttribute(new Float32Array(_weights), BONESPERVERT)) - geometry.setAttribute('skinIndex', new BufferAttribute(new Float32Array(_bones), BONESPERVERT)) - } + var mesh - var mesh + if (this.mBones.length == 0) mesh = new Mesh(geometry, mat) - if (this.mBones.length == 0) mesh = new Mesh(geometry, mat) + if (this.mBones.length > 0) { + mesh = new SkinnedMesh(geometry, mat) + mesh.normalizeSkinWeights() + } - if (this.mBones.length > 0) { - mesh = new SkinnedMesh(geometry, mat) - mesh.normalizeSkinWeights() + this.threeNode = mesh + //mesh.matrixAutoUpdate = false; + return mesh } - - this.threeNode = mesh - //mesh.matrixAutoUpdate = false; - return mesh } } - function aiFace() { - this.mNumIndices = 0 - this.mIndices = [] + class aiFace { + constructor() { + this.mNumIndices = 0 + this.mIndices = [] + } } - function aiVector3D() { - this.x = 0 - this.y = 0 - this.z = 0 + class aiVector3D { + constructor() { + this.x = 0 + this.y = 0 + this.z = 0 - this.toTHREE = function () { - return new Vector3(this.x, this.y, this.z) + this.toTHREE = function () { + return new Vector3(this.x, this.y, this.z) + } } } - function aiColor3D() { - this.r = 0 - this.g = 0 - this.b = 0 - this.a = 0 - this.toTHREE = function () { - return new Color(this.r, this.g, this.b) + class aiColor3D { + constructor() { + this.r = 0 + this.g = 0 + this.b = 0 + this.a = 0 + this.toTHREE = function () { + return new Color(this.r, this.g, this.b) + } } } - function aiQuaternion() { - this.x = 0 - this.y = 0 - this.z = 0 - this.w = 0 - this.toTHREE = function () { - return new Quaternion(this.x, this.y, this.z, this.w) + class aiQuaternion { + constructor() { + this.x = 0 + this.y = 0 + this.z = 0 + this.w = 0 + this.toTHREE = function () { + return new Quaternion(this.x, this.y, this.z, this.w) + } } } - function aiVertexWeight() { - this.mVertexId = 0 - this.mWeight = 0 + class aiVertexWeight { + constructor() { + this.mVertexId = 0 + this.mWeight = 0 + } } - function aiString() { - this.data = [] - this.toString = function () { - var str = '' - this.data.forEach(function (i) { - str += String.fromCharCode(i) - }) - return str.replace(/[^\x20-\x7E]+/g, '') + class aiString { + constructor() { + this.data = [] + this.toString = function () { + var str = '' + this.data.forEach(function (i) { + str += String.fromCharCode(i) + }) + return str.replace(/[^\x20-\x7E]+/g, '') + } } } - function aiVectorKey() { - this.mTime = 0 - this.mValue = null + class aiVectorKey { + constructor() { + this.mTime = 0 + this.mValue = null + } } - function aiQuatKey() { - this.mTime = 0 - this.mValue = null + class aiQuatKey { + constructor() { + this.mTime = 0 + this.mValue = null + } } - function aiNode() { - this.mName = '' - this.mTransformation = [] - this.mNumChildren = 0 - this.mNumMeshes = 0 - this.mMeshes = [] - this.mChildren = [] - this.toTHREE = function (scene) { - if (this.threeNode) return this.threeNode - var o = new Object3D() - o.name = this.mName - o.matrix = this.mTransformation.toTHREE() + class aiNode { + constructor() { + this.mName = '' + this.mTransformation = [] + this.mNumChildren = 0 + this.mNumMeshes = 0 + this.mMeshes = [] + this.mChildren = [] + this.toTHREE = function (scene) { + if (this.threeNode) return this.threeNode + var o = new Object3D() + o.name = this.mName + o.matrix = this.mTransformation.toTHREE() - for (let i = 0; i < this.mChildren.length; i++) { - o.add(this.mChildren[i].toTHREE(scene)) - } + for (let i = 0; i < this.mChildren.length; i++) { + o.add(this.mChildren[i].toTHREE(scene)) + } - for (let i = 0; i < this.mMeshes.length; i++) { - o.add(scene.mMeshes[this.mMeshes[i]].toTHREE(scene)) - } + for (let i = 0; i < this.mMeshes.length; i++) { + o.add(scene.mMeshes[this.mMeshes[i]].toTHREE(scene)) + } - this.threeNode = o - //o.matrixAutoUpdate = false; - o.matrix.decompose(o.position, o.quaternion, o.scale) - return o + this.threeNode = o + //o.matrixAutoUpdate = false; + o.matrix.decompose(o.position, o.quaternion, o.scale) + return o + } } } - function aiBone() { - this.mName = '' - this.mNumWeights = 0 - this.mOffsetMatrix = 0 + class aiBone { + constructor() { + this.mName = '' + this.mNumWeights = 0 + this.mOffsetMatrix = 0 + } } - function aiMaterialProperty() { - this.mKey = '' - this.mSemantic = 0 - this.mIndex = 0 - this.mData = [] - this.mDataLength = 0 - this.mType = 0 - this.dataAsColor = function () { - var array = new Uint8Array(this.mData).buffer - var reader = new DataView(array) - var r = reader.getFloat32(0, true) - var g = reader.getFloat32(4, true) - var b = reader.getFloat32(8, true) - //var a = reader.getFloat32(12, true); - return new Color(r, g, b) - } + class aiMaterialProperty { + constructor() { + this.mKey = '' + this.mSemantic = 0 + this.mIndex = 0 + this.mData = [] + this.mDataLength = 0 + this.mType = 0 + this.dataAsColor = function () { + var array = new Uint8Array(this.mData).buffer + var reader = new DataView(array) + var r = reader.getFloat32(0, true) + var g = reader.getFloat32(4, true) + var b = reader.getFloat32(8, true) + //var a = reader.getFloat32(12, true); + return new Color(r, g, b) + } - this.dataAsFloat = function () { - var array = new Uint8Array(this.mData).buffer - var reader = new DataView(array) - var r = reader.getFloat32(0, true) - return r - } + this.dataAsFloat = function () { + var array = new Uint8Array(this.mData).buffer + var reader = new DataView(array) + var r = reader.getFloat32(0, true) + return r + } - this.dataAsBool = function () { - var array = new Uint8Array(this.mData).buffer - var reader = new DataView(array) - var r = reader.getFloat32(0, true) - return !!r - } + this.dataAsBool = function () { + var array = new Uint8Array(this.mData).buffer + var reader = new DataView(array) + var r = reader.getFloat32(0, true) + return !!r + } - this.dataAsString = function () { - var s = new aiString() - s.data = this.mData - return s.toString() - } + this.dataAsString = function () { + var s = new aiString() + s.data = this.mData + return s.toString() + } - this.dataAsMap = function () { - var s = new aiString() - s.data = this.mData - var path = s.toString() - path = path.replace(/\\/g, '/') + this.dataAsMap = function () { + var s = new aiString() + s.data = this.mData + var path = s.toString() + path = path.replace(/\\/g, '/') - if (path.indexOf('/') != -1) { - path = path.substr(path.lastIndexOf('/') + 1) - } + if (path.indexOf('/') != -1) { + path = path.substr(path.lastIndexOf('/') + 1) + } - return textureLoader.load(path) + return textureLoader.load(path) + } } } @@ -831,42 +851,44 @@ AssimpLoader.prototype = Object.assign(Object.create(Loader.prototype), { '$tex.file': 'map', } - function aiMaterial() { - this.mNumAllocated = 0 - this.mNumProperties = 0 - this.mProperties = [] - this.toTHREE = function () { - var mat = new MeshPhongMaterial() + class aiMaterial { + constructor() { + this.mNumAllocated = 0 + this.mNumProperties = 0 + this.mProperties = [] + this.toTHREE = function () { + var mat = new MeshPhongMaterial() - for (let i = 0; i < this.mProperties.length; i++) { - if (nameTypeMapping[this.mProperties[i].mKey] == 'float') { - mat[namePropMapping[this.mProperties[i].mKey]] = this.mProperties[i].dataAsFloat() - } - if (nameTypeMapping[this.mProperties[i].mKey] == 'color') { - mat[namePropMapping[this.mProperties[i].mKey]] = this.mProperties[i].dataAsColor() - } - if (nameTypeMapping[this.mProperties[i].mKey] == 'bool') { - mat[namePropMapping[this.mProperties[i].mKey]] = this.mProperties[i].dataAsBool() - } - if (nameTypeMapping[this.mProperties[i].mKey] == 'string') { - mat[namePropMapping[this.mProperties[i].mKey]] = this.mProperties[i].dataAsString() - } - if (nameTypeMapping[this.mProperties[i].mKey] == 'map') { - var prop = this.mProperties[i] - if (prop.mSemantic == aiTextureType_DIFFUSE) mat.map = this.mProperties[i].dataAsMap() - if (prop.mSemantic == aiTextureType_NORMALS) mat.normalMap = this.mProperties[i].dataAsMap() - if (prop.mSemantic == aiTextureType_LIGHTMAP) mat.lightMap = this.mProperties[i].dataAsMap() - if (prop.mSemantic == aiTextureType_OPACITY) mat.alphaMap = this.mProperties[i].dataAsMap() + for (let i = 0; i < this.mProperties.length; i++) { + if (nameTypeMapping[this.mProperties[i].mKey] == 'float') { + mat[namePropMapping[this.mProperties[i].mKey]] = this.mProperties[i].dataAsFloat() + } + if (nameTypeMapping[this.mProperties[i].mKey] == 'color') { + mat[namePropMapping[this.mProperties[i].mKey]] = this.mProperties[i].dataAsColor() + } + if (nameTypeMapping[this.mProperties[i].mKey] == 'bool') { + mat[namePropMapping[this.mProperties[i].mKey]] = this.mProperties[i].dataAsBool() + } + if (nameTypeMapping[this.mProperties[i].mKey] == 'string') { + mat[namePropMapping[this.mProperties[i].mKey]] = this.mProperties[i].dataAsString() + } + if (nameTypeMapping[this.mProperties[i].mKey] == 'map') { + var prop = this.mProperties[i] + if (prop.mSemantic == aiTextureType_DIFFUSE) mat.map = this.mProperties[i].dataAsMap() + if (prop.mSemantic == aiTextureType_NORMALS) mat.normalMap = this.mProperties[i].dataAsMap() + if (prop.mSemantic == aiTextureType_LIGHTMAP) mat.lightMap = this.mProperties[i].dataAsMap() + if (prop.mSemantic == aiTextureType_OPACITY) mat.alphaMap = this.mProperties[i].dataAsMap() + } } - } - mat.ambient.r = 0.53 - mat.ambient.g = 0.53 - mat.ambient.b = 0.53 - mat.color.r = 1 - mat.color.g = 1 - mat.color.b = 1 - return mat + mat.ambient.r = 0.53 + mat.ambient.g = 0.53 + mat.ambient.b = 0.53 + mat.color.r = 1 + mat.color.g = 1 + mat.color.b = 1 + return mat + } } } @@ -920,220 +942,234 @@ AssimpLoader.prototype = Object.assign(Object.create(Loader.prototype), { } } - function aiNodeAnim() { - this.mNodeName = '' - this.mNumPositionKeys = 0 - this.mNumRotationKeys = 0 - this.mNumScalingKeys = 0 - this.mPositionKeys = [] - this.mRotationKeys = [] - this.mScalingKeys = [] - this.mPreState = '' - this.mPostState = '' - this.init = function (tps) { - if (!tps) tps = 1 - - function t(t) { - t.mTime /= tps - } + class aiNodeAnim { + constructor() { + this.mNodeName = '' + this.mNumPositionKeys = 0 + this.mNumRotationKeys = 0 + this.mNumScalingKeys = 0 + this.mPositionKeys = [] + this.mRotationKeys = [] + this.mScalingKeys = [] + this.mPreState = '' + this.mPostState = '' + this.init = function (tps) { + if (!tps) tps = 1 - this.mPositionKeys.forEach(t) - this.mRotationKeys.forEach(t) - this.mScalingKeys.forEach(t) - } + function t(t) { + t.mTime /= tps + } - this.sortKeys = function () { - function comp(a, b) { - return a.mTime - b.mTime + this.mPositionKeys.forEach(t) + this.mRotationKeys.forEach(t) + this.mScalingKeys.forEach(t) } - this.mPositionKeys.sort(comp) - this.mRotationKeys.sort(comp) - this.mScalingKeys.sort(comp) - } + this.sortKeys = function () { + function comp(a, b) { + return a.mTime - b.mTime + } - this.getLength = function () { - return Math.max( - Math.max.apply( - null, - this.mPositionKeys.map(function (a) { - return a.mTime - }), - ), - Math.max.apply( - null, - this.mRotationKeys.map(function (a) { - return a.mTime - }), - ), - Math.max.apply( - null, - this.mScalingKeys.map(function (a) { - return a.mTime - }), - ), - ) - } + this.mPositionKeys.sort(comp) + this.mRotationKeys.sort(comp) + this.mScalingKeys.sort(comp) + } - this.toTHREE = function (o) { - this.sortKeys() - var length = this.getLength() - var track = new Virtulous.KeyFrameTrack() - - for (let i = 0; i < length; i += 0.05) { - var matrix = new Matrix4() - var time = i - var pos = sampleTrack(this.mPositionKeys, time, length, veclerp) - var scale = sampleTrack(this.mScalingKeys, time, length, veclerp) - var rotation = sampleTrack(this.mRotationKeys, time, length, quatlerp) - matrix.compose(pos, rotation, scale) - - var key = new Virtulous.KeyFrame(time, matrix) - track.addKey(key) + this.getLength = function () { + return Math.max( + Math.max.apply( + null, + this.mPositionKeys.map(function (a) { + return a.mTime + }), + ), + Math.max.apply( + null, + this.mRotationKeys.map(function (a) { + return a.mTime + }), + ), + Math.max.apply( + null, + this.mScalingKeys.map(function (a) { + return a.mTime + }), + ), + ) } - track.target = o.findNode(this.mNodeName).toTHREE() + this.toTHREE = function (o) { + this.sortKeys() + var length = this.getLength() + var track = new Virtulous.KeyFrameTrack() + + for (let i = 0; i < length; i += 0.05) { + var matrix = new Matrix4() + var time = i + var pos = sampleTrack(this.mPositionKeys, time, length, veclerp) + var scale = sampleTrack(this.mScalingKeys, time, length, veclerp) + var rotation = sampleTrack(this.mRotationKeys, time, length, quatlerp) + matrix.compose(pos, rotation, scale) + + var key = new Virtulous.KeyFrame(time, matrix) + track.addKey(key) + } + + track.target = o.findNode(this.mNodeName).toTHREE() - var tracks = [track] + var tracks = [track] - if (o.nodeToBoneMap[this.mNodeName]) { - for (let i = 0; i < o.nodeToBoneMap[this.mNodeName].length; i++) { - var t2 = track.clone() - t2.target = o.nodeToBoneMap[this.mNodeName][i] - tracks.push(t2) + if (o.nodeToBoneMap[this.mNodeName]) { + for (let i = 0; i < o.nodeToBoneMap[this.mNodeName].length; i++) { + var t2 = track.clone() + t2.target = o.nodeToBoneMap[this.mNodeName][i] + tracks.push(t2) + } } - } - return tracks + return tracks + } } } - function aiAnimation() { - this.mName = '' - this.mDuration = 0 - this.mTicksPerSecond = 0 - this.mNumChannels = 0 - this.mChannels = [] - this.toTHREE = function (root) { - var animationHandle = new Virtulous.Animation() + class aiAnimation { + constructor() { + this.mName = '' + this.mDuration = 0 + this.mTicksPerSecond = 0 + this.mNumChannels = 0 + this.mChannels = [] + this.toTHREE = function (root) { + var animationHandle = new Virtulous.Animation() - for (let i in this.mChannels) { - this.mChannels[i].init(this.mTicksPerSecond) + for (let i in this.mChannels) { + this.mChannels[i].init(this.mTicksPerSecond) - var tracks = this.mChannels[i].toTHREE(root) + var tracks = this.mChannels[i].toTHREE(root) - for (let j in tracks) { - tracks[j].init() - animationHandle.addTrack(tracks[j]) + for (let j in tracks) { + tracks[j].init() + animationHandle.addTrack(tracks[j]) + } } - } - animationHandle.length = Math.max.apply( - null, - animationHandle.tracks.map(function (e) { - return e.length - }), - ) - return animationHandle - } - } - - function aiTexture() { - this.mWidth = 0 - this.mHeight = 0 - this.texAchFormatHint = [] - this.pcData = [] - } - - function aiLight() { - this.mName = '' - this.mType = 0 - this.mAttenuationConstant = 0 - this.mAttenuationLinear = 0 - this.mAttenuationQuadratic = 0 - this.mAngleInnerCone = 0 - this.mAngleOuterCone = 0 - this.mColorDiffuse = null - this.mColorSpecular = null - this.mColorAmbient = null - } - - function aiCamera() { - this.mName = '' - this.mPosition = null - this.mLookAt = null - this.mUp = null - this.mHorizontalFOV = 0 - this.mClipPlaneNear = 0 - this.mClipPlaneFar = 0 - this.mAspect = 0 - } - - function aiScene() { - this.versionMajor = 0 - this.versionMinor = 0 - this.versionRevision = 0 - this.compileFlags = 0 - this.mFlags = 0 - this.mNumMeshes = 0 - this.mNumMaterials = 0 - this.mNumAnimations = 0 - this.mNumTextures = 0 - this.mNumLights = 0 - this.mNumCameras = 0 - this.mRootNode = null - this.mMeshes = [] - this.mMaterials = [] - this.mAnimations = [] - this.mLights = [] - this.mCameras = [] - this.nodeToBoneMap = {} - this.findNode = function (name, root) { - if (!root) { - root = this.mRootNode + animationHandle.length = Math.max.apply( + null, + animationHandle.tracks.map(function (e) { + return e.length + }), + ) + return animationHandle } + } + } - if (root.mName == name) { - return root - } + class aiTexture { + constructor() { + this.mWidth = 0 + this.mHeight = 0 + this.texAchFormatHint = [] + this.pcData = [] + } + } + + class aiLight { + constructor() { + this.mName = '' + this.mType = 0 + this.mAttenuationConstant = 0 + this.mAttenuationLinear = 0 + this.mAttenuationQuadratic = 0 + this.mAngleInnerCone = 0 + this.mAngleOuterCone = 0 + this.mColorDiffuse = null + this.mColorSpecular = null + this.mColorAmbient = null + } + } + + class aiCamera { + constructor() { + this.mName = '' + this.mPosition = null + this.mLookAt = null + this.mUp = null + this.mHorizontalFOV = 0 + this.mClipPlaneNear = 0 + this.mClipPlaneFar = 0 + this.mAspect = 0 + } + } + + class aiScene { + constructor() { + this.versionMajor = 0 + this.versionMinor = 0 + this.versionRevision = 0 + this.compileFlags = 0 + this.mFlags = 0 + this.mNumMeshes = 0 + this.mNumMaterials = 0 + this.mNumAnimations = 0 + this.mNumTextures = 0 + this.mNumLights = 0 + this.mNumCameras = 0 + this.mRootNode = null + this.mMeshes = [] + this.mMaterials = [] + this.mAnimations = [] + this.mLights = [] + this.mCameras = [] + this.nodeToBoneMap = {} + this.findNode = function (name, root) { + if (!root) { + root = this.mRootNode + } + + if (root.mName == name) { + return root + } - for (let i = 0; i < root.mChildren.length; i++) { - var ret = this.findNode(name, root.mChildren[i]) - if (ret) return ret + for (let i = 0; i < root.mChildren.length; i++) { + var ret = this.findNode(name, root.mChildren[i]) + if (ret) return ret + } + + return null } - return null - } + this.toTHREE = function () { + this.nodeCount = 0 - this.toTHREE = function () { - this.nodeCount = 0 + markBones(this) - markBones(this) + var o = this.mRootNode.toTHREE(this) - var o = this.mRootNode.toTHREE(this) + for (let i in this.mMeshes) this.mMeshes[i].hookupSkeletons(this) - for (let i in this.mMeshes) this.mMeshes[i].hookupSkeletons(this) + if (this.mAnimations.length > 0) { + var a = this.mAnimations[0].toTHREE(this) + } - if (this.mAnimations.length > 0) { - var a = this.mAnimations[0].toTHREE(this) + return { object: o, animation: a } } - - return { object: o, animation: a } } } - function aiMatrix4() { - this.elements = [[], [], [], []] - this.toTHREE = function () { - var m = new Matrix4() + class aiMatrix4 { + constructor() { + this.elements = [[], [], [], []] + this.toTHREE = function () { + var m = new Matrix4() - for (let i = 0; i < 4; ++i) { - for (let i2 = 0; i2 < 4; ++i2) { - m.elements[i * 4 + i2] = this.elements[i2][i] + for (let i = 0; i < 4; ++i) { + for (let i2 = 0; i2 < 4; ++i2) { + m.elements[i * 4 + i2] = this.elements[i2][i] + } } - } - return m + return m + } } } @@ -1787,7 +1823,7 @@ AssimpLoader.prototype = Object.assign(Object.create(Loader.prototype), { } return InternReadFile(buffer) - }, -}) + } +} export { AssimpLoader } diff --git a/src/loaders/BasisTextureLoader.js b/src/loaders/BasisTextureLoader.js index c9b1070c..f568464c 100644 --- a/src/loaders/BasisTextureLoader.js +++ b/src/loaders/BasisTextureLoader.js @@ -33,6 +33,384 @@ import { const _taskCache = new WeakMap() class BasisTextureLoader extends Loader { + /* CONSTANTS */ + + static BasisFormat = { + ETC1S: 0, + UASTC_4x4: 1, + } + + static TranscoderFormat = { + ETC1: 0, + ETC2: 1, + BC1: 2, + BC3: 3, + BC4: 4, + BC5: 5, + BC7_M6_OPAQUE_ONLY: 6, + BC7_M5: 7, + PVRTC1_4_RGB: 8, + PVRTC1_4_RGBA: 9, + ASTC_4x4: 10, + ATC_RGB: 11, + ATC_RGBA_INTERPOLATED_ALPHA: 12, + RGBA32: 13, + RGB565: 14, + BGR565: 15, + RGBA4444: 16, + } + + static EngineFormat = { + RGBAFormat: RGBAFormat, + RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format, + RGBA_BPTC_Format: RGBA_BPTC_Format, + RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format, + RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format, + RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format, + RGB_ETC1_Format: RGB_ETC1_Format, + RGB_ETC2_Format: RGB_ETC2_Format, + RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format, + RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format, + } + + /* WEB WORKER */ + + static BasisWorker = function () { + let config + let transcoderPending + let BasisModule + + const EngineFormat = _EngineFormat + const TranscoderFormat = _TranscoderFormat + const BasisFormat = _BasisFormat + + onmessage = function (e) { + const message = e.data + + switch (message.type) { + case 'init': + config = message.config + init(message.transcoderBinary) + break + + case 'transcode': + transcoderPending.then(() => { + try { + const { width, height, hasAlpha, mipmaps, format } = message.taskConfig.lowLevel + ? transcodeLowLevel(message.taskConfig) + : transcode(message.buffers[0]) + + const buffers = [] + + for (let i = 0; i < mipmaps.length; ++i) { + buffers.push(mipmaps[i].data.buffer) + } + + self.postMessage({ type: 'transcode', id: message.id, width, height, hasAlpha, mipmaps, format }, buffers) + } catch (error) { + console.error(error) + + self.postMessage({ type: 'error', id: message.id, error: error.message }) + } + }) + break + } + } + + function init(wasmBinary) { + transcoderPending = new Promise((resolve) => { + BasisModule = { wasmBinary, onRuntimeInitialized: resolve } + BASIS(BasisModule) + }).then(() => { + BasisModule.initializeBasis() + }) + } + + function transcodeLowLevel(taskConfig) { + const { basisFormat, width, height, hasAlpha } = taskConfig + + const { transcoderFormat, engineFormat } = getTranscoderFormat(basisFormat, width, height, hasAlpha) + + const blockByteLength = BasisModule.getBytesPerBlockOrPixel(transcoderFormat) + + assert(BasisModule.isFormatSupported(transcoderFormat), 'THREE.BasisTextureLoader: Unsupported format.') + + const mipmaps = [] + + if (basisFormat === BasisFormat.ETC1S) { + const transcoder = new BasisModule.LowLevelETC1SImageTranscoder() + + const { endpointCount, endpointsData, selectorCount, selectorsData, tablesData } = taskConfig.globalData + + try { + let ok + + ok = transcoder.decodePalettes(endpointCount, endpointsData, selectorCount, selectorsData) + + assert(ok, 'THREE.BasisTextureLoader: decodePalettes() failed.') + + ok = transcoder.decodeTables(tablesData) + + assert(ok, 'THREE.BasisTextureLoader: decodeTables() failed.') + + for (let i = 0; i < taskConfig.levels.length; i++) { + const level = taskConfig.levels[i] + const imageDesc = taskConfig.globalData.imageDescs[i] + + const dstByteLength = getTranscodedImageByteLength(transcoderFormat, level.width, level.height) + const dst = new Uint8Array(dstByteLength) + + ok = transcoder.transcodeImage( + transcoderFormat, + dst, + dstByteLength / blockByteLength, + level.data, + getWidthInBlocks(transcoderFormat, level.width), + getHeightInBlocks(transcoderFormat, level.height), + level.width, + level.height, + level.index, + imageDesc.rgbSliceByteOffset, + imageDesc.rgbSliceByteLength, + imageDesc.alphaSliceByteOffset, + imageDesc.alphaSliceByteLength, + imageDesc.imageFlags, + hasAlpha, + false, + 0, + 0, + ) + + assert(ok, 'THREE.BasisTextureLoader: transcodeImage() failed for level ' + level.index + '.') + + mipmaps.push({ data: dst, width: level.width, height: level.height }) + } + } finally { + transcoder.delete() + } + } else { + for (let i = 0; i < taskConfig.levels.length; i++) { + const level = taskConfig.levels[i] + + const dstByteLength = getTranscodedImageByteLength(transcoderFormat, level.width, level.height) + const dst = new Uint8Array(dstByteLength) + + const ok = BasisModule.transcodeUASTCImage( + transcoderFormat, + dst, + dstByteLength / blockByteLength, + level.data, + getWidthInBlocks(transcoderFormat, level.width), + getHeightInBlocks(transcoderFormat, level.height), + level.width, + level.height, + level.index, + 0, + level.data.byteLength, + 0, + hasAlpha, + false, + 0, + 0, + -1, + -1, + ) + + assert(ok, 'THREE.BasisTextureLoader: transcodeUASTCImage() failed for level ' + level.index + '.') + + mipmaps.push({ data: dst, width: level.width, height: level.height }) + } + } + + return { width, height, hasAlpha, mipmaps, format: engineFormat } + } + + function transcode(buffer) { + const basisFile = new BasisModule.BasisFile(new Uint8Array(buffer)) + + const basisFormat = basisFile.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S + const width = basisFile.getImageWidth(0, 0) + const height = basisFile.getImageHeight(0, 0) + const levels = basisFile.getNumLevels(0) + const hasAlpha = basisFile.getHasAlpha() + + function cleanup() { + basisFile.close() + basisFile.delete() + } + + const { transcoderFormat, engineFormat } = getTranscoderFormat(basisFormat, width, height, hasAlpha) + + if (!width || !height || !levels) { + cleanup() + throw new Error('THREE.BasisTextureLoader: Invalid texture') + } + + if (!basisFile.startTranscoding()) { + cleanup() + throw new Error('THREE.BasisTextureLoader: .startTranscoding failed') + } + + const mipmaps = [] + + for (let mip = 0; mip < levels; mip++) { + const mipWidth = basisFile.getImageWidth(0, mip) + const mipHeight = basisFile.getImageHeight(0, mip) + const dst = new Uint8Array(basisFile.getImageTranscodedSizeInBytes(0, mip, transcoderFormat)) + + const status = basisFile.transcodeImage(dst, 0, mip, transcoderFormat, 0, hasAlpha) + + if (!status) { + cleanup() + throw new Error('THREE.BasisTextureLoader: .transcodeImage failed.') + } + + mipmaps.push({ data: dst, width: mipWidth, height: mipHeight }) + } + + cleanup() + + return { width, height, hasAlpha, mipmaps, format: engineFormat } + } + + // + + // Optimal choice of a transcoder target format depends on the Basis format (ETC1S or UASTC), + // device capabilities, and texture dimensions. The list below ranks the formats separately + // for ETC1S and UASTC. + // + // In some cases, transcoding UASTC to RGBA32 might be preferred for higher quality (at + // significant memory cost) compared to ETC1/2, BC1/3, and PVRTC. The transcoder currently + // chooses RGBA32 only as a last resort and does not expose that option to the caller. + const FORMAT_OPTIONS = [ + { + if: 'astcSupported', + basisFormat: [BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4], + engineFormat: [EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format], + priorityETC1S: Infinity, + priorityUASTC: 1, + needsPowerOfTwo: false, + }, + { + if: 'bptcSupported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5], + engineFormat: [EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format], + priorityETC1S: 3, + priorityUASTC: 2, + needsPowerOfTwo: false, + }, + { + if: 'dxtSupported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.BC1, TranscoderFormat.BC3], + engineFormat: [EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format], + priorityETC1S: 4, + priorityUASTC: 5, + needsPowerOfTwo: false, + }, + { + if: 'etc2Supported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.ETC1, TranscoderFormat.ETC2], + engineFormat: [EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format], + priorityETC1S: 1, + priorityUASTC: 3, + needsPowerOfTwo: false, + }, + { + if: 'etc1Supported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.ETC1, TranscoderFormat.ETC1], + engineFormat: [EngineFormat.RGB_ETC1_Format, EngineFormat.RGB_ETC1_Format], + priorityETC1S: 2, + priorityUASTC: 4, + needsPowerOfTwo: false, + }, + { + if: 'pvrtcSupported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA], + engineFormat: [EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format], + priorityETC1S: 5, + priorityUASTC: 6, + needsPowerOfTwo: true, + }, + ] + + const ETC1S_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) { + return a.priorityETC1S - b.priorityETC1S + }) + const UASTC_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) { + return a.priorityUASTC - b.priorityUASTC + }) + + function getTranscoderFormat(basisFormat, width, height, hasAlpha) { + let transcoderFormat + let engineFormat + + const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS + + for (let i = 0; i < options.length; i++) { + const opt = options[i] + + if (!config[opt.if]) continue + if (!opt.basisFormat.includes(basisFormat)) continue + if (opt.needsPowerOfTwo && !(isPowerOfTwo(width) && isPowerOfTwo(height))) continue + + transcoderFormat = opt.transcoderFormat[hasAlpha ? 1 : 0] + engineFormat = opt.engineFormat[hasAlpha ? 1 : 0] + + return { transcoderFormat, engineFormat } + } + + console.warn('THREE.BasisTextureLoader: No suitable compressed texture format found. Decoding to RGBA32.') + + transcoderFormat = TranscoderFormat.RGBA32 + engineFormat = EngineFormat.RGBAFormat + + return { transcoderFormat, engineFormat } + } + + function assert(ok, message) { + if (!ok) throw new Error(message) + } + + function getWidthInBlocks(transcoderFormat, width) { + return Math.ceil(width / BasisModule.getFormatBlockWidth(transcoderFormat)) + } + + function getHeightInBlocks(transcoderFormat, height) { + return Math.ceil(height / BasisModule.getFormatBlockHeight(transcoderFormat)) + } + + function getTranscodedImageByteLength(transcoderFormat, width, height) { + const blockByteLength = BasisModule.getBytesPerBlockOrPixel(transcoderFormat) + + if (BasisModule.formatIsUncompressed(transcoderFormat)) { + return width * height * blockByteLength + } + + if (transcoderFormat === TranscoderFormat.PVRTC1_4_RGB || transcoderFormat === TranscoderFormat.PVRTC1_4_RGBA) { + // GL requires extra padding for very small textures: + // https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt + const paddedWidth = (width + 3) & ~3 + const paddedHeight = (height + 3) & ~3 + + return (Math.max(8, paddedWidth) * Math.max(8, paddedHeight) * 4 + 7) / 8 + } + + return getWidthInBlocks(transcoderFormat, width) * getHeightInBlocks(transcoderFormat, height) * blockByteLength + } + + function isPowerOfTwo(value) { + if (value <= 2) return true + + return (value & (value - 1)) === 0 && value !== 0 + } + } + constructor(manager) { super(manager) @@ -275,382 +653,4 @@ class BasisTextureLoader extends Loader { } } -/* CONSTANTS */ - -BasisTextureLoader.BasisFormat = { - ETC1S: 0, - UASTC_4x4: 1, -} - -BasisTextureLoader.TranscoderFormat = { - ETC1: 0, - ETC2: 1, - BC1: 2, - BC3: 3, - BC4: 4, - BC5: 5, - BC7_M6_OPAQUE_ONLY: 6, - BC7_M5: 7, - PVRTC1_4_RGB: 8, - PVRTC1_4_RGBA: 9, - ASTC_4x4: 10, - ATC_RGB: 11, - ATC_RGBA_INTERPOLATED_ALPHA: 12, - RGBA32: 13, - RGB565: 14, - BGR565: 15, - RGBA4444: 16, -} - -BasisTextureLoader.EngineFormat = { - RGBAFormat: RGBAFormat, - RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format, - RGBA_BPTC_Format: RGBA_BPTC_Format, - RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format, - RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format, - RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format, - RGB_ETC1_Format: RGB_ETC1_Format, - RGB_ETC2_Format: RGB_ETC2_Format, - RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format, - RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format, -} - -/* WEB WORKER */ - -BasisTextureLoader.BasisWorker = function () { - let config - let transcoderPending - let BasisModule - - const EngineFormat = _EngineFormat - const TranscoderFormat = _TranscoderFormat - const BasisFormat = _BasisFormat - - onmessage = function (e) { - const message = e.data - - switch (message.type) { - case 'init': - config = message.config - init(message.transcoderBinary) - break - - case 'transcode': - transcoderPending.then(() => { - try { - const { width, height, hasAlpha, mipmaps, format } = message.taskConfig.lowLevel - ? transcodeLowLevel(message.taskConfig) - : transcode(message.buffers[0]) - - const buffers = [] - - for (let i = 0; i < mipmaps.length; ++i) { - buffers.push(mipmaps[i].data.buffer) - } - - self.postMessage({ type: 'transcode', id: message.id, width, height, hasAlpha, mipmaps, format }, buffers) - } catch (error) { - console.error(error) - - self.postMessage({ type: 'error', id: message.id, error: error.message }) - } - }) - break - } - } - - function init(wasmBinary) { - transcoderPending = new Promise((resolve) => { - BasisModule = { wasmBinary, onRuntimeInitialized: resolve } - BASIS(BasisModule) - }).then(() => { - BasisModule.initializeBasis() - }) - } - - function transcodeLowLevel(taskConfig) { - const { basisFormat, width, height, hasAlpha } = taskConfig - - const { transcoderFormat, engineFormat } = getTranscoderFormat(basisFormat, width, height, hasAlpha) - - const blockByteLength = BasisModule.getBytesPerBlockOrPixel(transcoderFormat) - - assert(BasisModule.isFormatSupported(transcoderFormat), 'THREE.BasisTextureLoader: Unsupported format.') - - const mipmaps = [] - - if (basisFormat === BasisFormat.ETC1S) { - const transcoder = new BasisModule.LowLevelETC1SImageTranscoder() - - const { endpointCount, endpointsData, selectorCount, selectorsData, tablesData } = taskConfig.globalData - - try { - let ok - - ok = transcoder.decodePalettes(endpointCount, endpointsData, selectorCount, selectorsData) - - assert(ok, 'THREE.BasisTextureLoader: decodePalettes() failed.') - - ok = transcoder.decodeTables(tablesData) - - assert(ok, 'THREE.BasisTextureLoader: decodeTables() failed.') - - for (let i = 0; i < taskConfig.levels.length; i++) { - const level = taskConfig.levels[i] - const imageDesc = taskConfig.globalData.imageDescs[i] - - const dstByteLength = getTranscodedImageByteLength(transcoderFormat, level.width, level.height) - const dst = new Uint8Array(dstByteLength) - - ok = transcoder.transcodeImage( - transcoderFormat, - dst, - dstByteLength / blockByteLength, - level.data, - getWidthInBlocks(transcoderFormat, level.width), - getHeightInBlocks(transcoderFormat, level.height), - level.width, - level.height, - level.index, - imageDesc.rgbSliceByteOffset, - imageDesc.rgbSliceByteLength, - imageDesc.alphaSliceByteOffset, - imageDesc.alphaSliceByteLength, - imageDesc.imageFlags, - hasAlpha, - false, - 0, - 0, - ) - - assert(ok, 'THREE.BasisTextureLoader: transcodeImage() failed for level ' + level.index + '.') - - mipmaps.push({ data: dst, width: level.width, height: level.height }) - } - } finally { - transcoder.delete() - } - } else { - for (let i = 0; i < taskConfig.levels.length; i++) { - const level = taskConfig.levels[i] - - const dstByteLength = getTranscodedImageByteLength(transcoderFormat, level.width, level.height) - const dst = new Uint8Array(dstByteLength) - - const ok = BasisModule.transcodeUASTCImage( - transcoderFormat, - dst, - dstByteLength / blockByteLength, - level.data, - getWidthInBlocks(transcoderFormat, level.width), - getHeightInBlocks(transcoderFormat, level.height), - level.width, - level.height, - level.index, - 0, - level.data.byteLength, - 0, - hasAlpha, - false, - 0, - 0, - -1, - -1, - ) - - assert(ok, 'THREE.BasisTextureLoader: transcodeUASTCImage() failed for level ' + level.index + '.') - - mipmaps.push({ data: dst, width: level.width, height: level.height }) - } - } - - return { width, height, hasAlpha, mipmaps, format: engineFormat } - } - - function transcode(buffer) { - const basisFile = new BasisModule.BasisFile(new Uint8Array(buffer)) - - const basisFormat = basisFile.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S - const width = basisFile.getImageWidth(0, 0) - const height = basisFile.getImageHeight(0, 0) - const levels = basisFile.getNumLevels(0) - const hasAlpha = basisFile.getHasAlpha() - - function cleanup() { - basisFile.close() - basisFile.delete() - } - - const { transcoderFormat, engineFormat } = getTranscoderFormat(basisFormat, width, height, hasAlpha) - - if (!width || !height || !levels) { - cleanup() - throw new Error('THREE.BasisTextureLoader: Invalid texture') - } - - if (!basisFile.startTranscoding()) { - cleanup() - throw new Error('THREE.BasisTextureLoader: .startTranscoding failed') - } - - const mipmaps = [] - - for (let mip = 0; mip < levels; mip++) { - const mipWidth = basisFile.getImageWidth(0, mip) - const mipHeight = basisFile.getImageHeight(0, mip) - const dst = new Uint8Array(basisFile.getImageTranscodedSizeInBytes(0, mip, transcoderFormat)) - - const status = basisFile.transcodeImage(dst, 0, mip, transcoderFormat, 0, hasAlpha) - - if (!status) { - cleanup() - throw new Error('THREE.BasisTextureLoader: .transcodeImage failed.') - } - - mipmaps.push({ data: dst, width: mipWidth, height: mipHeight }) - } - - cleanup() - - return { width, height, hasAlpha, mipmaps, format: engineFormat } - } - - // - - // Optimal choice of a transcoder target format depends on the Basis format (ETC1S or UASTC), - // device capabilities, and texture dimensions. The list below ranks the formats separately - // for ETC1S and UASTC. - // - // In some cases, transcoding UASTC to RGBA32 might be preferred for higher quality (at - // significant memory cost) compared to ETC1/2, BC1/3, and PVRTC. The transcoder currently - // chooses RGBA32 only as a last resort and does not expose that option to the caller. - const FORMAT_OPTIONS = [ - { - if: 'astcSupported', - basisFormat: [BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4], - engineFormat: [EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format], - priorityETC1S: Infinity, - priorityUASTC: 1, - needsPowerOfTwo: false, - }, - { - if: 'bptcSupported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5], - engineFormat: [EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format], - priorityETC1S: 3, - priorityUASTC: 2, - needsPowerOfTwo: false, - }, - { - if: 'dxtSupported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.BC1, TranscoderFormat.BC3], - engineFormat: [EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format], - priorityETC1S: 4, - priorityUASTC: 5, - needsPowerOfTwo: false, - }, - { - if: 'etc2Supported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.ETC1, TranscoderFormat.ETC2], - engineFormat: [EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format], - priorityETC1S: 1, - priorityUASTC: 3, - needsPowerOfTwo: false, - }, - { - if: 'etc1Supported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.ETC1, TranscoderFormat.ETC1], - engineFormat: [EngineFormat.RGB_ETC1_Format, EngineFormat.RGB_ETC1_Format], - priorityETC1S: 2, - priorityUASTC: 4, - needsPowerOfTwo: false, - }, - { - if: 'pvrtcSupported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA], - engineFormat: [EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format], - priorityETC1S: 5, - priorityUASTC: 6, - needsPowerOfTwo: true, - }, - ] - - const ETC1S_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) { - return a.priorityETC1S - b.priorityETC1S - }) - const UASTC_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) { - return a.priorityUASTC - b.priorityUASTC - }) - - function getTranscoderFormat(basisFormat, width, height, hasAlpha) { - let transcoderFormat - let engineFormat - - const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS - - for (let i = 0; i < options.length; i++) { - const opt = options[i] - - if (!config[opt.if]) continue - if (!opt.basisFormat.includes(basisFormat)) continue - if (opt.needsPowerOfTwo && !(isPowerOfTwo(width) && isPowerOfTwo(height))) continue - - transcoderFormat = opt.transcoderFormat[hasAlpha ? 1 : 0] - engineFormat = opt.engineFormat[hasAlpha ? 1 : 0] - - return { transcoderFormat, engineFormat } - } - - console.warn('THREE.BasisTextureLoader: No suitable compressed texture format found. Decoding to RGBA32.') - - transcoderFormat = TranscoderFormat.RGBA32 - engineFormat = EngineFormat.RGBAFormat - - return { transcoderFormat, engineFormat } - } - - function assert(ok, message) { - if (!ok) throw new Error(message) - } - - function getWidthInBlocks(transcoderFormat, width) { - return Math.ceil(width / BasisModule.getFormatBlockWidth(transcoderFormat)) - } - - function getHeightInBlocks(transcoderFormat, height) { - return Math.ceil(height / BasisModule.getFormatBlockHeight(transcoderFormat)) - } - - function getTranscodedImageByteLength(transcoderFormat, width, height) { - const blockByteLength = BasisModule.getBytesPerBlockOrPixel(transcoderFormat) - - if (BasisModule.formatIsUncompressed(transcoderFormat)) { - return width * height * blockByteLength - } - - if (transcoderFormat === TranscoderFormat.PVRTC1_4_RGB || transcoderFormat === TranscoderFormat.PVRTC1_4_RGBA) { - // GL requires extra padding for very small textures: - // https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt - const paddedWidth = (width + 3) & ~3 - const paddedHeight = (height + 3) & ~3 - - return (Math.max(8, paddedWidth) * Math.max(8, paddedHeight) * 4 + 7) / 8 - } - - return getWidthInBlocks(transcoderFormat, width) * getHeightInBlocks(transcoderFormat, height) * blockByteLength - } - - function isPowerOfTwo(value) { - if (value <= 2) return true - - return (value & (value - 1)) === 0 && value !== 0 - } -} - export { BasisTextureLoader } diff --git a/src/loaders/ColladaLoader.js b/src/loaders/ColladaLoader.js index 4df58002..6b534f87 100644 --- a/src/loaders/ColladaLoader.js +++ b/src/loaders/ColladaLoader.js @@ -38,7 +38,7 @@ import { Vector3, VectorKeyframeTrack, } from 'three' -import { TGALoader } from '../loaders/TGALoader.js' +import { TGALoader } from '../loaders/TGALoader' class ColladaLoader extends Loader { constructor(manager) { diff --git a/src/loaders/FBXLoader.js b/src/loaders/FBXLoader.js index 7410e737..3e18c5fb 100644 --- a/src/loaders/FBXLoader.js +++ b/src/loaders/FBXLoader.js @@ -3116,8 +3116,8 @@ function getData(polygonVertexIndex, polygonIndex, vertexIndex, infoObject) { return slice(dataArray, infoObject.buffer, from, to) } -const tempEuler = new Euler() -const tempVec = new Vector3() +const tempEuler = /* @__PURE__ */ new Euler() +const tempVec = /* @__PURE__ */ new Vector3() // generate transformation from FBX transform data // ref: https://help.autodesk.com/view/FBX/2017/ENU/?guid=__files_GUID_10CDD63C_79C1_4F2D_BB28_AD2BE65A02ED_htm diff --git a/src/loaders/GLTFLoader.js b/src/loaders/GLTFLoader.js index a6dbb87c..59c2bdeb 100644 --- a/src/loaders/GLTFLoader.js +++ b/src/loaders/GLTFLoader.js @@ -1830,7 +1830,7 @@ function getImageURIMimeType(uri) { return 'image/png' } -const _identityMatrix = new Matrix4() +const _identityMatrix = /* @__PURE__ */ new Matrix4() /* GLTF PARSER */ diff --git a/src/loaders/KTX2Loader.js b/src/loaders/KTX2Loader.js index e5d56698..eef1646d 100644 --- a/src/loaders/KTX2Loader.js +++ b/src/loaders/KTX2Loader.js @@ -34,7 +34,7 @@ import { RGFormat, UnsignedByteType, } from 'three' -import { WorkerPool } from '../utils/WorkerPool.js' +import { WorkerPool } from '../utils/WorkerPool' import { read, KHR_DF_FLAG_ALPHA_PREMULTIPLIED, @@ -66,6 +66,309 @@ let _activeLoaders = 0 let _zstd class KTX2Loader extends Loader { + /* CONSTANTS */ + + static BasisFormat = { + ETC1S: 0, + UASTC_4x4: 1, + } + + static TranscoderFormat = { + ETC1: 0, + ETC2: 1, + BC1: 2, + BC3: 3, + BC4: 4, + BC5: 5, + BC7_M6_OPAQUE_ONLY: 6, + BC7_M5: 7, + PVRTC1_4_RGB: 8, + PVRTC1_4_RGBA: 9, + ASTC_4x4: 10, + ATC_RGB: 11, + ATC_RGBA_INTERPOLATED_ALPHA: 12, + RGBA32: 13, + RGB565: 14, + BGR565: 15, + RGBA4444: 16, + } + + static EngineFormat = { + RGBAFormat: RGBAFormat, + RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format, + RGBA_BPTC_Format: RGBA_BPTC_Format, + RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format, + RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format, + RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format, + RGB_ETC1_Format: RGB_ETC1_Format, + RGB_ETC2_Format: RGB_ETC2_Format, + RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format, + RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format, + } + + /* WEB WORKER */ + + static BasisWorker = function () { + let config + let transcoderPending + let BasisModule + + const EngineFormat = _EngineFormat + const TranscoderFormat = _TranscoderFormat + const BasisFormat = _BasisFormat + + self.addEventListener('message', function (e) { + const message = e.data + + switch (message.type) { + case 'init': + config = message.config + init(message.transcoderBinary) + break + + case 'transcode': + transcoderPending.then(() => { + try { + const { width, height, hasAlpha, mipmaps, format, dfdTransferFn, dfdFlags } = transcode(message.buffer) + + const buffers = [] + + for (let i = 0; i < mipmaps.length; ++i) { + buffers.push(mipmaps[i].data.buffer) + } + + self.postMessage( + { + type: 'transcode', + id: message.id, + width, + height, + hasAlpha, + mipmaps, + format, + dfdTransferFn, + dfdFlags, + }, + buffers, + ) + } catch (error) { + console.error(error) + + self.postMessage({ type: 'error', id: message.id, error: error.message }) + } + }) + break + } + }) + + function init(wasmBinary) { + transcoderPending = new Promise((resolve) => { + BasisModule = { wasmBinary, onRuntimeInitialized: resolve } + BASIS(BasisModule) + }).then(() => { + BasisModule.initializeBasis() + + if (BasisModule.KTX2File === undefined) { + console.warn('THREE.KTX2Loader: Please update Basis Universal transcoder.') + } + }) + } + + function transcode(buffer) { + const ktx2File = new BasisModule.KTX2File(new Uint8Array(buffer)) + + function cleanup() { + ktx2File.close() + ktx2File.delete() + } + + if (!ktx2File.isValid()) { + cleanup() + throw new Error('THREE.KTX2Loader: Invalid or unsupported .ktx2 file') + } + + const basisFormat = ktx2File.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S + const width = ktx2File.getWidth() + const height = ktx2File.getHeight() + const layers = ktx2File.getLayers() || 1 + const levels = ktx2File.getLevels() + const hasAlpha = ktx2File.getHasAlpha() + const dfdTransferFn = ktx2File.getDFDTransferFunc() + const dfdFlags = ktx2File.getDFDFlags() + + const { transcoderFormat, engineFormat } = getTranscoderFormat(basisFormat, width, height, hasAlpha) + + if (!width || !height || !levels) { + cleanup() + throw new Error('THREE.KTX2Loader: Invalid texture') + } + + if (!ktx2File.startTranscoding()) { + cleanup() + throw new Error('THREE.KTX2Loader: .startTranscoding failed') + } + + const mipmaps = [] + + for (let mip = 0; mip < levels; mip++) { + const layerMips = [] + + let mipWidth, mipHeight + + for (let layer = 0; layer < layers; layer++) { + const levelInfo = ktx2File.getImageLevelInfo(mip, layer, 0) + mipWidth = levelInfo.origWidth < 4 ? levelInfo.origWidth : levelInfo.width + mipHeight = levelInfo.origHeight < 4 ? levelInfo.origHeight : levelInfo.height + const dst = new Uint8Array(ktx2File.getImageTranscodedSizeInBytes(mip, layer, 0, transcoderFormat)) + const status = ktx2File.transcodeImage(dst, mip, layer, 0, transcoderFormat, 0, -1, -1) + + if (!status) { + cleanup() + throw new Error('THREE.KTX2Loader: .transcodeImage failed.') + } + + layerMips.push(dst) + } + + mipmaps.push({ data: concat(layerMips), width: mipWidth, height: mipHeight }) + } + + cleanup() + + return { width, height, hasAlpha, mipmaps, format: engineFormat, dfdTransferFn, dfdFlags } + } + + // + + // Optimal choice of a transcoder target format depends on the Basis format (ETC1S or UASTC), + // device capabilities, and texture dimensions. The list below ranks the formats separately + // for ETC1S and UASTC. + // + // In some cases, transcoding UASTC to RGBA32 might be preferred for higher quality (at + // significant memory cost) compared to ETC1/2, BC1/3, and PVRTC. The transcoder currently + // chooses RGBA32 only as a last resort and does not expose that option to the caller. + const FORMAT_OPTIONS = [ + { + if: 'astcSupported', + basisFormat: [BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4], + engineFormat: [EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format], + priorityETC1S: Infinity, + priorityUASTC: 1, + needsPowerOfTwo: false, + }, + { + if: 'bptcSupported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5], + engineFormat: [EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format], + priorityETC1S: 3, + priorityUASTC: 2, + needsPowerOfTwo: false, + }, + { + if: 'dxtSupported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.BC1, TranscoderFormat.BC3], + engineFormat: [EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format], + priorityETC1S: 4, + priorityUASTC: 5, + needsPowerOfTwo: false, + }, + { + if: 'etc2Supported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.ETC1, TranscoderFormat.ETC2], + engineFormat: [EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format], + priorityETC1S: 1, + priorityUASTC: 3, + needsPowerOfTwo: false, + }, + { + if: 'etc1Supported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.ETC1], + engineFormat: [EngineFormat.RGB_ETC1_Format], + priorityETC1S: 2, + priorityUASTC: 4, + needsPowerOfTwo: false, + }, + { + if: 'pvrtcSupported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA], + engineFormat: [EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format], + priorityETC1S: 5, + priorityUASTC: 6, + needsPowerOfTwo: true, + }, + ] + + const ETC1S_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) { + return a.priorityETC1S - b.priorityETC1S + }) + const UASTC_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) { + return a.priorityUASTC - b.priorityUASTC + }) + + function getTranscoderFormat(basisFormat, width, height, hasAlpha) { + let transcoderFormat + let engineFormat + + const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS + + for (let i = 0; i < options.length; i++) { + const opt = options[i] + + if (!config[opt.if]) continue + if (!opt.basisFormat.includes(basisFormat)) continue + if (hasAlpha && opt.transcoderFormat.length < 2) continue + if (opt.needsPowerOfTwo && !(isPowerOfTwo(width) && isPowerOfTwo(height))) continue + + transcoderFormat = opt.transcoderFormat[hasAlpha ? 1 : 0] + engineFormat = opt.engineFormat[hasAlpha ? 1 : 0] + + return { transcoderFormat, engineFormat } + } + + console.warn('THREE.KTX2Loader: No suitable compressed texture format found. Decoding to RGBA32.') + + transcoderFormat = TranscoderFormat.RGBA32 + engineFormat = EngineFormat.RGBAFormat + + return { transcoderFormat, engineFormat } + } + + function isPowerOfTwo(value) { + if (value <= 2) return true + + return (value & (value - 1)) === 0 && value !== 0 + } + + /** Concatenates N byte arrays. */ + function concat(arrays) { + let totalByteLength = 0 + + for (let i = 0; i < arrays.length; i++) { + const array = arrays[i] + totalByteLength += array.byteLength + } + + const result = new Uint8Array(totalByteLength) + + let byteOffset = 0 + + for (let i = 0; i < arrays.length; i++) { + const array = arrays[i] + result.set(array, byteOffset) + + byteOffset += array.byteLength + } + + return result + } + } + constructor(manager) { super(manager) @@ -262,299 +565,6 @@ class KTX2Loader extends Loader { } } -/* CONSTANTS */ - -KTX2Loader.BasisFormat = { - ETC1S: 0, - UASTC_4x4: 1, -} - -KTX2Loader.TranscoderFormat = { - ETC1: 0, - ETC2: 1, - BC1: 2, - BC3: 3, - BC4: 4, - BC5: 5, - BC7_M6_OPAQUE_ONLY: 6, - BC7_M5: 7, - PVRTC1_4_RGB: 8, - PVRTC1_4_RGBA: 9, - ASTC_4x4: 10, - ATC_RGB: 11, - ATC_RGBA_INTERPOLATED_ALPHA: 12, - RGBA32: 13, - RGB565: 14, - BGR565: 15, - RGBA4444: 16, -} - -KTX2Loader.EngineFormat = { - RGBAFormat: RGBAFormat, - RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format, - RGBA_BPTC_Format: RGBA_BPTC_Format, - RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format, - RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format, - RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format, - RGB_ETC1_Format: RGB_ETC1_Format, - RGB_ETC2_Format: RGB_ETC2_Format, - RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format, - RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format, -} - -/* WEB WORKER */ - -KTX2Loader.BasisWorker = function () { - let config - let transcoderPending - let BasisModule - - const EngineFormat = _EngineFormat - const TranscoderFormat = _TranscoderFormat - const BasisFormat = _BasisFormat - - self.addEventListener('message', function (e) { - const message = e.data - - switch (message.type) { - case 'init': - config = message.config - init(message.transcoderBinary) - break - - case 'transcode': - transcoderPending.then(() => { - try { - const { width, height, hasAlpha, mipmaps, format, dfdTransferFn, dfdFlags } = transcode(message.buffer) - - const buffers = [] - - for (let i = 0; i < mipmaps.length; ++i) { - buffers.push(mipmaps[i].data.buffer) - } - - self.postMessage( - { type: 'transcode', id: message.id, width, height, hasAlpha, mipmaps, format, dfdTransferFn, dfdFlags }, - buffers, - ) - } catch (error) { - console.error(error) - - self.postMessage({ type: 'error', id: message.id, error: error.message }) - } - }) - break - } - }) - - function init(wasmBinary) { - transcoderPending = new Promise((resolve) => { - BasisModule = { wasmBinary, onRuntimeInitialized: resolve } - BASIS(BasisModule) - }).then(() => { - BasisModule.initializeBasis() - - if (BasisModule.KTX2File === undefined) { - console.warn('THREE.KTX2Loader: Please update Basis Universal transcoder.') - } - }) - } - - function transcode(buffer) { - const ktx2File = new BasisModule.KTX2File(new Uint8Array(buffer)) - - function cleanup() { - ktx2File.close() - ktx2File.delete() - } - - if (!ktx2File.isValid()) { - cleanup() - throw new Error('THREE.KTX2Loader: Invalid or unsupported .ktx2 file') - } - - const basisFormat = ktx2File.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S - const width = ktx2File.getWidth() - const height = ktx2File.getHeight() - const layers = ktx2File.getLayers() || 1 - const levels = ktx2File.getLevels() - const hasAlpha = ktx2File.getHasAlpha() - const dfdTransferFn = ktx2File.getDFDTransferFunc() - const dfdFlags = ktx2File.getDFDFlags() - - const { transcoderFormat, engineFormat } = getTranscoderFormat(basisFormat, width, height, hasAlpha) - - if (!width || !height || !levels) { - cleanup() - throw new Error('THREE.KTX2Loader: Invalid texture') - } - - if (!ktx2File.startTranscoding()) { - cleanup() - throw new Error('THREE.KTX2Loader: .startTranscoding failed') - } - - const mipmaps = [] - - for (let mip = 0; mip < levels; mip++) { - const layerMips = [] - - let mipWidth, mipHeight - - for (let layer = 0; layer < layers; layer++) { - const levelInfo = ktx2File.getImageLevelInfo(mip, layer, 0) - mipWidth = levelInfo.origWidth < 4 ? levelInfo.origWidth : levelInfo.width - mipHeight = levelInfo.origHeight < 4 ? levelInfo.origHeight : levelInfo.height - const dst = new Uint8Array(ktx2File.getImageTranscodedSizeInBytes(mip, layer, 0, transcoderFormat)) - const status = ktx2File.transcodeImage(dst, mip, layer, 0, transcoderFormat, 0, -1, -1) - - if (!status) { - cleanup() - throw new Error('THREE.KTX2Loader: .transcodeImage failed.') - } - - layerMips.push(dst) - } - - mipmaps.push({ data: concat(layerMips), width: mipWidth, height: mipHeight }) - } - - cleanup() - - return { width, height, hasAlpha, mipmaps, format: engineFormat, dfdTransferFn, dfdFlags } - } - - // - - // Optimal choice of a transcoder target format depends on the Basis format (ETC1S or UASTC), - // device capabilities, and texture dimensions. The list below ranks the formats separately - // for ETC1S and UASTC. - // - // In some cases, transcoding UASTC to RGBA32 might be preferred for higher quality (at - // significant memory cost) compared to ETC1/2, BC1/3, and PVRTC. The transcoder currently - // chooses RGBA32 only as a last resort and does not expose that option to the caller. - const FORMAT_OPTIONS = [ - { - if: 'astcSupported', - basisFormat: [BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4], - engineFormat: [EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format], - priorityETC1S: Infinity, - priorityUASTC: 1, - needsPowerOfTwo: false, - }, - { - if: 'bptcSupported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5], - engineFormat: [EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format], - priorityETC1S: 3, - priorityUASTC: 2, - needsPowerOfTwo: false, - }, - { - if: 'dxtSupported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.BC1, TranscoderFormat.BC3], - engineFormat: [EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format], - priorityETC1S: 4, - priorityUASTC: 5, - needsPowerOfTwo: false, - }, - { - if: 'etc2Supported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.ETC1, TranscoderFormat.ETC2], - engineFormat: [EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format], - priorityETC1S: 1, - priorityUASTC: 3, - needsPowerOfTwo: false, - }, - { - if: 'etc1Supported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.ETC1], - engineFormat: [EngineFormat.RGB_ETC1_Format], - priorityETC1S: 2, - priorityUASTC: 4, - needsPowerOfTwo: false, - }, - { - if: 'pvrtcSupported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA], - engineFormat: [EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format], - priorityETC1S: 5, - priorityUASTC: 6, - needsPowerOfTwo: true, - }, - ] - - const ETC1S_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) { - return a.priorityETC1S - b.priorityETC1S - }) - const UASTC_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) { - return a.priorityUASTC - b.priorityUASTC - }) - - function getTranscoderFormat(basisFormat, width, height, hasAlpha) { - let transcoderFormat - let engineFormat - - const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS - - for (let i = 0; i < options.length; i++) { - const opt = options[i] - - if (!config[opt.if]) continue - if (!opt.basisFormat.includes(basisFormat)) continue - if (hasAlpha && opt.transcoderFormat.length < 2) continue - if (opt.needsPowerOfTwo && !(isPowerOfTwo(width) && isPowerOfTwo(height))) continue - - transcoderFormat = opt.transcoderFormat[hasAlpha ? 1 : 0] - engineFormat = opt.engineFormat[hasAlpha ? 1 : 0] - - return { transcoderFormat, engineFormat } - } - - console.warn('THREE.KTX2Loader: No suitable compressed texture format found. Decoding to RGBA32.') - - transcoderFormat = TranscoderFormat.RGBA32 - engineFormat = EngineFormat.RGBAFormat - - return { transcoderFormat, engineFormat } - } - - function isPowerOfTwo(value) { - if (value <= 2) return true - - return (value & (value - 1)) === 0 && value !== 0 - } - - /** Concatenates N byte arrays. */ - function concat(arrays) { - let totalByteLength = 0 - - for (let i = 0; i < arrays.length; i++) { - const array = arrays[i] - totalByteLength += array.byteLength - } - - const result = new Uint8Array(totalByteLength) - - let byteOffset = 0 - - for (let i = 0; i < arrays.length; i++) { - const array = arrays[i] - result.set(array, byteOffset) - - byteOffset += array.byteLength - } - - return result - } -} - // // DataTexture and Data3DTexture parsing. diff --git a/src/loaders/LDrawLoader.js b/src/loaders/LDrawLoader.js index 8de7de7f..3debe46c 100644 --- a/src/loaders/LDrawLoader.js +++ b/src/loaders/LDrawLoader.js @@ -39,8 +39,8 @@ const FILE_LOCATION_NOT_FOUND = 6 const MAIN_COLOUR_CODE = '16' const MAIN_EDGE_COLOUR_CODE = '24' -const _tempVec0 = new Vector3() -const _tempVec1 = new Vector3() +const _tempVec0 = /* @__PURE__ */ new Vector3() +const _tempVec1 = /* @__PURE__ */ new Vector3() class LDrawConditionalLineMaterial extends ShaderMaterial { constructor(parameters) { @@ -179,7 +179,7 @@ function generateFaceNormals(faces) { } } -const _ray = new Ray() +const _ray = /* @__PURE__ */ new Ray() function smoothNormals(faces, lineSegments, checkSubSegments = false) { // NOTE: 1e2 is pretty coarse but was chosen to quantize the resulting value because // it allows edges to be smoothed as expected (see minifig arms). diff --git a/src/loaders/NodeMaterialLoader.js b/src/loaders/NodeMaterialLoader.js index ab5e4ce1..c690d3ad 100644 --- a/src/loaders/NodeMaterialLoader.js +++ b/src/loaders/NodeMaterialLoader.js @@ -1,6 +1,9 @@ import { Loader, FileLoader } from 'three' import * as Nodes from '../nodes/Nodes' +/** + * @deprecated + */ class NodeMaterialLoader extends Loader { constructor(manager, library = {}) { super(manager) diff --git a/src/loaders/OBJLoader.js b/src/loaders/OBJLoader.js index f5a5ffce..82ffde04 100644 --- a/src/loaders/OBJLoader.js +++ b/src/loaders/OBJLoader.js @@ -23,12 +23,12 @@ const _material_use_pattern = /^usemtl / // usemap map_name const _map_use_pattern = /^usemap / -const _vA = new Vector3() -const _vB = new Vector3() -const _vC = new Vector3() +const _vA = /* @__PURE__ */ new Vector3() +const _vB = /* @__PURE__ */ new Vector3() +const _vC = /* @__PURE__ */ new Vector3() -const _ab = new Vector3() -const _cb = new Vector3() +const _ab = /* @__PURE__ */ new Vector3() +const _cb = /* @__PURE__ */ new Vector3() function ParserState() { const state = { diff --git a/src/loaders/RGBMLoader.js b/src/loaders/RGBMLoader.js index c1e3406a..81c7ab30 100644 --- a/src/loaders/RGBMLoader.js +++ b/src/loaders/RGBMLoader.js @@ -1,1205 +1,1211 @@ import { DataTextureLoader, RGBAFormat, LinearFilter, CubeTexture, HalfFloatType, DataUtils } from 'three' -class RGBMLoader extends DataTextureLoader { - constructor(manager) { - super(manager) +let UPNG - this.type = HalfFloatType - this.maxRange = 7 // more information about this property at https://iwasbeingirony.blogspot.com/2010/06/difference-between-rgbm-and-rgbd.html - } +function init() { + if (UPNG) return UPNG + // from https://github.com/photopea/UPNG.js (MIT License) - setDataType(value) { - this.type = value - return this - } + UPNG = {} - setMaxRange(value) { - this.maxRange = value - return this - } - - loadCubemap(urls, onLoad, onProgress, onError) { - const texture = new CubeTexture() + UPNG.toRGBA8 = function (out) { + var w = out.width, + h = out.height + if (out.tabs.acTL == null) return [UPNG.toRGBA8.decodeImage(out.data, w, h, out).buffer] - let loaded = 0 + var frms = [] + if (out.frames[0].data == null) out.frames[0].data = out.data - const scope = this - - function loadTexture(i) { - scope.load( - urls[i], - function (image) { - texture.images[i] = image + var len = w * h * 4, + img = new Uint8Array(len), + empty = new Uint8Array(len), + prev = new Uint8Array(len) + for (var i = 0; i < out.frames.length; i++) { + var frm = out.frames[i] + var fx = frm.rect.x, + fy = frm.rect.y, + fw = frm.rect.width, + fh = frm.rect.height + var fdata = UPNG.toRGBA8.decodeImage(frm.data, fw, fh, out) - loaded++ + if (i != 0) for (var j = 0; j < len; j++) prev[j] = img[j] - if (loaded === 6) { - texture.needsUpdate = true + if (frm.blend == 0) UPNG._copyTile(fdata, fw, fh, img, w, h, fx, fy, 0) + else if (frm.blend == 1) UPNG._copyTile(fdata, fw, fh, img, w, h, fx, fy, 1) - if (onLoad) onLoad(texture) - } - }, - undefined, - onError, - ) - } + frms.push(img.buffer.slice(0)) - for (let i = 0; i < urls.length; ++i) { - loadTexture(i) + if (frm.dispose == 1) UPNG._copyTile(empty, fw, fh, img, w, h, fx, fy, 0) + else if (frm.dispose == 2) for (var j = 0; j < len; j++) img[j] = prev[j] } - texture.type = this.type - texture.format = RGBAFormat - texture.minFilter = LinearFilter - texture.generateMipmaps = false - - return texture + return frms } - parse(buffer) { - const img = UPNG.decode(buffer) - const rgba = UPNG.toRGBA8(img)[0] - - const data = new Uint8Array(rgba) - const size = img.width * img.height * 4 - - const output = this.type === HalfFloatType ? new Uint16Array(size) : new Float32Array(size) + UPNG.toRGBA8.decodeImage = function (data, w, h, out) { + var area = w * h, + bpp = UPNG.decode._getBPP(out) + var bpl = Math.ceil((w * bpp) / 8) // bytes per line - // decode RGBM + var bf = new Uint8Array(area * 4), + bf32 = new Uint32Array(bf.buffer) + var ctype = out.ctype, + depth = out.depth + var rs = UPNG._bin.readUshort - for (let i = 0; i < data.length; i += 4) { - const r = data[i + 0] / 255 - const g = data[i + 1] / 255 - const b = data[i + 2] / 255 - const a = data[i + 3] / 255 + if (ctype == 6) { + // RGB + alpha - if (this.type === HalfFloatType) { - output[i + 0] = DataUtils.toHalfFloat(Math.min(r * a * this.maxRange, 65504)) - output[i + 1] = DataUtils.toHalfFloat(Math.min(g * a * this.maxRange, 65504)) - output[i + 2] = DataUtils.toHalfFloat(Math.min(b * a * this.maxRange, 65504)) - output[i + 3] = DataUtils.toHalfFloat(1) - } else { - output[i + 0] = r * a * this.maxRange - output[i + 1] = g * a * this.maxRange - output[i + 2] = b * a * this.maxRange - output[i + 3] = 1 + var qarea = area << 2 + if (depth == 8) { + for (var i = 0; i < qarea; i += 4) { + bf[i] = data[i] + bf[i + 1] = data[i + 1] + bf[i + 2] = data[i + 2] + bf[i + 3] = data[i + 3] + } } - } - - return { - width: img.width, - height: img.height, - data: output, - format: RGBAFormat, - type: this.type, - flipY: true, - } - } -} -// from https://github.com/photopea/UPNG.js (MIT License) - -var UPNG = {} - -UPNG.toRGBA8 = function (out) { - var w = out.width, - h = out.height - if (out.tabs.acTL == null) return [UPNG.toRGBA8.decodeImage(out.data, w, h, out).buffer] - - var frms = [] - if (out.frames[0].data == null) out.frames[0].data = out.data - - var len = w * h * 4, - img = new Uint8Array(len), - empty = new Uint8Array(len), - prev = new Uint8Array(len) - for (var i = 0; i < out.frames.length; i++) { - var frm = out.frames[i] - var fx = frm.rect.x, - fy = frm.rect.y, - fw = frm.rect.width, - fh = frm.rect.height - var fdata = UPNG.toRGBA8.decodeImage(frm.data, fw, fh, out) - - if (i != 0) for (var j = 0; j < len; j++) prev[j] = img[j] - - if (frm.blend == 0) UPNG._copyTile(fdata, fw, fh, img, w, h, fx, fy, 0) - else if (frm.blend == 1) UPNG._copyTile(fdata, fw, fh, img, w, h, fx, fy, 1) - - frms.push(img.buffer.slice(0)) + if (depth == 16) { + for (var i = 0; i < qarea; i++) { + bf[i] = data[i << 1] + } + } + } else if (ctype == 2) { + // RGB + + var ts = out.tabs['tRNS'] + if (ts == null) { + if (depth == 8) { + for (var i = 0; i < area; i++) { + var ti = i * 3 + bf32[i] = (255 << 24) | (data[ti + 2] << 16) | (data[ti + 1] << 8) | data[ti] + } + } - if (frm.dispose == 1) UPNG._copyTile(empty, fw, fh, img, w, h, fx, fy, 0) - else if (frm.dispose == 2) for (var j = 0; j < len; j++) img[j] = prev[j] - } + if (depth == 16) { + for (var i = 0; i < area; i++) { + var ti = i * 6 + bf32[i] = (255 << 24) | (data[ti + 4] << 16) | (data[ti + 2] << 8) | data[ti] + } + } + } else { + var tr = ts[0], + tg = ts[1], + tb = ts[2] + if (depth == 8) { + for (var i = 0; i < area; i++) { + var qi = i << 2, + ti = i * 3 + bf32[i] = (255 << 24) | (data[ti + 2] << 16) | (data[ti + 1] << 8) | data[ti] + if (data[ti] == tr && data[ti + 1] == tg && data[ti + 2] == tb) bf[qi + 3] = 0 + } + } - return frms -} + if (depth == 16) { + for (var i = 0; i < area; i++) { + var qi = i << 2, + ti = i * 6 + bf32[i] = (255 << 24) | (data[ti + 4] << 16) | (data[ti + 2] << 8) | data[ti] + if (rs(data, ti) == tr && rs(data, ti + 2) == tg && rs(data, ti + 4) == tb) bf[qi + 3] = 0 + } + } + } + } else if (ctype == 3) { + // palette -UPNG.toRGBA8.decodeImage = function (data, w, h, out) { - var area = w * h, - bpp = UPNG.decode._getBPP(out) - var bpl = Math.ceil((w * bpp) / 8) // bytes per line - - var bf = new Uint8Array(area * 4), - bf32 = new Uint32Array(bf.buffer) - var ctype = out.ctype, - depth = out.depth - var rs = UPNG._bin.readUshort - - if (ctype == 6) { - // RGB + alpha - - var qarea = area << 2 - if (depth == 8) { - for (var i = 0; i < qarea; i += 4) { - bf[i] = data[i] - bf[i + 1] = data[i + 1] - bf[i + 2] = data[i + 2] - bf[i + 3] = data[i + 3] + var p = out.tabs['PLTE'], + ap = out.tabs['tRNS'], + tl = ap ? ap.length : 0 + //console.log(p, ap); + if (depth == 1) { + for (var y = 0; y < h; y++) { + var s0 = y * bpl, + t0 = y * w + for (var i = 0; i < w; i++) { + var qi = (t0 + i) << 2, + j = (data[s0 + (i >> 3)] >> (7 - ((i & 7) << 0))) & 1, + cj = 3 * j + bf[qi] = p[cj] + bf[qi + 1] = p[cj + 1] + bf[qi + 2] = p[cj + 2] + bf[qi + 3] = j < tl ? ap[j] : 255 + } + } } - } - if (depth == 16) { - for (var i = 0; i < qarea; i++) { - bf[i] = data[i << 1] + if (depth == 2) { + for (var y = 0; y < h; y++) { + var s0 = y * bpl, + t0 = y * w + for (var i = 0; i < w; i++) { + var qi = (t0 + i) << 2, + j = (data[s0 + (i >> 2)] >> (6 - ((i & 3) << 1))) & 3, + cj = 3 * j + bf[qi] = p[cj] + bf[qi + 1] = p[cj + 1] + bf[qi + 2] = p[cj + 2] + bf[qi + 3] = j < tl ? ap[j] : 255 + } + } } - } - } else if (ctype == 2) { - // RGB - var ts = out.tabs['tRNS'] - if (ts == null) { - if (depth == 8) { - for (var i = 0; i < area; i++) { - var ti = i * 3 - bf32[i] = (255 << 24) | (data[ti + 2] << 16) | (data[ti + 1] << 8) | data[ti] + if (depth == 4) { + for (var y = 0; y < h; y++) { + var s0 = y * bpl, + t0 = y * w + for (var i = 0; i < w; i++) { + var qi = (t0 + i) << 2, + j = (data[s0 + (i >> 1)] >> (4 - ((i & 1) << 2))) & 15, + cj = 3 * j + bf[qi] = p[cj] + bf[qi + 1] = p[cj + 1] + bf[qi + 2] = p[cj + 2] + bf[qi + 3] = j < tl ? ap[j] : 255 + } } } - if (depth == 16) { + if (depth == 8) { for (var i = 0; i < area; i++) { - var ti = i * 6 - bf32[i] = (255 << 24) | (data[ti + 4] << 16) | (data[ti + 2] << 8) | data[ti] + var qi = i << 2, + j = data[i], + cj = 3 * j + bf[qi] = p[cj] + bf[qi + 1] = p[cj + 1] + bf[qi + 2] = p[cj + 2] + bf[qi + 3] = j < tl ? ap[j] : 255 } } - } else { - var tr = ts[0], - tg = ts[1], - tb = ts[2] + } else if (ctype == 4) { + // gray + alpha + if (depth == 8) { for (var i = 0; i < area; i++) { var qi = i << 2, - ti = i * 3 - bf32[i] = (255 << 24) | (data[ti + 2] << 16) | (data[ti + 1] << 8) | data[ti] - if (data[ti] == tr && data[ti + 1] == tg && data[ti + 2] == tb) bf[qi + 3] = 0 + di = i << 1, + gr = data[di] + bf[qi] = gr + bf[qi + 1] = gr + bf[qi + 2] = gr + bf[qi + 3] = data[di + 1] } } if (depth == 16) { for (var i = 0; i < area; i++) { var qi = i << 2, - ti = i * 6 - bf32[i] = (255 << 24) | (data[ti + 4] << 16) | (data[ti + 2] << 8) | data[ti] - if (rs(data, ti) == tr && rs(data, ti + 2) == tg && rs(data, ti + 4) == tb) bf[qi + 3] = 0 + di = i << 2, + gr = data[di] + bf[qi] = gr + bf[qi + 1] = gr + bf[qi + 2] = gr + bf[qi + 3] = data[di + 2] } } - } - } else if (ctype == 3) { - // palette - - var p = out.tabs['PLTE'], - ap = out.tabs['tRNS'], - tl = ap ? ap.length : 0 - //console.log(p, ap); - if (depth == 1) { + } else if (ctype == 0) { + // gray + + var tr = out.tabs['tRNS'] ? out.tabs['tRNS'] : -1 for (var y = 0; y < h; y++) { - var s0 = y * bpl, - t0 = y * w - for (var i = 0; i < w; i++) { - var qi = (t0 + i) << 2, - j = (data[s0 + (i >> 3)] >> (7 - ((i & 7) << 0))) & 1, - cj = 3 * j - bf[qi] = p[cj] - bf[qi + 1] = p[cj + 1] - bf[qi + 2] = p[cj + 2] - bf[qi + 3] = j < tl ? ap[j] : 255 + var off = y * bpl, + to = y * w + if (depth == 1) { + for (var x = 0; x < w; x++) { + var gr = 255 * ((data[off + (x >>> 3)] >>> (7 - (x & 7))) & 1), + al = gr == tr * 255 ? 0 : 255 + bf32[to + x] = (al << 24) | (gr << 16) | (gr << 8) | gr + } + } else if (depth == 2) { + for (var x = 0; x < w; x++) { + var gr = 85 * ((data[off + (x >>> 2)] >>> (6 - ((x & 3) << 1))) & 3), + al = gr == tr * 85 ? 0 : 255 + bf32[to + x] = (al << 24) | (gr << 16) | (gr << 8) | gr + } + } else if (depth == 4) { + for (var x = 0; x < w; x++) { + var gr = 17 * ((data[off + (x >>> 1)] >>> (4 - ((x & 1) << 2))) & 15), + al = gr == tr * 17 ? 0 : 255 + bf32[to + x] = (al << 24) | (gr << 16) | (gr << 8) | gr + } + } else if (depth == 8) { + for (var x = 0; x < w; x++) { + var gr = data[off + x], + al = gr == tr ? 0 : 255 + bf32[to + x] = (al << 24) | (gr << 16) | (gr << 8) | gr + } + } else if (depth == 16) { + for (var x = 0; x < w; x++) { + var gr = data[off + (x << 1)], + al = rs(data, off + (x << 1)) == tr ? 0 : 255 + bf32[to + x] = (al << 24) | (gr << 16) | (gr << 8) | gr + } } } } - if (depth == 2) { - for (var y = 0; y < h; y++) { - var s0 = y * bpl, - t0 = y * w - for (var i = 0; i < w; i++) { - var qi = (t0 + i) << 2, - j = (data[s0 + (i >> 2)] >> (6 - ((i & 3) << 1))) & 3, - cj = 3 * j - bf[qi] = p[cj] - bf[qi + 1] = p[cj + 1] - bf[qi + 2] = p[cj + 2] - bf[qi + 3] = j < tl ? ap[j] : 255 + //console.log(Date.now()-time); + return bf + } + + UPNG.decode = function (buff) { + var data = new Uint8Array(buff), + offset = 8, + bin = UPNG._bin, + rUs = bin.readUshort, + rUi = bin.readUint + var out = { tabs: {}, frames: [] } + var dd = new Uint8Array(data.length), + doff = 0 // put all IDAT data into it + var fd, + foff = 0 // frames + var text, keyw, bfr + + var mgck = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a] + for (var i = 0; i < 8; i++) if (data[i] != mgck[i]) throw new Error('The input is not a PNG file!') + + while (offset < data.length) { + var len = bin.readUint(data, offset) + offset += 4 + var type = bin.readASCII(data, offset, 4) + offset += 4 + //console.log(type,len); + + if (type == 'IHDR') { + UPNG.decode._IHDR(data, offset, out) + } else if (type == 'CgBI') { + out.tabs[type] = data.slice(offset, offset + 4) + } else if (type == 'IDAT') { + for (var i = 0; i < len; i++) dd[doff + i] = data[offset + i] + doff += len + } else if (type == 'acTL') { + out.tabs[type] = { num_frames: rUi(data, offset), num_plays: rUi(data, offset + 4) } + fd = new Uint8Array(data.length) + } else if (type == 'fcTL') { + if (foff != 0) { + var fr = out.frames[out.frames.length - 1] + fr.data = UPNG.decode._decompress(out, fd.slice(0, foff), fr.rect.width, fr.rect.height) + foff = 0 } - } - } - if (depth == 4) { - for (var y = 0; y < h; y++) { - var s0 = y * bpl, - t0 = y * w - for (var i = 0; i < w; i++) { - var qi = (t0 + i) << 2, - j = (data[s0 + (i >> 1)] >> (4 - ((i & 1) << 2))) & 15, - cj = 3 * j - bf[qi] = p[cj] - bf[qi + 1] = p[cj + 1] - bf[qi + 2] = p[cj + 2] - bf[qi + 3] = j < tl ? ap[j] : 255 + var rct = { + x: rUi(data, offset + 12), + y: rUi(data, offset + 16), + width: rUi(data, offset + 4), + height: rUi(data, offset + 8), + } + var del = rUs(data, offset + 22) + del = rUs(data, offset + 20) / (del == 0 ? 100 : del) + var frm = { rect: rct, delay: Math.round(del * 1000), dispose: data[offset + 24], blend: data[offset + 25] } + //console.log(frm); + out.frames.push(frm) + } else if (type == 'fdAT') { + for (var i = 0; i < len - 4; i++) fd[foff + i] = data[offset + i + 4] + foff += len - 4 + } else if (type == 'pHYs') { + out.tabs[type] = [bin.readUint(data, offset), bin.readUint(data, offset + 4), data[offset + 8]] + } else if (type == 'cHRM') { + out.tabs[type] = [] + for (var i = 0; i < 8; i++) out.tabs[type].push(bin.readUint(data, offset + i * 4)) + } else if (type == 'tEXt' || type == 'zTXt') { + if (out.tabs[type] == null) out.tabs[type] = {} + var nz = bin.nextZero(data, offset) + keyw = bin.readASCII(data, offset, nz - offset) + var tl = offset + len - nz - 1 + if (type == 'tEXt') { + text = bin.readASCII(data, nz + 1, tl) + } else { + bfr = UPNG.decode._inflate(data.slice(nz + 2, nz + 2 + tl)) + text = bin.readUTF8(bfr, 0, bfr.length) } - } - } - if (depth == 8) { - for (var i = 0; i < area; i++) { - var qi = i << 2, - j = data[i], - cj = 3 * j - bf[qi] = p[cj] - bf[qi + 1] = p[cj + 1] - bf[qi + 2] = p[cj + 2] - bf[qi + 3] = j < tl ? ap[j] : 255 - } - } - } else if (ctype == 4) { - // gray + alpha - - if (depth == 8) { - for (var i = 0; i < area; i++) { - var qi = i << 2, - di = i << 1, - gr = data[di] - bf[qi] = gr - bf[qi + 1] = gr - bf[qi + 2] = gr - bf[qi + 3] = data[di + 1] + out.tabs[type][keyw] = text + } else if (type == 'iTXt') { + if (out.tabs[type] == null) out.tabs[type] = {} + var nz = 0, + off = offset + nz = bin.nextZero(data, off) + keyw = bin.readASCII(data, off, nz - off) + off = nz + 1 + var cflag = data[off] + off += 2 + nz = bin.nextZero(data, off) + bin.readASCII(data, off, nz - off) + off = nz + 1 + nz = bin.nextZero(data, off) + bin.readUTF8(data, off, nz - off) + off = nz + 1 + var tl = len - (off - offset) + if (cflag == 0) { + text = bin.readUTF8(data, off, tl) + } else { + bfr = UPNG.decode._inflate(data.slice(off, off + tl)) + text = bin.readUTF8(bfr, 0, bfr.length) + } + + out.tabs[type][keyw] = text + } else if (type == 'PLTE') { + out.tabs[type] = bin.readBytes(data, offset, len) + } else if (type == 'hIST') { + var pl = out.tabs['PLTE'].length / 3 + out.tabs[type] = [] + for (var i = 0; i < pl; i++) out.tabs[type].push(rUs(data, offset + i * 2)) + } else if (type == 'tRNS') { + if (out.ctype == 3) out.tabs[type] = bin.readBytes(data, offset, len) + else if (out.ctype == 0) out.tabs[type] = rUs(data, offset) + else if (out.ctype == 2) out.tabs[type] = [rUs(data, offset), rUs(data, offset + 2), rUs(data, offset + 4)] + //else console.log("tRNS for unsupported color type",out.ctype, len); + } else if (type == 'gAMA') { + out.tabs[type] = bin.readUint(data, offset) / 100000 + } else if (type == 'sRGB') { + out.tabs[type] = data[offset] + } else if (type == 'bKGD') { + if (out.ctype == 0 || out.ctype == 4) { + out.tabs[type] = [rUs(data, offset)] + } else if (out.ctype == 2 || out.ctype == 6) { + out.tabs[type] = [rUs(data, offset), rUs(data, offset + 2), rUs(data, offset + 4)] + } else if (out.ctype == 3) { + out.tabs[type] = data[offset] + } + } else if (type == 'IEND') { + break } + + //else { console.log("unknown chunk type", type, len); out.tabs[type]=data.slice(offset,offset+len); } + offset += len + bin.readUint(data, offset) + offset += 4 } - if (depth == 16) { - for (var i = 0; i < area; i++) { - var qi = i << 2, - di = i << 2, - gr = data[di] - bf[qi] = gr - bf[qi + 1] = gr - bf[qi + 2] = gr - bf[qi + 3] = data[di + 2] - } + if (foff != 0) { + var fr = out.frames[out.frames.length - 1] + fr.data = UPNG.decode._decompress(out, fd.slice(0, foff), fr.rect.width, fr.rect.height) } - } else if (ctype == 0) { - // gray - var tr = out.tabs['tRNS'] ? out.tabs['tRNS'] : -1 - for (var y = 0; y < h; y++) { - var off = y * bpl, - to = y * w - if (depth == 1) { - for (var x = 0; x < w; x++) { - var gr = 255 * ((data[off + (x >>> 3)] >>> (7 - (x & 7))) & 1), - al = gr == tr * 255 ? 0 : 255 - bf32[to + x] = (al << 24) | (gr << 16) | (gr << 8) | gr - } - } else if (depth == 2) { - for (var x = 0; x < w; x++) { - var gr = 85 * ((data[off + (x >>> 2)] >>> (6 - ((x & 3) << 1))) & 3), - al = gr == tr * 85 ? 0 : 255 - bf32[to + x] = (al << 24) | (gr << 16) | (gr << 8) | gr + out.data = UPNG.decode._decompress(out, dd, out.width, out.height) + + delete out.compress + delete out.interlace + delete out.filter + return out + } + + UPNG.decode._decompress = function (out, dd, w, h) { + var bpp = UPNG.decode._getBPP(out), + bpl = Math.ceil((w * bpp) / 8), + buff = new Uint8Array((bpl + 1 + out.interlace) * h) + if (out.tabs['CgBI']) dd = UPNG.inflateRaw(dd, buff) + else dd = UPNG.decode._inflate(dd, buff) + + if (out.interlace == 0) dd = UPNG.decode._filterZero(dd, out, 0, w, h) + else if (out.interlace == 1) dd = UPNG.decode._readInterlace(dd, out) + + return dd + } + + UPNG.decode._inflate = function (data, buff) { + var out = UPNG['inflateRaw'](new Uint8Array(data.buffer, 2, data.length - 6), buff) + return out + } + + UPNG.inflateRaw = (function () { + var H = {} + H.H = {} + H.H.N = function (N, W) { + var R = Uint8Array, + i = 0, + m = 0, + J = 0, + h = 0, + Q = 0, + X = 0, + u = 0, + w = 0, + d = 0, + v, + C + if (N[0] == 3 && N[1] == 0) return W ? W : new R(0) + var V = H.H, + n = V.b, + A = V.e, + l = V.R, + M = V.n, + I = V.A, + e = V.Z, + b = V.m, + Z = W == null + if (Z) W = new R((N.length >>> 2) << 5) + while (i == 0) { + i = n(N, d, 1) + m = n(N, d + 1, 2) + d += 3 + if (m == 0) { + if ((d & 7) != 0) d += 8 - (d & 7) + var D = (d >>> 3) + 4, + q = N[D - 4] | (N[D - 3] << 8) + if (Z) W = H.H.W(W, w + q) + W.set(new R(N.buffer, N.byteOffset + D, q), w) + d = (D + q) << 3 + w += q + continue } - } else if (depth == 4) { - for (var x = 0; x < w; x++) { - var gr = 17 * ((data[off + (x >>> 1)] >>> (4 - ((x & 1) << 2))) & 15), - al = gr == tr * 17 ? 0 : 255 - bf32[to + x] = (al << 24) | (gr << 16) | (gr << 8) | gr + + if (Z) W = H.H.W(W, w + (1 << 17)) + if (m == 1) { + v = b.J + C = b.h + X = (1 << 9) - 1 + u = (1 << 5) - 1 } - } else if (depth == 8) { - for (var x = 0; x < w; x++) { - var gr = data[off + x], - al = gr == tr ? 0 : 255 - bf32[to + x] = (al << 24) | (gr << 16) | (gr << 8) | gr + + if (m == 2) { + J = A(N, d, 5) + 257 + h = A(N, d + 5, 5) + 1 + Q = A(N, d + 10, 4) + 4 + d += 14 + var j = 1 + for (var c = 0; c < 38; c += 2) { + b.Q[c] = 0 + b.Q[c + 1] = 0 + } + + for (var c = 0; c < Q; c++) { + var K = A(N, d + c * 3, 3) + b.Q[(b.X[c] << 1) + 1] = K + if (K > j) j = K + } + + d += 3 * Q + M(b.Q, j) + I(b.Q, j, b.u) + v = b.w + C = b.d + d = l(b.u, (1 << j) - 1, J + h, N, d, b.v) + var r = V.V(b.v, 0, J, b.C) + X = (1 << r) - 1 + var S = V.V(b.v, J, h, b.D) + u = (1 << S) - 1 + M(b.C, r) + I(b.C, r, v) + M(b.D, S) + I(b.D, S, C) } - } else if (depth == 16) { - for (var x = 0; x < w; x++) { - var gr = data[off + (x << 1)], - al = rs(data, off + (x << 1)) == tr ? 0 : 255 - bf32[to + x] = (al << 24) | (gr << 16) | (gr << 8) | gr + + while (!0) { + var T = v[e(N, d) & X] + d += T & 15 + var p = T >>> 4 + if (p >>> 8 == 0) { + W[w++] = p + } else if (p == 256) { + break + } else { + var z = w + p - 254 + if (p > 264) { + var _ = b.q[p - 257] + z = w + (_ >>> 3) + A(N, d, _ & 7) + d += _ & 7 + } + + var $ = C[e(N, d) & u] + d += $ & 15 + var s = $ >>> 4, + Y = b.c[s], + a = (Y >>> 4) + n(N, d, Y & 15) + d += Y & 15 + while (w < z) { + W[w] = W[w++ - a] + W[w] = W[w++ - a] + W[w] = W[w++ - a] + W[w] = W[w++ - a] + } + + w = z + } } } + + return W.length == w ? W : W.slice(0, w) } - } - //console.log(Date.now()-time); - return bf -} + H.H.W = function (N, W) { + var R = N.length + if (W <= R) return N + var V = new Uint8Array(R << 1) + V.set(N, 0) + return V + } -UPNG.decode = function (buff) { - var data = new Uint8Array(buff), - offset = 8, - bin = UPNG._bin, - rUs = bin.readUshort, - rUi = bin.readUint - var out = { tabs: {}, frames: [] } - var dd = new Uint8Array(data.length), - doff = 0 // put all IDAT data into it - var fd, - foff = 0 // frames - var text, keyw, bfr - - var mgck = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a] - for (var i = 0; i < 8; i++) if (data[i] != mgck[i]) throw new Error('The input is not a PNG file!') - - while (offset < data.length) { - var len = bin.readUint(data, offset) - offset += 4 - var type = bin.readASCII(data, offset, 4) - offset += 4 - //console.log(type,len); - - if (type == 'IHDR') { - UPNG.decode._IHDR(data, offset, out) - } else if (type == 'CgBI') { - out.tabs[type] = data.slice(offset, offset + 4) - } else if (type == 'IDAT') { - for (var i = 0; i < len; i++) dd[doff + i] = data[offset + i] - doff += len - } else if (type == 'acTL') { - out.tabs[type] = { num_frames: rUi(data, offset), num_plays: rUi(data, offset + 4) } - fd = new Uint8Array(data.length) - } else if (type == 'fcTL') { - if (foff != 0) { - var fr = out.frames[out.frames.length - 1] - fr.data = UPNG.decode._decompress(out, fd.slice(0, foff), fr.rect.width, fr.rect.height) - foff = 0 + H.H.R = function (N, W, R, V, n, A) { + var l = H.H.e, + M = H.H.Z, + I = 0 + while (I < R) { + var e = N[M(V, n) & W] + n += e & 15 + var b = e >>> 4 + if (b <= 15) { + A[I] = b + I++ + } else { + var Z = 0, + m = 0 + if (b == 16) { + m = 3 + l(V, n, 2) + n += 2 + Z = A[I - 1] + } else if (b == 17) { + m = 3 + l(V, n, 3) + n += 3 + } else if (b == 18) { + m = 11 + l(V, n, 7) + n += 7 + } + + var J = I + m + while (I < J) { + A[I] = Z + I++ + } + } } - var rct = { - x: rUi(data, offset + 12), - y: rUi(data, offset + 16), - width: rUi(data, offset + 4), - height: rUi(data, offset + 8), + return n + } + + H.H.V = function (N, W, R, V) { + var n = 0, + A = 0, + l = V.length >>> 1 + while (A < R) { + var M = N[A + W] + V[A << 1] = 0 + V[(A << 1) + 1] = M + if (M > n) n = M + A++ } - var del = rUs(data, offset + 22) - del = rUs(data, offset + 20) / (del == 0 ? 100 : del) - var frm = { rect: rct, delay: Math.round(del * 1000), dispose: data[offset + 24], blend: data[offset + 25] } - //console.log(frm); - out.frames.push(frm) - } else if (type == 'fdAT') { - for (var i = 0; i < len - 4; i++) fd[foff + i] = data[offset + i + 4] - foff += len - 4 - } else if (type == 'pHYs') { - out.tabs[type] = [bin.readUint(data, offset), bin.readUint(data, offset + 4), data[offset + 8]] - } else if (type == 'cHRM') { - out.tabs[type] = [] - for (var i = 0; i < 8; i++) out.tabs[type].push(bin.readUint(data, offset + i * 4)) - } else if (type == 'tEXt' || type == 'zTXt') { - if (out.tabs[type] == null) out.tabs[type] = {} - var nz = bin.nextZero(data, offset) - keyw = bin.readASCII(data, offset, nz - offset) - var tl = offset + len - nz - 1 - if (type == 'tEXt') { - text = bin.readASCII(data, nz + 1, tl) - } else { - bfr = UPNG.decode._inflate(data.slice(nz + 2, nz + 2 + tl)) - text = bin.readUTF8(bfr, 0, bfr.length) + + while (A < l) { + V[A << 1] = 0 + V[(A << 1) + 1] = 0 + A++ } - out.tabs[type][keyw] = text - } else if (type == 'iTXt') { - if (out.tabs[type] == null) out.tabs[type] = {} - var nz = 0, - off = offset - nz = bin.nextZero(data, off) - keyw = bin.readASCII(data, off, nz - off) - off = nz + 1 - var cflag = data[off] - off += 2 - nz = bin.nextZero(data, off) - bin.readASCII(data, off, nz - off) - off = nz + 1 - nz = bin.nextZero(data, off) - bin.readUTF8(data, off, nz - off) - off = nz + 1 - var tl = len - (off - offset) - if (cflag == 0) { - text = bin.readUTF8(data, off, tl) - } else { - bfr = UPNG.decode._inflate(data.slice(off, off + tl)) - text = bin.readUTF8(bfr, 0, bfr.length) + return n + } + + H.H.n = function (N, W) { + var R = H.H.m, + V = N.length, + n, + A, + l, + M, + I, + e = R.j + for (var M = 0; M <= W; M++) e[M] = 0 + for (M = 1; M < V; M += 2) e[N[M]]++ + var b = R.K + n = 0 + e[0] = 0 + for (A = 1; A <= W; A++) { + n = (n + e[A - 1]) << 1 + b[A] = n } - out.tabs[type][keyw] = text - } else if (type == 'PLTE') { - out.tabs[type] = bin.readBytes(data, offset, len) - } else if (type == 'hIST') { - var pl = out.tabs['PLTE'].length / 3 - out.tabs[type] = [] - for (var i = 0; i < pl; i++) out.tabs[type].push(rUs(data, offset + i * 2)) - } else if (type == 'tRNS') { - if (out.ctype == 3) out.tabs[type] = bin.readBytes(data, offset, len) - else if (out.ctype == 0) out.tabs[type] = rUs(data, offset) - else if (out.ctype == 2) out.tabs[type] = [rUs(data, offset), rUs(data, offset + 2), rUs(data, offset + 4)] - //else console.log("tRNS for unsupported color type",out.ctype, len); - } else if (type == 'gAMA') { - out.tabs[type] = bin.readUint(data, offset) / 100000 - } else if (type == 'sRGB') { - out.tabs[type] = data[offset] - } else if (type == 'bKGD') { - if (out.ctype == 0 || out.ctype == 4) { - out.tabs[type] = [rUs(data, offset)] - } else if (out.ctype == 2 || out.ctype == 6) { - out.tabs[type] = [rUs(data, offset), rUs(data, offset + 2), rUs(data, offset + 4)] - } else if (out.ctype == 3) { - out.tabs[type] = data[offset] + for (l = 0; l < V; l += 2) { + I = N[l + 1] + if (I != 0) { + N[l] = b[I] + b[I]++ + } } - } else if (type == 'IEND') { - break } - //else { console.log("unknown chunk type", type, len); out.tabs[type]=data.slice(offset,offset+len); } - offset += len - bin.readUint(data, offset) - offset += 4 - } + H.H.A = function (N, W, R) { + var V = N.length, + n = H.H.m, + A = n.r + for (var l = 0; l < V; l += 2) { + if (N[l + 1] != 0) { + var M = l >> 1, + I = N[l + 1], + e = (M << 4) | I, + b = W - I, + Z = N[l] << b, + m = Z + (1 << b) + while (Z != m) { + var J = A[Z] >>> (15 - W) + R[J] = e + Z++ + } + } + } + } - if (foff != 0) { - var fr = out.frames[out.frames.length - 1] - fr.data = UPNG.decode._decompress(out, fd.slice(0, foff), fr.rect.width, fr.rect.height) - } + H.H.l = function (N, W) { + var R = H.H.m.r, + V = 15 - W + for (var n = 0; n < N.length; n += 2) { + var A = N[n] << (W - N[n + 1]) + N[n] = R[A] >>> V + } + } - out.data = UPNG.decode._decompress(out, dd, out.width, out.height) + H.H.M = function (N, W, R) { + R = R << (W & 7) + var V = W >>> 3 + N[V] |= R + N[V + 1] |= R >>> 8 + } - delete out.compress - delete out.interlace - delete out.filter - return out -} + H.H.I = function (N, W, R) { + R = R << (W & 7) + var V = W >>> 3 + N[V] |= R + N[V + 1] |= R >>> 8 + N[V + 2] |= R >>> 16 + } -UPNG.decode._decompress = function (out, dd, w, h) { - var bpp = UPNG.decode._getBPP(out), - bpl = Math.ceil((w * bpp) / 8), - buff = new Uint8Array((bpl + 1 + out.interlace) * h) - if (out.tabs['CgBI']) dd = UPNG.inflateRaw(dd, buff) - else dd = UPNG.decode._inflate(dd, buff) + H.H.e = function (N, W, R) { + return ((N[W >>> 3] | (N[(W >>> 3) + 1] << 8)) >>> (W & 7)) & ((1 << R) - 1) + } - if (out.interlace == 0) dd = UPNG.decode._filterZero(dd, out, 0, w, h) - else if (out.interlace == 1) dd = UPNG.decode._readInterlace(dd, out) + H.H.b = function (N, W, R) { + return ((N[W >>> 3] | (N[(W >>> 3) + 1] << 8) | (N[(W >>> 3) + 2] << 16)) >>> (W & 7)) & ((1 << R) - 1) + } - return dd -} + H.H.Z = function (N, W) { + return (N[W >>> 3] | (N[(W >>> 3) + 1] << 8) | (N[(W >>> 3) + 2] << 16)) >>> (W & 7) + } -UPNG.decode._inflate = function (data, buff) { - var out = UPNG['inflateRaw'](new Uint8Array(data.buffer, 2, data.length - 6), buff) - return out -} + H.H.i = function (N, W) { + return (N[W >>> 3] | (N[(W >>> 3) + 1] << 8) | (N[(W >>> 3) + 2] << 16) | (N[(W >>> 3) + 3] << 24)) >>> (W & 7) + } -UPNG.inflateRaw = (function () { - var H = {} - H.H = {} - H.H.N = function (N, W) { - var R = Uint8Array, - i = 0, - m = 0, - J = 0, - h = 0, - Q = 0, - X = 0, - u = 0, - w = 0, - d = 0, - v, - C - if (N[0] == 3 && N[1] == 0) return W ? W : new R(0) - var V = H.H, - n = V.b, - A = V.e, - l = V.R, - M = V.n, - I = V.A, - e = V.Z, - b = V.m, - Z = W == null - if (Z) W = new R((N.length >>> 2) << 5) - while (i == 0) { - i = n(N, d, 1) - m = n(N, d + 1, 2) - d += 3 - if (m == 0) { - if ((d & 7) != 0) d += 8 - (d & 7) - var D = (d >>> 3) + 4, - q = N[D - 4] | (N[D - 3] << 8) - if (Z) W = H.H.W(W, w + q) - W.set(new R(N.buffer, N.byteOffset + D, q), w) - d = (D + q) << 3 - w += q - continue + H.H.m = (function () { + var N = Uint16Array, + W = Uint32Array + return { + K: new N(16), + j: new N(16), + X: [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15], + S: [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 13, + 15, + 17, + 19, + 23, + 27, + 31, + 35, + 43, + 51, + 59, + 67, + 83, + 99, + 115, + 131, + 163, + 195, + 227, + 258, + 999, + 999, + 999, + ], + T: [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, 0, 0, 0], + q: new N(32), + p: [ + 1, + 2, + 3, + 4, + 5, + 7, + 9, + 13, + 17, + 25, + 33, + 49, + 65, + 97, + 129, + 193, + 257, + 385, + 513, + 769, + 1025, + 1537, + 2049, + 3073, + 4097, + 6145, + 8193, + 12289, + 16385, + 24577, + 65535, + 65535, + ], + z: [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, 0, 0], + c: new W(32), + J: new N(512), + _: [], + h: new N(32), + $: [], + w: new N(32768), + C: [], + v: [], + d: new N(32768), + D: [], + u: new N(512), + Q: [], + r: new N(1 << 15), + s: new W(286), + Y: new W(30), + a: new W(19), + t: new W(15e3), + k: new N(1 << 16), + g: new N(1 << 15), + } + })() + ;(function () { + var N = H.H.m, + W = 1 << 15 + for (var R = 0; R < W; R++) { + var V = R + V = ((V & 2863311530) >>> 1) | ((V & 1431655765) << 1) + V = ((V & 3435973836) >>> 2) | ((V & 858993459) << 2) + V = ((V & 4042322160) >>> 4) | ((V & 252645135) << 4) + V = ((V & 4278255360) >>> 8) | ((V & 16711935) << 8) + N.r[R] = ((V >>> 16) | (V << 16)) >>> 17 } - if (Z) W = H.H.W(W, w + (1 << 17)) - if (m == 1) { - v = b.J - C = b.h - X = (1 << 9) - 1 - u = (1 << 5) - 1 + function n(A, l, M) { + while (l-- != 0) A.push(0, M) } - if (m == 2) { - J = A(N, d, 5) + 257 - h = A(N, d + 5, 5) + 1 - Q = A(N, d + 10, 4) + 4 - d += 14 - var j = 1 - for (var c = 0; c < 38; c += 2) { - b.Q[c] = 0 - b.Q[c + 1] = 0 - } + for (var R = 0; R < 32; R++) { + N.q[R] = (N.S[R] << 3) | N.T[R] + N.c[R] = (N.p[R] << 4) | N.z[R] + } - for (var c = 0; c < Q; c++) { - var K = A(N, d + c * 3, 3) - b.Q[(b.X[c] << 1) + 1] = K - if (K > j) j = K - } + n(N._, 144, 8) + n(N._, 255 - 143, 9) + n(N._, 279 - 255, 7) + n(N._, 287 - 279, 8) + H.H.n(N._, 9) + H.H.A(N._, 9, N.J) + H.H.l(N._, 9) + n(N.$, 32, 5) + H.H.n(N.$, 5) + H.H.A(N.$, 5, N.h) + H.H.l(N.$, 5) + n(N.Q, 19, 0) + n(N.C, 286, 0) + n(N.D, 30, 0) + n(N.v, 320, 0) + })() + + return H.H.N + })() - d += 3 * Q - M(b.Q, j) - I(b.Q, j, b.u) - v = b.w - C = b.d - d = l(b.u, (1 << j) - 1, J + h, N, d, b.v) - var r = V.V(b.v, 0, J, b.C) - X = (1 << r) - 1 - var S = V.V(b.v, J, h, b.D) - u = (1 << S) - 1 - M(b.C, r) - I(b.C, r, v) - M(b.D, S) - I(b.D, S, C) + UPNG.decode._readInterlace = function (data, out) { + var w = out.width, + h = out.height + var bpp = UPNG.decode._getBPP(out), + cbpp = bpp >> 3, + bpl = Math.ceil((w * bpp) / 8) + var img = new Uint8Array(h * bpl) + var di = 0 + + var starting_row = [0, 0, 4, 0, 2, 0, 1] + var starting_col = [0, 4, 0, 2, 0, 1, 0] + var row_increment = [8, 8, 8, 4, 4, 2, 2] + var col_increment = [8, 8, 4, 4, 2, 2, 1] + + var pass = 0 + while (pass < 7) { + var ri = row_increment[pass], + ci = col_increment[pass] + var sw = 0, + sh = 0 + var cr = starting_row[pass] + while (cr < h) { + cr += ri + sh++ } - while (!0) { - var T = v[e(N, d) & X] - d += T & 15 - var p = T >>> 4 - if (p >>> 8 == 0) { - W[w++] = p - } else if (p == 256) { - break - } else { - var z = w + p - 254 - if (p > 264) { - var _ = b.q[p - 257] - z = w + (_ >>> 3) + A(N, d, _ & 7) - d += _ & 7 + var cc = starting_col[pass] + while (cc < w) { + cc += ci + sw++ + } + + var bpll = Math.ceil((sw * bpp) / 8) + UPNG.decode._filterZero(data, out, di, sw, sh) + + var y = 0, + row = starting_row[pass] + var val + + while (row < h) { + var col = starting_col[pass] + var cdi = (di + y * bpll) << 3 + + while (col < w) { + if (bpp == 1) { + val = data[cdi >> 3] + val = (val >> (7 - (cdi & 7))) & 1 + img[row * bpl + (col >> 3)] |= val << (7 - ((col & 7) << 0)) + } + + if (bpp == 2) { + val = data[cdi >> 3] + val = (val >> (6 - (cdi & 7))) & 3 + img[row * bpl + (col >> 2)] |= val << (6 - ((col & 3) << 1)) + } + + if (bpp == 4) { + val = data[cdi >> 3] + val = (val >> (4 - (cdi & 7))) & 15 + img[row * bpl + (col >> 1)] |= val << (4 - ((col & 1) << 2)) } - var $ = C[e(N, d) & u] - d += $ & 15 - var s = $ >>> 4, - Y = b.c[s], - a = (Y >>> 4) + n(N, d, Y & 15) - d += Y & 15 - while (w < z) { - W[w] = W[w++ - a] - W[w] = W[w++ - a] - W[w] = W[w++ - a] - W[w] = W[w++ - a] + if (bpp >= 8) { + var ii = row * bpl + col * cbpp + for (var j = 0; j < cbpp; j++) img[ii + j] = data[(cdi >> 3) + j] } - w = z + cdi += bpp + col += ci } + + y++ + row += ri } + + if (sw * sh != 0) di += sh * (1 + bpll) + pass = pass + 1 } - return W.length == w ? W : W.slice(0, w) + return img } - H.H.W = function (N, W) { - var R = N.length - if (W <= R) return N - var V = new Uint8Array(R << 1) - V.set(N, 0) - return V + UPNG.decode._getBPP = function (out) { + var noc = [1, null, 3, 1, 2, null, 4][out.ctype] + return noc * out.depth } - H.H.R = function (N, W, R, V, n, A) { - var l = H.H.e, - M = H.H.Z, - I = 0 - while (I < R) { - var e = N[M(V, n) & W] - n += e & 15 - var b = e >>> 4 - if (b <= 15) { - A[I] = b - I++ - } else { - var Z = 0, - m = 0 - if (b == 16) { - m = 3 + l(V, n, 2) - n += 2 - Z = A[I - 1] - } else if (b == 17) { - m = 3 + l(V, n, 3) - n += 3 - } else if (b == 18) { - m = 11 + l(V, n, 7) - n += 7 - } + UPNG.decode._filterZero = function (data, out, off, w, h) { + var bpp = UPNG.decode._getBPP(out), + bpl = Math.ceil((w * bpp) / 8), + paeth = UPNG.decode._paeth + bpp = Math.ceil(bpp / 8) - var J = I + m - while (I < J) { - A[I] = Z - I++ + var i, + di, + type = data[off], + x = 0 + + if (type > 1) data[off] = [0, 0, 1][type - 2] + if (type == 3) for (x = bpp; x < bpl; x++) data[x + 1] = (data[x + 1] + (data[x + 1 - bpp] >>> 1)) & 255 + + for (var y = 0; y < h; y++) { + i = off + y * bpl + di = i + y + 1 + type = data[di - 1] + x = 0 + + if (type == 0) { + for (; x < bpl; x++) data[i + x] = data[di + x] + } else if (type == 1) { + for (; x < bpp; x++) data[i + x] = data[di + x] + for (; x < bpl; x++) data[i + x] = data[di + x] + data[i + x - bpp] + } else if (type == 2) { + for (; x < bpl; x++) data[i + x] = data[di + x] + data[i + x - bpl] + } else if (type == 3) { + for (; x < bpp; x++) data[i + x] = data[di + x] + (data[i + x - bpl] >>> 1) + for (; x < bpl; x++) data[i + x] = data[di + x] + ((data[i + x - bpl] + data[i + x - bpp]) >>> 1) + } else { + for (; x < bpp; x++) data[i + x] = data[di + x] + paeth(0, data[i + x - bpl], 0) + for (; x < bpl; x++) { + data[i + x] = data[di + x] + paeth(data[i + x - bpp], data[i + x - bpl], data[i + x - bpp - bpl]) } } } - return n + return data } - H.H.V = function (N, W, R, V) { - var n = 0, - A = 0, - l = V.length >>> 1 - while (A < R) { - var M = N[A + W] - V[A << 1] = 0 - V[(A << 1) + 1] = M - if (M > n) n = M - A++ - } - - while (A < l) { - V[A << 1] = 0 - V[(A << 1) + 1] = 0 - A++ - } - - return n + UPNG.decode._paeth = function (a, b, c) { + var p = a + b - c, + pa = p - a, + pb = p - b, + pc = p - c + if (pa * pa <= pb * pb && pa * pa <= pc * pc) return a + else if (pb * pb <= pc * pc) return b + return c } - H.H.n = function (N, W) { - var R = H.H.m, - V = N.length, - n, - A, - l, - M, - I, - e = R.j - for (var M = 0; M <= W; M++) e[M] = 0 - for (M = 1; M < V; M += 2) e[N[M]]++ - var b = R.K - n = 0 - e[0] = 0 - for (A = 1; A <= W; A++) { - n = (n + e[A - 1]) << 1 - b[A] = n - } + UPNG.decode._IHDR = function (data, offset, out) { + var bin = UPNG._bin + out.width = bin.readUint(data, offset) + offset += 4 + out.height = bin.readUint(data, offset) + offset += 4 + out.depth = data[offset] + offset++ + out.ctype = data[offset] + offset++ + out.compress = data[offset] + offset++ + out.filter = data[offset] + offset++ + out.interlace = data[offset] + offset++ + } - for (l = 0; l < V; l += 2) { - I = N[l + 1] - if (I != 0) { - N[l] = b[I] - b[I]++ + UPNG._bin = { + nextZero: function (data, p) { + while (data[p] != 0) p++ + return p + }, + readUshort: function (buff, p) { + return (buff[p] << 8) | buff[p + 1] + }, + writeUshort: function (buff, p, n) { + buff[p] = (n >> 8) & 255 + buff[p + 1] = n & 255 + }, + readUint: function (buff, p) { + return buff[p] * (256 * 256 * 256) + ((buff[p + 1] << 16) | (buff[p + 2] << 8) | buff[p + 3]) + }, + writeUint: function (buff, p, n) { + buff[p] = (n >> 24) & 255 + buff[p + 1] = (n >> 16) & 255 + buff[p + 2] = (n >> 8) & 255 + buff[p + 3] = n & 255 + }, + readASCII: function (buff, p, l) { + var s = '' + for (var i = 0; i < l; i++) s += String.fromCharCode(buff[p + i]) + return s + }, + writeASCII: function (data, p, s) { + for (var i = 0; i < s.length; i++) data[p + i] = s.charCodeAt(i) + }, + readBytes: function (buff, p, l) { + var arr = [] + for (var i = 0; i < l; i++) arr.push(buff[p + i]) + return arr + }, + pad: function (n) { + return n.length < 2 ? '0' + n : n + }, + readUTF8: function (buff, p, l) { + var s = '', + ns + for (var i = 0; i < l; i++) s += '%' + UPNG._bin.pad(buff[p + i].toString(16)) + try { + ns = decodeURIComponent(s) + } catch (e) { + return UPNG._bin.readASCII(buff, p, l) } - } + + return ns + }, } + UPNG._copyTile = function (sb, sw, sh, tb, tw, th, xoff, yoff, mode) { + var w = Math.min(sw, tw), + h = Math.min(sh, th) + var si = 0, + ti = 0 + for (var y = 0; y < h; y++) { + for (var x = 0; x < w; x++) { + if (xoff >= 0 && yoff >= 0) { + si = (y * sw + x) << 2 + ti = ((yoff + y) * tw + xoff + x) << 2 + } else { + si = ((-yoff + y) * sw - xoff + x) << 2 + ti = (y * tw + x) << 2 + } - H.H.A = function (N, W, R) { - var V = N.length, - n = H.H.m, - A = n.r - for (var l = 0; l < V; l += 2) { - if (N[l + 1] != 0) { - var M = l >> 1, - I = N[l + 1], - e = (M << 4) | I, - b = W - I, - Z = N[l] << b, - m = Z + (1 << b) - while (Z != m) { - var J = A[Z] >>> (15 - W) - R[J] = e - Z++ + if (mode == 0) { + tb[ti] = sb[si] + tb[ti + 1] = sb[si + 1] + tb[ti + 2] = sb[si + 2] + tb[ti + 3] = sb[si + 3] + } else if (mode == 1) { + var fa = sb[si + 3] * (1 / 255), + fr = sb[si] * fa, + fg = sb[si + 1] * fa, + fb = sb[si + 2] * fa + var ba = tb[ti + 3] * (1 / 255), + br = tb[ti] * ba, + bg = tb[ti + 1] * ba, + bb = tb[ti + 2] * ba + + var ifa = 1 - fa, + oa = fa + ba * ifa, + ioa = oa == 0 ? 0 : 1 / oa + tb[ti + 3] = 255 * oa + tb[ti + 0] = (fr + br * ifa) * ioa + tb[ti + 1] = (fg + bg * ifa) * ioa + tb[ti + 2] = (fb + bb * ifa) * ioa + } else if (mode == 2) { + // copy only differences, otherwise zero + + var fa = sb[si + 3], + fr = sb[si], + fg = sb[si + 1], + fb = sb[si + 2] + var ba = tb[ti + 3], + br = tb[ti], + bg = tb[ti + 1], + bb = tb[ti + 2] + if (fa == ba && fr == br && fg == bg && fb == bb) { + tb[ti] = 0 + tb[ti + 1] = 0 + tb[ti + 2] = 0 + tb[ti + 3] = 0 + } else { + tb[ti] = fr + tb[ti + 1] = fg + tb[ti + 2] = fb + tb[ti + 3] = fa + } + } else if (mode == 3) { + // check if can be blended + + var fa = sb[si + 3], + fr = sb[si], + fg = sb[si + 1], + fb = sb[si + 2] + var ba = tb[ti + 3], + br = tb[ti], + bg = tb[ti + 1], + bb = tb[ti + 2] + if (fa == ba && fr == br && fg == bg && fb == bb) continue + //if(fa!=255 && ba!=0) return false; + if (fa < 220 && ba > 20) return false } } } - } - H.H.l = function (N, W) { - var R = H.H.m.r, - V = 15 - W - for (var n = 0; n < N.length; n += 2) { - var A = N[n] << (W - N[n + 1]) - N[n] = R[A] >>> V - } + return true } +} - H.H.M = function (N, W, R) { - R = R << (W & 7) - var V = W >>> 3 - N[V] |= R - N[V + 1] |= R >>> 8 - } +class RGBMLoader extends DataTextureLoader { + constructor(manager) { + super(manager) - H.H.I = function (N, W, R) { - R = R << (W & 7) - var V = W >>> 3 - N[V] |= R - N[V + 1] |= R >>> 8 - N[V + 2] |= R >>> 16 + this.type = HalfFloatType + this.maxRange = 7 // more information about this property at https://iwasbeingirony.blogspot.com/2010/06/difference-between-rgbm-and-rgbd.html } - H.H.e = function (N, W, R) { - return ((N[W >>> 3] | (N[(W >>> 3) + 1] << 8)) >>> (W & 7)) & ((1 << R) - 1) + setDataType(value) { + this.type = value + return this } - H.H.b = function (N, W, R) { - return ((N[W >>> 3] | (N[(W >>> 3) + 1] << 8) | (N[(W >>> 3) + 2] << 16)) >>> (W & 7)) & ((1 << R) - 1) + setMaxRange(value) { + this.maxRange = value + return this } - H.H.Z = function (N, W) { - return (N[W >>> 3] | (N[(W >>> 3) + 1] << 8) | (N[(W >>> 3) + 2] << 16)) >>> (W & 7) - } + loadCubemap(urls, onLoad, onProgress, onError) { + const texture = new CubeTexture() - H.H.i = function (N, W) { - return (N[W >>> 3] | (N[(W >>> 3) + 1] << 8) | (N[(W >>> 3) + 2] << 16) | (N[(W >>> 3) + 3] << 24)) >>> (W & 7) - } + let loaded = 0 - H.H.m = (function () { - var N = Uint16Array, - W = Uint32Array - return { - K: new N(16), - j: new N(16), - X: [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15], - S: [ - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 13, - 15, - 17, - 19, - 23, - 27, - 31, - 35, - 43, - 51, - 59, - 67, - 83, - 99, - 115, - 131, - 163, - 195, - 227, - 258, - 999, - 999, - 999, - ], - T: [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, 0, 0, 0], - q: new N(32), - p: [ - 1, - 2, - 3, - 4, - 5, - 7, - 9, - 13, - 17, - 25, - 33, - 49, - 65, - 97, - 129, - 193, - 257, - 385, - 513, - 769, - 1025, - 1537, - 2049, - 3073, - 4097, - 6145, - 8193, - 12289, - 16385, - 24577, - 65535, - 65535, - ], - z: [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, 0, 0], - c: new W(32), - J: new N(512), - _: [], - h: new N(32), - $: [], - w: new N(32768), - C: [], - v: [], - d: new N(32768), - D: [], - u: new N(512), - Q: [], - r: new N(1 << 15), - s: new W(286), - Y: new W(30), - a: new W(19), - t: new W(15e3), - k: new N(1 << 16), - g: new N(1 << 15), - } - })() - ;(function () { - var N = H.H.m, - W = 1 << 15 - for (var R = 0; R < W; R++) { - var V = R - V = ((V & 2863311530) >>> 1) | ((V & 1431655765) << 1) - V = ((V & 3435973836) >>> 2) | ((V & 858993459) << 2) - V = ((V & 4042322160) >>> 4) | ((V & 252645135) << 4) - V = ((V & 4278255360) >>> 8) | ((V & 16711935) << 8) - N.r[R] = ((V >>> 16) | (V << 16)) >>> 17 - } + const scope = this - function n(A, l, M) { - while (l-- != 0) A.push(0, M) - } + function loadTexture(i) { + scope.load( + urls[i], + function (image) { + texture.images[i] = image - for (var R = 0; R < 32; R++) { - N.q[R] = (N.S[R] << 3) | N.T[R] - N.c[R] = (N.p[R] << 4) | N.z[R] - } + loaded++ - n(N._, 144, 8) - n(N._, 255 - 143, 9) - n(N._, 279 - 255, 7) - n(N._, 287 - 279, 8) - H.H.n(N._, 9) - H.H.A(N._, 9, N.J) - H.H.l(N._, 9) - n(N.$, 32, 5) - H.H.n(N.$, 5) - H.H.A(N.$, 5, N.h) - H.H.l(N.$, 5) - n(N.Q, 19, 0) - n(N.C, 286, 0) - n(N.D, 30, 0) - n(N.v, 320, 0) - })() + if (loaded === 6) { + texture.needsUpdate = true - return H.H.N -})() - -UPNG.decode._readInterlace = function (data, out) { - var w = out.width, - h = out.height - var bpp = UPNG.decode._getBPP(out), - cbpp = bpp >> 3, - bpl = Math.ceil((w * bpp) / 8) - var img = new Uint8Array(h * bpl) - var di = 0 - - var starting_row = [0, 0, 4, 0, 2, 0, 1] - var starting_col = [0, 4, 0, 2, 0, 1, 0] - var row_increment = [8, 8, 8, 4, 4, 2, 2] - var col_increment = [8, 8, 4, 4, 2, 2, 1] - - var pass = 0 - while (pass < 7) { - var ri = row_increment[pass], - ci = col_increment[pass] - var sw = 0, - sh = 0 - var cr = starting_row[pass] - while (cr < h) { - cr += ri - sh++ + if (onLoad) onLoad(texture) + } + }, + undefined, + onError, + ) } - var cc = starting_col[pass] - while (cc < w) { - cc += ci - sw++ + for (let i = 0; i < urls.length; ++i) { + loadTexture(i) } - var bpll = Math.ceil((sw * bpp) / 8) - UPNG.decode._filterZero(data, out, di, sw, sh) - - var y = 0, - row = starting_row[pass] - var val - - while (row < h) { - var col = starting_col[pass] - var cdi = (di + y * bpll) << 3 - - while (col < w) { - if (bpp == 1) { - val = data[cdi >> 3] - val = (val >> (7 - (cdi & 7))) & 1 - img[row * bpl + (col >> 3)] |= val << (7 - ((col & 7) << 0)) - } - - if (bpp == 2) { - val = data[cdi >> 3] - val = (val >> (6 - (cdi & 7))) & 3 - img[row * bpl + (col >> 2)] |= val << (6 - ((col & 3) << 1)) - } - - if (bpp == 4) { - val = data[cdi >> 3] - val = (val >> (4 - (cdi & 7))) & 15 - img[row * bpl + (col >> 1)] |= val << (4 - ((col & 1) << 2)) - } - - if (bpp >= 8) { - var ii = row * bpl + col * cbpp - for (var j = 0; j < cbpp; j++) img[ii + j] = data[(cdi >> 3) + j] - } - - cdi += bpp - col += ci - } - - y++ - row += ri - } + texture.type = this.type + texture.format = RGBAFormat + texture.minFilter = LinearFilter + texture.generateMipmaps = false - if (sw * sh != 0) di += sh * (1 + bpll) - pass = pass + 1 + return texture } - return img -} - -UPNG.decode._getBPP = function (out) { - var noc = [1, null, 3, 1, 2, null, 4][out.ctype] - return noc * out.depth -} - -UPNG.decode._filterZero = function (data, out, off, w, h) { - var bpp = UPNG.decode._getBPP(out), - bpl = Math.ceil((w * bpp) / 8), - paeth = UPNG.decode._paeth - bpp = Math.ceil(bpp / 8) - - var i, - di, - type = data[off], - x = 0 - - if (type > 1) data[off] = [0, 0, 1][type - 2] - if (type == 3) for (x = bpp; x < bpl; x++) data[x + 1] = (data[x + 1] + (data[x + 1 - bpp] >>> 1)) & 255 - - for (var y = 0; y < h; y++) { - i = off + y * bpl - di = i + y + 1 - type = data[di - 1] - x = 0 - - if (type == 0) { - for (; x < bpl; x++) data[i + x] = data[di + x] - } else if (type == 1) { - for (; x < bpp; x++) data[i + x] = data[di + x] - for (; x < bpl; x++) data[i + x] = data[di + x] + data[i + x - bpp] - } else if (type == 2) { - for (; x < bpl; x++) data[i + x] = data[di + x] + data[i + x - bpl] - } else if (type == 3) { - for (; x < bpp; x++) data[i + x] = data[di + x] + (data[i + x - bpl] >>> 1) - for (; x < bpl; x++) data[i + x] = data[di + x] + ((data[i + x - bpl] + data[i + x - bpp]) >>> 1) - } else { - for (; x < bpp; x++) data[i + x] = data[di + x] + paeth(0, data[i + x - bpl], 0) - for (; x < bpl; x++) { - data[i + x] = data[di + x] + paeth(data[i + x - bpp], data[i + x - bpl], data[i + x - bpp - bpl]) - } - } - } + parse(buffer) { + init() + const img = UPNG.decode(buffer) + const rgba = UPNG.toRGBA8(img)[0] - return data -} + const data = new Uint8Array(rgba) + const size = img.width * img.height * 4 -UPNG.decode._paeth = function (a, b, c) { - var p = a + b - c, - pa = p - a, - pb = p - b, - pc = p - c - if (pa * pa <= pb * pb && pa * pa <= pc * pc) return a - else if (pb * pb <= pc * pc) return b - return c -} + const output = this.type === HalfFloatType ? new Uint16Array(size) : new Float32Array(size) -UPNG.decode._IHDR = function (data, offset, out) { - var bin = UPNG._bin - out.width = bin.readUint(data, offset) - offset += 4 - out.height = bin.readUint(data, offset) - offset += 4 - out.depth = data[offset] - offset++ - out.ctype = data[offset] - offset++ - out.compress = data[offset] - offset++ - out.filter = data[offset] - offset++ - out.interlace = data[offset] - offset++ -} + // decode RGBM -UPNG._bin = { - nextZero: function (data, p) { - while (data[p] != 0) p++ - return p - }, - readUshort: function (buff, p) { - return (buff[p] << 8) | buff[p + 1] - }, - writeUshort: function (buff, p, n) { - buff[p] = (n >> 8) & 255 - buff[p + 1] = n & 255 - }, - readUint: function (buff, p) { - return buff[p] * (256 * 256 * 256) + ((buff[p + 1] << 16) | (buff[p + 2] << 8) | buff[p + 3]) - }, - writeUint: function (buff, p, n) { - buff[p] = (n >> 24) & 255 - buff[p + 1] = (n >> 16) & 255 - buff[p + 2] = (n >> 8) & 255 - buff[p + 3] = n & 255 - }, - readASCII: function (buff, p, l) { - var s = '' - for (var i = 0; i < l; i++) s += String.fromCharCode(buff[p + i]) - return s - }, - writeASCII: function (data, p, s) { - for (var i = 0; i < s.length; i++) data[p + i] = s.charCodeAt(i) - }, - readBytes: function (buff, p, l) { - var arr = [] - for (var i = 0; i < l; i++) arr.push(buff[p + i]) - return arr - }, - pad: function (n) { - return n.length < 2 ? '0' + n : n - }, - readUTF8: function (buff, p, l) { - var s = '', - ns - for (var i = 0; i < l; i++) s += '%' + UPNG._bin.pad(buff[p + i].toString(16)) - try { - ns = decodeURIComponent(s) - } catch (e) { - return UPNG._bin.readASCII(buff, p, l) - } + for (let i = 0; i < data.length; i += 4) { + const r = data[i + 0] / 255 + const g = data[i + 1] / 255 + const b = data[i + 2] / 255 + const a = data[i + 3] / 255 - return ns - }, -} -UPNG._copyTile = function (sb, sw, sh, tb, tw, th, xoff, yoff, mode) { - var w = Math.min(sw, tw), - h = Math.min(sh, th) - var si = 0, - ti = 0 - for (var y = 0; y < h; y++) { - for (var x = 0; x < w; x++) { - if (xoff >= 0 && yoff >= 0) { - si = (y * sw + x) << 2 - ti = ((yoff + y) * tw + xoff + x) << 2 + if (this.type === HalfFloatType) { + output[i + 0] = DataUtils.toHalfFloat(Math.min(r * a * this.maxRange, 65504)) + output[i + 1] = DataUtils.toHalfFloat(Math.min(g * a * this.maxRange, 65504)) + output[i + 2] = DataUtils.toHalfFloat(Math.min(b * a * this.maxRange, 65504)) + output[i + 3] = DataUtils.toHalfFloat(1) } else { - si = ((-yoff + y) * sw - xoff + x) << 2 - ti = (y * tw + x) << 2 + output[i + 0] = r * a * this.maxRange + output[i + 1] = g * a * this.maxRange + output[i + 2] = b * a * this.maxRange + output[i + 3] = 1 } + } - if (mode == 0) { - tb[ti] = sb[si] - tb[ti + 1] = sb[si + 1] - tb[ti + 2] = sb[si + 2] - tb[ti + 3] = sb[si + 3] - } else if (mode == 1) { - var fa = sb[si + 3] * (1 / 255), - fr = sb[si] * fa, - fg = sb[si + 1] * fa, - fb = sb[si + 2] * fa - var ba = tb[ti + 3] * (1 / 255), - br = tb[ti] * ba, - bg = tb[ti + 1] * ba, - bb = tb[ti + 2] * ba - - var ifa = 1 - fa, - oa = fa + ba * ifa, - ioa = oa == 0 ? 0 : 1 / oa - tb[ti + 3] = 255 * oa - tb[ti + 0] = (fr + br * ifa) * ioa - tb[ti + 1] = (fg + bg * ifa) * ioa - tb[ti + 2] = (fb + bb * ifa) * ioa - } else if (mode == 2) { - // copy only differences, otherwise zero - - var fa = sb[si + 3], - fr = sb[si], - fg = sb[si + 1], - fb = sb[si + 2] - var ba = tb[ti + 3], - br = tb[ti], - bg = tb[ti + 1], - bb = tb[ti + 2] - if (fa == ba && fr == br && fg == bg && fb == bb) { - tb[ti] = 0 - tb[ti + 1] = 0 - tb[ti + 2] = 0 - tb[ti + 3] = 0 - } else { - tb[ti] = fr - tb[ti + 1] = fg - tb[ti + 2] = fb - tb[ti + 3] = fa - } - } else if (mode == 3) { - // check if can be blended - - var fa = sb[si + 3], - fr = sb[si], - fg = sb[si + 1], - fb = sb[si + 2] - var ba = tb[ti + 3], - br = tb[ti], - bg = tb[ti + 1], - bb = tb[ti + 2] - if (fa == ba && fr == br && fg == bg && fb == bb) continue - //if(fa!=255 && ba!=0) return false; - if (fa < 220 && ba > 20) return false - } + return { + width: img.width, + height: img.height, + data: output, + format: RGBAFormat, + type: this.type, + flipY: true, } } - - return true } export { RGBMLoader } diff --git a/src/loaders/TiltLoader.js b/src/loaders/TiltLoader.js index f8d21592..5ce41e4d 100644 --- a/src/loaders/TiltLoader.js +++ b/src/loaders/TiltLoader.js @@ -369,7 +369,9 @@ const common = { const shaders = () => ({ Light: { uniforms: { - mainTex: { value: new TextureLoader().setPath('./textures/tiltbrush/').loader.load('Light.webp') }, + mainTex: { + value: /* @__PURE__ */ new TextureLoader().setPath('./textures/tiltbrush/').loader.load('Light.webp'), + }, alphaTest: { value: 0.067 }, emission_gain: { value: 0.45 }, alpha: { value: 1 }, diff --git a/src/loaders/VRMLoader.d.ts b/src/loaders/VRMLoader.d.ts new file mode 100644 index 00000000..106a492e --- /dev/null +++ b/src/loaders/VRMLoader.d.ts @@ -0,0 +1,19 @@ +import { Loader, LoadingManager } from 'three' + +import { GLTFLoader, GLTF } from './GLTFLoader' +import { DRACOLoader } from './DRACOLoader' + +export class VRMLoader extends Loader { + constructor(manager?: LoadingManager) + gltfLoader: GLTFLoader + + load( + url: string, + onLoad: (scene: GLTF) => void, + onProgress?: (event: ProgressEvent) => void, + onError?: (event: ErrorEvent) => void, + ): void + loadAsync(url: string, onProgress?: (event: ProgressEvent) => void): Promise + parse(gltf: GLTF, onLoad: (scene: GLTF) => void): void + setDRACOLoader(dracoLoader: DRACOLoader): this +} diff --git a/src/loaders/XLoader.d.ts b/src/loaders/XLoader.d.ts new file mode 100644 index 00000000..0d4a8241 --- /dev/null +++ b/src/loaders/XLoader.d.ts @@ -0,0 +1,19 @@ +import { Mesh, Loader, LoadingManager } from 'three' + +export interface XResult { + animations: object[] + models: Mesh[] +} + +export class XLoader extends Loader { + constructor(manager?: LoadingManager) + + load( + url: string, + onLoad: (object: XResult) => void, + onProgress?: (event: ProgressEvent) => void, + onError?: (event: ErrorEvent) => void, + ): void + loadAsync(url: string, onProgress?: (event: ProgressEvent) => void): Promise + parse(data: ArrayBuffer | string, onLoad: (object: object) => void): object +} diff --git a/src/loaders/XLoader.js b/src/loaders/XLoader.js index 49ff0616..15a38d4a 100644 --- a/src/loaders/XLoader.js +++ b/src/loaders/XLoader.js @@ -20,7 +20,7 @@ import { Vector3, } from 'three' -var XLoader = (function () { +var XLoader = /* @__PURE__ */ (function () { var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function') diff --git a/src/loaders/lwo/IFFParser.js b/src/loaders/lwo/IFFParser.js index a188eb23..926609fe 100644 --- a/src/loaders/lwo/IFFParser.js +++ b/src/loaders/lwo/IFFParser.js @@ -32,7 +32,6 @@ * **/ -import { LoaderUtils } from 'three' import { LWO2Parser } from './LWO2Parser' import { LWO3Parser } from './LWO3Parser' @@ -584,7 +583,7 @@ IFFParser.prototype = { // x -> -x and switch material FrontSide -> BackSide parsePoints(length) { this.currentPoints = [] - for (let i = 0; i < length / 4; i += 3) { + for (var i = 0; i < length / 4; i += 3) { // z -> -z to match three.js right handed coords this.currentPoints.push(this.reader.getFloat32(), this.reader.getFloat32(), -this.reader.getFloat32()) } @@ -715,7 +714,7 @@ IFFParser.prototype = { numverts = numverts & 1023 // remaining ten low order bits are vertex num polygonDimensions.push(numverts) - for (let j = 0; j < numverts; j++) indices.push(this.reader.getVariableLengthIndex()) + for (var j = 0; j < numverts; j++) indices.push(this.reader.getVariableLengthIndex()) } var geometryData = { @@ -743,9 +742,8 @@ IFFParser.prototype = { parsePolygonTagMapping(length) { var finalOffset = this.reader.offset + length var type = this.reader.getIDTag() - if (type === 'SURF') { - this.parseMaterialIndices(finalOffset) - } else { + if (type === 'SURF') this.parseMaterialIndices(finalOffset) + else { //PART, SMGP, COLR not supported this.reader.skip(length - 4) @@ -779,6 +777,8 @@ IFFParser.prototype = { function DataViewReader(buffer) { this.dv = new DataView(buffer) this.offset = 0 + this._textDecoder = new TextDecoder() + this._bytes = new Uint8Array(buffer) } DataViewReader.prototype = { @@ -846,7 +846,7 @@ DataViewReader.prototype = { getFloat32Array: function (size) { var a = [] - for (let i = 0; i < size; i++) { + for (var i = 0; i < size; i++) { a.push(this.getFloat32()) } @@ -862,7 +862,7 @@ DataViewReader.prototype = { getFloat64Array: function (size) { var a = [] - for (let i = 0; i < size; i++) { + for (var i = 0; i < size; i++) { a.push(this.getFloat64()) } @@ -893,27 +893,30 @@ DataViewReader.prototype = { getString: function (size) { if (size === 0) return - // note: safari 9 doesn't support Uint8Array.indexOf; create intermediate array instead - var a = [] + const start = this.offset + + let result + let length if (size) { - for (let i = 0; i < size; i++) { - a[i] = this.getUint8() - } + length = size + result = this._textDecoder.decode(new Uint8Array(this.dv.buffer, start, size)) } else { - var currentChar - var len = 0 + // use 1:1 mapping of buffer to avoid redundant new array creation. + length = this._bytes.indexOf(0, start) - start - while (currentChar !== 0) { - currentChar = this.getUint8() - if (currentChar !== 0) a.push(currentChar) - len++ - } + result = this._textDecoder.decode(new Uint8Array(this.dv.buffer, start, length)) + + // account for null byte in length + length++ - if (!isEven(len + 1)) this.getUint8() // if string with terminating nullbyte is uneven, extra nullbyte is added + // if string with terminating nullbyte is uneven, extra nullbyte is added, skip that too + length += length % 2 } - return LoaderUtils.decodeText(new Uint8Array(a)) + this.skip(length) + + return result }, getStringArray: function (size) { @@ -978,7 +981,7 @@ Debugger.prototype = { closeForms: function () { if (!this.active) return - for (let i = this.formList.length - 1; i >= 0; i--) { + for (var i = this.formList.length - 1; i >= 0; i--) { if (this.offset >= this.formList[i]) { this.depth -= 1 console.log('| '.repeat(this.depth) + '}') @@ -1003,7 +1006,7 @@ function stringOffset(string) { // for testing purposes, dump buffer to console // printBuffer( this.reader.dv.buffer, this.reader.offset, length ); function printBuffer(buffer, from, to) { - console.log(LoaderUtils.decodeText(new Uint8Array(buffer, from, to))) + console.log(new TextDecoder().decode(new Uint8Array(buffer, from, to))) } export { IFFParser } diff --git a/src/loaders/lwo/LWO2Parser.js b/src/loaders/lwo/LWO2Parser.js index ad0c9f6a..ba9f15b5 100644 --- a/src/loaders/lwo/LWO2Parser.js +++ b/src/loaders/lwo/LWO2Parser.js @@ -1,16 +1,14 @@ -function LWO2Parser(IFFParser) { - this.IFF = IFFParser -} - -LWO2Parser.prototype = { - constructor: LWO2Parser, +class LWO2Parser { + constructor(IFFParser) { + this.IFF = IFFParser + } - parseBlock: function () { + parseBlock() { this.IFF.debugger.offset = this.IFF.reader.offset this.IFF.debugger.closeForms() - var blockID = this.IFF.reader.getIDTag() - var length = this.IFF.reader.getUint32() // size of data in bytes + const blockID = this.IFF.reader.getIDTag() + let length = this.IFF.reader.getUint32() // size of data in bytes if (length > this.IFF.reader.dv.byteLength - this.IFF.reader.offset) { this.IFF.reader.offset -= 4 length = this.IFF.reader.getUint16() @@ -99,6 +97,7 @@ LWO2Parser.prototype = { case 'WRPW': // image wrap w ( for cylindrical and spherical projections) case 'WRPH': // image wrap h case 'NMOD': + case 'NSEL': case 'NPRW': case 'NPLA': case 'NODS': @@ -223,14 +222,11 @@ LWO2Parser.prototype = { // Image Map Layer case 'WRAP': - this.IFF.currentForm.wrap = { - w: this.IFF.reader.getUint16(), - h: this.IFF.reader.getUint16(), - } + this.IFF.currentForm.wrap = { w: this.IFF.reader.getUint16(), h: this.IFF.reader.getUint16() } break case 'IMAG': - var index = this.IFF.reader.getVariableLengthIndex() + const index = this.IFF.reader.getVariableLengthIndex() this.IFF.currentForm.imageIndex = index break @@ -298,50 +294,38 @@ LWO2Parser.prototype = { // LWO2 Spec chunks: these are needed since the SURF FORMs are often in LWO2 format case 'SMAN': - var maxSmoothingAngle = this.IFF.reader.getFloat32() + const maxSmoothingAngle = this.IFF.reader.getFloat32() this.IFF.currentSurface.attributes.smooth = maxSmoothingAngle < 0 ? false : true break // LWO2: Basic Surface Parameters case 'COLR': - this.IFF.currentSurface.attributes.Color = { - value: this.IFF.reader.getFloat32Array(3), - } + this.IFF.currentSurface.attributes.Color = { value: this.IFF.reader.getFloat32Array(3) } this.IFF.reader.skip(2) // VX: envelope break case 'LUMI': - this.IFF.currentSurface.attributes.Luminosity = { - value: this.IFF.reader.getFloat32(), - } + this.IFF.currentSurface.attributes.Luminosity = { value: this.IFF.reader.getFloat32() } this.IFF.reader.skip(2) break case 'SPEC': - this.IFF.currentSurface.attributes.Specular = { - value: this.IFF.reader.getFloat32(), - } + this.IFF.currentSurface.attributes.Specular = { value: this.IFF.reader.getFloat32() } this.IFF.reader.skip(2) break case 'DIFF': - this.IFF.currentSurface.attributes.Diffuse = { - value: this.IFF.reader.getFloat32(), - } + this.IFF.currentSurface.attributes.Diffuse = { value: this.IFF.reader.getFloat32() } this.IFF.reader.skip(2) break case 'REFL': - this.IFF.currentSurface.attributes.Reflection = { - value: this.IFF.reader.getFloat32(), - } + this.IFF.currentSurface.attributes.Reflection = { value: this.IFF.reader.getFloat32() } this.IFF.reader.skip(2) break case 'GLOS': - this.IFF.currentSurface.attributes.Glossiness = { - value: this.IFF.reader.getFloat32(), - } + this.IFF.currentSurface.attributes.Glossiness = { value: this.IFF.reader.getFloat32() } this.IFF.reader.skip(2) break @@ -410,7 +394,7 @@ LWO2Parser.prototype = { if (this.IFF.reader.offset >= this.IFF.currentFormEnd) { this.IFF.currentForm = this.IFF.parentForm } - }, + } } export { LWO2Parser } diff --git a/src/loaders/lwo/LWO3Parser.js b/src/loaders/lwo/LWO3Parser.js index 3bcdca74..37b34eac 100644 --- a/src/loaders/lwo/LWO3Parser.js +++ b/src/loaders/lwo/LWO3Parser.js @@ -1,16 +1,14 @@ -function LWO3Parser(IFFParser) { - this.IFF = IFFParser -} - -LWO3Parser.prototype = { - constructor: LWO3Parser, +class LWO3Parser { + constructor(IFFParser) { + this.IFF = IFFParser + } - parseBlock: function () { + parseBlock() { this.IFF.debugger.offset = this.IFF.reader.offset this.IFF.debugger.closeForms() - var blockID = this.IFF.reader.getIDTag() - var length = this.IFF.reader.getUint32() // size of data in bytes + const blockID = this.IFF.reader.getIDTag() + const length = this.IFF.reader.getUint32() // size of data in bytes this.IFF.debugger.dataOffset = this.IFF.reader.offset this.IFF.debugger.length = length @@ -33,8 +31,8 @@ LWO3Parser.prototype = { case 'NORM': // ENVL FORM skipped - case 'PRE ': - case 'POST': + case 'PRE ': // Pre-loop behavior for the keyframe + case 'POST': // Post-loop behavior for the keyframe case 'KEY ': case 'SPAN': @@ -195,14 +193,11 @@ LWO3Parser.prototype = { // Image Map Layer case 'WRAP': - this.IFF.currentForm.wrap = { - w: this.IFF.reader.getUint16(), - h: this.IFF.reader.getUint16(), - } + this.IFF.currentForm.wrap = { w: this.IFF.reader.getUint16(), h: this.IFF.reader.getUint16() } break case 'IMAG': - var index = this.IFF.reader.getVariableLengthIndex() + const index = this.IFF.reader.getVariableLengthIndex() this.IFF.currentForm.imageIndex = index break @@ -270,50 +265,38 @@ LWO3Parser.prototype = { // LWO2 Spec chunks: these are needed since the SURF FORMs are often in LWO2 format case 'SMAN': - var maxSmoothingAngle = this.IFF.reader.getFloat32() + const maxSmoothingAngle = this.IFF.reader.getFloat32() this.IFF.currentSurface.attributes.smooth = maxSmoothingAngle < 0 ? false : true break // LWO2: Basic Surface Parameters case 'COLR': - this.IFF.currentSurface.attributes.Color = { - value: this.IFF.reader.getFloat32Array(3), - } + this.IFF.currentSurface.attributes.Color = { value: this.IFF.reader.getFloat32Array(3) } this.IFF.reader.skip(2) // VX: envelope break case 'LUMI': - this.IFF.currentSurface.attributes.Luminosity = { - value: this.IFF.reader.getFloat32(), - } + this.IFF.currentSurface.attributes.Luminosity = { value: this.IFF.reader.getFloat32() } this.IFF.reader.skip(2) break case 'SPEC': - this.IFF.currentSurface.attributes.Specular = { - value: this.IFF.reader.getFloat32(), - } + this.IFF.currentSurface.attributes.Specular = { value: this.IFF.reader.getFloat32() } this.IFF.reader.skip(2) break case 'DIFF': - this.IFF.currentSurface.attributes.Diffuse = { - value: this.IFF.reader.getFloat32(), - } + this.IFF.currentSurface.attributes.Diffuse = { value: this.IFF.reader.getFloat32() } this.IFF.reader.skip(2) break case 'REFL': - this.IFF.currentSurface.attributes.Reflection = { - value: this.IFF.reader.getFloat32(), - } + this.IFF.currentSurface.attributes.Reflection = { value: this.IFF.reader.getFloat32() } this.IFF.reader.skip(2) break case 'GLOS': - this.IFF.currentSurface.attributes.Glossiness = { - value: this.IFF.reader.getFloat32(), - } + this.IFF.currentSurface.attributes.Glossiness = { value: this.IFF.reader.getFloat32() } this.IFF.reader.skip(2) break @@ -372,7 +355,7 @@ LWO3Parser.prototype = { if (this.IFF.reader.offset >= this.IFF.currentFormEnd) { this.IFF.currentForm = this.IFF.parentForm } - }, + } } export { LWO3Parser }