diff --git a/js/ThreeCanvas.js b/js/ThreeCanvas.js index 0882473..24de518 100644 --- a/js/ThreeCanvas.js +++ b/js/ThreeCanvas.js @@ -1,8 +1,6 @@ import * as THREE from "./lib/three.module.js"; import { OrbitControls } from "./lib/jsm/controls/OrbitControls.js"; -import { RGBELoader } from './lib/jsm/loaders/RGBELoader.js'; -import { GLTFLoader } from './lib/jsm/loaders/GLTFLoader.js'; -import { DRACOLoader } from './lib/jsm/loaders/DRACOLoader.js'; + import { EffectComposer } from './lib/jsm/postprocessing/EffectComposer.js'; import { RenderPass } from './lib/jsm/postprocessing/RenderPass.js'; import { ShaderPass } from './lib/jsm/postprocessing/ShaderPass.js'; @@ -15,6 +13,7 @@ import { Depth, Outline, Inline, BlackAll, sobelShader, cannyEdgeShader, thresho import { Hub } from "./lib/Hub.js"; import { Files } from "./lib/Files.js"; import { Tools } from "./lib/Tools.js"; +import { Pool } from "./lib/Pool.js"; import { $el } from "./lib/utils.js"; @@ -275,6 +274,8 @@ export class ThreeCanvas { // renderer1.domElement.style.cssText = "position:absolute; margin:0; padding:0; border:1px solid black;"; renderer1.domElement.setAttribute("view", "LEFT") renderer1.domElement.classList.add("threeview_renderer") + + Pool.renderer = renderer1; // Renderer setup 2 LINES const renderer2 = new THREE.WebGLRenderer({ antialias: true, alpha: false }); @@ -395,7 +396,7 @@ export class ThreeCanvas { this.initLight(); this.initEnvmap(); - this.initLoader(); + //this.initLoader(); if(!this.savedData?.currentModel) this.addHeadTest(); @@ -404,12 +405,19 @@ export class ThreeCanvas { if(this.autoAutoAnim) this.animate(); } + getLoader( type = 'glb' ){ + // all loader is on Pool.js + return Pool.getLoader( type ); + } + initEnvmap( url = `./assets/clear.hdr` ){ const envUrl = new URL(url, import.meta.url); const self = this; - new RGBELoader().load( envUrl, function ( texture ) { + + + this.getLoader('hdr').load( envUrl, function ( texture ) { texture.mapping = THREE.EquirectangularReflectionMapping; @@ -488,14 +496,14 @@ export class ThreeCanvas { // import api directlly break index.html preview !! setApi( api ){ this.api = api; } - initLoader(){ + /*initLoader(){ const dracoPath = new URL(`./lib/jsm/libs/draco/gltf/`, import.meta.url); const dracoLoader = new DRACOLoader().setDecoderPath( dracoPath.href ) dracoLoader.setDecoderConfig({ type: 'js' }); this.loaderGltf = new GLTFLoader().setDRACOLoader(dracoLoader); - } + }*/ clear(b){ @@ -567,7 +575,9 @@ export class ThreeCanvas { directGlb( data, name ){ - this.loaderGltf.parse( data, name, ( glb ) => { this.addModel( glb ); }) + this.getLoader('glb').parse( data, name, ( glb ) => { this.addModel( glb ); }) + + //this.loaderGltf.parse( data, name, ( glb ) => { this.addModel( glb ); }) } @@ -580,19 +590,9 @@ export class ThreeCanvas { let u = headModel.href; this.defPath = u.substring( 0, u.lastIndexOf('/')+1 ); - /*const light = new THREE.PointLight( 0x0080FF, 300 ); - light.position.set(-5,5,-10) - scene.add( light ); - const light2 = new THREE.PointLight( 0xff8000, 100 ); - light2.position.set(5,-5,-5) - scene.add( light2 ); - - const light3 = new THREE.PointLight( 0xFFFFFF, 100 ); - light3.position.set(0,5,5) - scene.add( light3 );*/ - - this.loaderGltf.load( headModel.href, ( glb ) => { + //this.loaderGltf. + this.getLoader('glb').load( headModel.href, ( glb ) => { this.addModel( glb ); // Load camera data if( this.savedData?.camera ){ @@ -789,15 +789,14 @@ export class ThreeCanvas { async render() { if (this.autoScale) this.resize(); - //this.tools.forEach((data)=>data.renderer.render(this.scene, data.camera)) + // TODO: find better way to add hub on top if(!this.hub.ready) this.hub.add(this.getDom(0)) this.tools.forEach((data)=>{ + let camera = this.VIEWS3 && !this.fixCamers ? data.camera : this.camera - - this.scene.overrideMaterial = !data.material ? null: data.material; if( data.type !== 'color' ) this.helper.visible = false @@ -814,7 +813,6 @@ export class ThreeCanvas { } - //this.scene.overrideMaterial = !data.material ? null: data.material; return data.renderer.render(this.scene, camera) }) @@ -843,7 +841,7 @@ export class ThreeCanvas { } - async update(widgetWidth, posY) { + /*async update(widgetWidth, posY) { let w = widgetWidth - this.size.offset; if (this.size.w === w) return; @@ -851,7 +849,7 @@ export class ThreeCanvas { this.size.h = w * this.size.r; this.needResize = true; - } + }*/ // Get object saves property getSavedOptions(){ diff --git a/js/lib/Pool.js b/js/lib/Pool.js new file mode 100644 index 0000000..9b1ae62 --- /dev/null +++ b/js/lib/Pool.js @@ -0,0 +1,82 @@ +import * as THREE from "./three.module.js"; + +// 3D MODEL +import { GLTFLoader } from './jsm/loaders/GLTFLoader.js'; +import { DRACOLoader } from './jsm/loaders/DRACOLoader.js'; +import { KTX2Loader } from './jsm/loaders/KTX2Loader.js'; +import { MeshoptDecoder } from './jsm/libs/meshopt_decoder.module.js'; +import { FBXLoader } from './jsm/loaders/FBXLoader.js'; +import { OBJLoader } from './jsm/loaders/OBJLoader.js'; +import { STLLoader } from './jsm/loaders/STLLoader.js'; +// IMAGE +import { RGBELoader } from './jsm/loaders/RGBELoader.js'; +import { EXRLoader } from './jsm/loaders/EXRLoader.js'; + +export const Pool = { + + renderer:null, + manager: new THREE.LoadingManager(), + + loader:{ + + gltf:null, + fbx:null, + obj:null, + stl:null, + + hdr:null, + exr:null, + + }, + + getLoader( type ){ + + if(type==='gltf') type = 'glb'; + if(Pool['l_' + type]) return Pool['l_' + type](); + + }, + + l_exr(){ + if(Pool.loader.exr === null ) Pool.loader.exr = new EXRLoader( Pool.manager ); + return Pool.loader.exr; + }, + + l_hdr(){ + if(Pool.loader.hdr === null ) Pool.loader.hdr = new RGBELoader( Pool.manager ); + return Pool.loader.hdr; + }, + + l_obj(){ + if(Pool.loader.obj === null ) Pool.loader.obj = new OBJLoader( Pool.manager ); + return Pool.loader.obj; + }, + + l_fbx(){ + if(Pool.loader.fbx === null ) Pool.loader.fbx = new FBXLoader( Pool.manager ); + return Pool.loader.fbx; + }, + + l_stl(){ + if(Pool.loader.stl === null ) Pool.loader.stl = new STLLoader( Pool.manager ); + return Pool.loader.stl; + }, + + l_glb(){ + if(Pool.loader.gltf === null ){ + const dracoPath = new URL(`./jsm/libs/draco/gltf/`, import.meta.url); + const dracoLoader = new DRACOLoader().setDecoderPath( dracoPath.href ) + dracoLoader.setDecoderConfig({ type: 'js' }); + + const ktx2Path = new URL(`./jsm/libs/basis/`, import.meta.url); + const ktx2Loader = new KTX2Loader().setTranscoderPath( ktx2Path.href ) + + Pool.loader.gltf = new GLTFLoader( Pool.manager ) + .setCrossOrigin('anonymous') + .setDRACOLoader(dracoLoader) + .setKTX2Loader(ktx2Loader.detectSupport(Pool.renderer)) + .setMeshoptDecoder(MeshoptDecoder); + } + return Pool.loader.gltf; + } + +} \ No newline at end of file diff --git a/js/lib/jsm/libs/basis/README.md b/js/lib/jsm/libs/basis/README.md new file mode 100644 index 0000000..2d7744f --- /dev/null +++ b/js/lib/jsm/libs/basis/README.md @@ -0,0 +1,46 @@ +# Basis Universal GPU Texture Compression + +Basis Universal is a "[supercompressed](http://gamma.cs.unc.edu/GST/gst.pdf)" +GPU texture and texture video compression system that outputs a highly +compressed intermediate file format (.basis) that can be quickly transcoded to +a wide variety of GPU texture compression formats. + +[GitHub](https://github.com/BinomialLLC/basis_universal) + +## Transcoders + +Basis Universal texture data may be used in two different file formats: +`.basis` and `.ktx2`, where `ktx2` is a standardized wrapper around basis texture data. + +For further documentation about the Basis compressor and transcoder, refer to +the [Basis GitHub repository](https://github.com/BinomialLLC/basis_universal). + +The folder contains two files required for transcoding `.basis` or `.ktx2` textures: + +* `basis_transcoder.js` — JavaScript wrapper for the WebAssembly transcoder. +* `basis_transcoder.wasm` — WebAssembly transcoder. + +Both are dependencies of `KTX2Loader`: + +```js +const ktx2Loader = new KTX2Loader(); +ktx2Loader.setTranscoderPath( 'examples/jsm/libs/basis/' ); +ktx2Loader.detectSupport( renderer ); +ktx2Loader.load( 'diffuse.ktx2', function ( texture ) { + + const material = new THREE.MeshStandardMaterial( { map: texture } ); + +}, function () { + + console.log( 'onProgress' ); + +}, function ( e ) { + + console.error( e ); + +} ); +``` + +## License + +[Apache License 2.0](https://github.com/BinomialLLC/basis_universal/blob/master/LICENSE) diff --git a/js/lib/jsm/libs/basis/basis_transcoder.js b/js/lib/jsm/libs/basis/basis_transcoder.js new file mode 100644 index 0000000..6f02a4a --- /dev/null +++ b/js/lib/jsm/libs/basis/basis_transcoder.js @@ -0,0 +1,19 @@ + +var BASIS = (() => { + var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined; + if (typeof __filename != 'undefined') _scriptName ||= __filename; + return ( +function(moduleArg = {}) { + var moduleRtn; + +var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){}var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");scriptDirectory=__dirname+"/";readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);var ret=fs.readFileSync(filename);return ret};readAsync=(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return new Promise((resolve,reject)=>{fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)reject(err);else resolve(binary?data.buffer:data)})})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptName){scriptDirectory=_scriptName}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=url=>{if(isFileURI(url)){return new Promise((reject,resolve)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){resolve(xhr.response)}reject(xhr.status)};xhr.onerror=reject;xhr.send(null)})}return fetch(url,{credentials:"same-origin"}).then(response=>{if(response.ok){return response.arrayBuffer()}return Promise.reject(new Error(response.status+" : "+response.url))})}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var wasmMemory;var ABORT=false;var EXITSTATUS;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var __ATPRERUN__=[];var __ATINIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);var isFileURI=filename=>filename.startsWith("file://");function findWasmBinary(){var f="basis_transcoder.wasm";if(!isDataURI(f)){return locateFile(f)}return f}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary){return readAsync(binaryFile).then(response=>new Uint8Array(response),()=>getBinarySync(binaryFile))}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return{a:wasmImports}}function createWasm(){var info=getWasmImports();function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["L"];updateMemoryViews();wasmTable=wasmExports["P"];addOnInit(wasmExports["M"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}if(!wasmBinaryFile)wasmBinaryFile=findWasmBinary();instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var noExitRuntime=Module["noExitRuntime"]||true;class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>2]=type}get_type(){return HEAPU32[this.ptr+4>>2]}set_destructor(destructor){HEAPU32[this.ptr+8>>2]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>2]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12]=caught}get_caught(){return HEAP8[this.ptr+12]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13]=rethrown}get_rethrown(){return HEAP8[this.ptr+13]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>2]}get_exception_ptr(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return HEAPU32[this.excPtr>>2]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}var exceptionLast=0;var uncaughtExceptionCount=0;var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast};var __abort_js=()=>{abort("")};var structRegistrations={};var runDestructors=destructors=>{while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}};function readPointer(pointer){return this["fromWireType"](HEAPU32[pointer>>2])}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var InternalError;var throwInternalError=message=>{throw new InternalError(message)};var whenDependentTypesAreResolved=(myTypes,dependentTypes,getTypeConverters)=>{myTypes.forEach(function(type){typeDependencies[type]=dependentTypes});function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i{if(registeredTypes.hasOwnProperty(dt)){typeConverters[i]=registeredTypes[dt]}else{unregisteredTypes.push(dt);if(!awaitingDependencies.hasOwnProperty(dt)){awaitingDependencies[dt]=[]}awaitingDependencies[dt].push(()=>{typeConverters[i]=registeredTypes[dt];++registered;if(registered===unregisteredTypes.length){onComplete(typeConverters)}})}});if(0===unregisteredTypes.length){onComplete(typeConverters)}};var __embind_finalize_value_object=structType=>{var reg=structRegistrations[structType];delete structRegistrations[structType];var rawConstructor=reg.rawConstructor;var rawDestructor=reg.rawDestructor;var fieldRecords=reg.fields;var fieldTypes=fieldRecords.map(field=>field.getterReturnType).concat(fieldRecords.map(field=>field.setterArgumentType));whenDependentTypesAreResolved([structType],fieldTypes,fieldTypes=>{var fields={};fieldRecords.forEach((field,i)=>{var fieldName=field.fieldName;var getterReturnType=fieldTypes[i];var getter=field.getter;var getterContext=field.getterContext;var setterArgumentType=fieldTypes[i+fieldRecords.length];var setter=field.setter;var setterContext=field.setterContext;fields[fieldName]={read:ptr=>getterReturnType["fromWireType"](getter(getterContext,ptr)),write:(ptr,o)=>{var destructors=[];setter(setterContext,ptr,setterArgumentType["toWireType"](destructors,o));runDestructors(destructors)}}});return[{name:reg.name,fromWireType:ptr=>{var rv={};for(var i in fields){rv[i]=fields[i].read(ptr)}rawDestructor(ptr);return rv},toWireType:(destructors,o)=>{for(var fieldName in fields){if(!(fieldName in o)){throw new TypeError(`Missing field: "${fieldName}"`)}}var ptr=rawConstructor();for(fieldName in fields){fields[fieldName].write(ptr,o[fieldName])}if(destructors!==null){destructors.push(rawDestructor,ptr)}return ptr},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction:rawDestructor}]})};var __embind_register_bigint=(primitiveType,name,size,minRange,maxRange)=>{};var embind_init_charCodes=()=>{var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes};var embind_charCodes;var readLatin1String=ptr=>{var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret};var BindingError;var throwBindingError=message=>{throw new BindingError(message)};function sharedRegisterType(rawType,registeredInstance,options={}){var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function registerType(rawType,registeredInstance,options={}){if(!("argPackAdvance"in registeredInstance)){throw new TypeError("registerType registeredInstance requires argPackAdvance")}return sharedRegisterType(rawType,registeredInstance,options)}var GenericWireTypeSize=8;var __embind_register_bool=(rawType,name,trueValue,falseValue)=>{name=readLatin1String(name);registerType(rawType,{name:name,fromWireType:function(wt){return!!wt},toWireType:function(destructors,o){return o?trueValue:falseValue},argPackAdvance:GenericWireTypeSize,readValueFromPointer:function(pointer){return this["fromWireType"](HEAPU8[pointer])},destructorFunction:null})};var shallowCopyInternalPointer=o=>({count:o.count,deleteScheduled:o.deleteScheduled,preservePointerOnDelete:o.preservePointerOnDelete,ptr:o.ptr,ptrType:o.ptrType,smartPtr:o.smartPtr,smartPtrType:o.smartPtrType});var throwInstanceAlreadyDeleted=obj=>{function getInstanceTypeName(handle){return handle.$$.ptrType.registeredClass.name}throwBindingError(getInstanceTypeName(obj)+" instance already deleted")};var finalizationRegistry=false;var detachFinalizer=handle=>{};var runDestructor=$$=>{if($$.smartPtr){$$.smartPtrType.rawDestructor($$.smartPtr)}else{$$.ptrType.registeredClass.rawDestructor($$.ptr)}};var releaseClassHandle=$$=>{$$.count.value-=1;var toDelete=0===$$.count.value;if(toDelete){runDestructor($$)}};var downcastPointer=(ptr,ptrClass,desiredClass)=>{if(ptrClass===desiredClass){return ptr}if(undefined===desiredClass.baseClass){return null}var rv=downcastPointer(ptr,ptrClass,desiredClass.baseClass);if(rv===null){return null}return desiredClass.downcast(rv)};var registeredPointers={};var getInheritedInstanceCount=()=>Object.keys(registeredInstances).length;var getLiveInheritedInstances=()=>{var rv=[];for(var k in registeredInstances){if(registeredInstances.hasOwnProperty(k)){rv.push(registeredInstances[k])}}return rv};var deletionQueue=[];var flushPendingDeletes=()=>{while(deletionQueue.length){var obj=deletionQueue.pop();obj.$$.deleteScheduled=false;obj["delete"]()}};var delayFunction;var setDelayFunction=fn=>{delayFunction=fn;if(deletionQueue.length&&delayFunction){delayFunction(flushPendingDeletes)}};var init_embind=()=>{Module["getInheritedInstanceCount"]=getInheritedInstanceCount;Module["getLiveInheritedInstances"]=getLiveInheritedInstances;Module["flushPendingDeletes"]=flushPendingDeletes;Module["setDelayFunction"]=setDelayFunction};var registeredInstances={};var getBasestPointer=(class_,ptr)=>{if(ptr===undefined){throwBindingError("ptr should not be undefined")}while(class_.baseClass){ptr=class_.upcast(ptr);class_=class_.baseClass}return ptr};var getInheritedInstance=(class_,ptr)=>{ptr=getBasestPointer(class_,ptr);return registeredInstances[ptr]};var makeClassHandle=(prototype,record)=>{if(!record.ptrType||!record.ptr){throwInternalError("makeClassHandle requires ptr and ptrType")}var hasSmartPtrType=!!record.smartPtrType;var hasSmartPtr=!!record.smartPtr;if(hasSmartPtrType!==hasSmartPtr){throwInternalError("Both smartPtrType and smartPtr must be specified")}record.count={value:1};return attachFinalizer(Object.create(prototype,{$$:{value:record,writable:true}}))};function RegisteredPointer_fromWireType(ptr){var rawPointer=this.getPointee(ptr);if(!rawPointer){this.destructor(ptr);return null}var registeredInstance=getInheritedInstance(this.registeredClass,rawPointer);if(undefined!==registeredInstance){if(0===registeredInstance.$$.count.value){registeredInstance.$$.ptr=rawPointer;registeredInstance.$$.smartPtr=ptr;return registeredInstance["clone"]()}else{var rv=registeredInstance["clone"]();this.destructor(ptr);return rv}}function makeDefaultHandle(){if(this.isSmartPointer){return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:rawPointer,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this,ptr:ptr})}}var actualType=this.registeredClass.getActualType(rawPointer);var registeredPointerRecord=registeredPointers[actualType];if(!registeredPointerRecord){return makeDefaultHandle.call(this)}var toType;if(this.isConst){toType=registeredPointerRecord.constPointerType}else{toType=registeredPointerRecord.pointerType}var dp=downcastPointer(rawPointer,this.registeredClass,toType.registeredClass);if(dp===null){return makeDefaultHandle.call(this)}if(this.isSmartPointer){return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp})}}var attachFinalizer=handle=>{if("undefined"===typeof FinalizationRegistry){attachFinalizer=handle=>handle;return handle}finalizationRegistry=new FinalizationRegistry(info=>{releaseClassHandle(info.$$)});attachFinalizer=handle=>{var $$=handle.$$;var hasSmartPtr=!!$$.smartPtr;if(hasSmartPtr){var info={$$:$$};finalizationRegistry.register(handle,info,handle)}return handle};detachFinalizer=handle=>finalizationRegistry.unregister(handle);return attachFinalizer(handle)};var init_ClassHandle=()=>{Object.assign(ClassHandle.prototype,{isAliasOf(other){if(!(this instanceof ClassHandle)){return false}if(!(other instanceof ClassHandle)){return false}var leftClass=this.$$.ptrType.registeredClass;var left=this.$$.ptr;other.$$=other.$$;var rightClass=other.$$.ptrType.registeredClass;var right=other.$$.ptr;while(leftClass.baseClass){left=leftClass.upcast(left);leftClass=leftClass.baseClass}while(rightClass.baseClass){right=rightClass.upcast(right);rightClass=rightClass.baseClass}return leftClass===rightClass&&left===right},clone(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.preservePointerOnDelete){this.$$.count.value+=1;return this}else{var clone=attachFinalizer(Object.create(Object.getPrototypeOf(this),{$$:{value:shallowCopyInternalPointer(this.$$)}}));clone.$$.count.value+=1;clone.$$.deleteScheduled=false;return clone}},delete(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}detachFinalizer(this);releaseClassHandle(this.$$);if(!this.$$.preservePointerOnDelete){this.$$.smartPtr=undefined;this.$$.ptr=undefined}},isDeleted(){return!this.$$.ptr},deleteLater(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}deletionQueue.push(this);if(deletionQueue.length===1&&delayFunction){delayFunction(flushPendingDeletes)}this.$$.deleteScheduled=true;return this}})};function ClassHandle(){}var createNamedFunction=(name,body)=>Object.defineProperty(body,"name",{value:name});var ensureOverloadTable=(proto,methodName,humanName)=>{if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(...args){if(!proto[methodName].overloadTable.hasOwnProperty(args.length)){throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${args.length}) - expects one of (${proto[methodName].overloadTable})!`)}return proto[methodName].overloadTable[args.length].apply(this,args)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}};var exposePublicSymbol=(name,value,numArguments)=>{if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError(`Cannot register public name '${name}' twice`)}ensureOverloadTable(Module,name,name);if(Module.hasOwnProperty(numArguments)){throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`)}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;if(undefined!==numArguments){Module[name].numArguments=numArguments}}};var char_0=48;var char_9=57;var makeLegalFunctionName=name=>{if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return`_${name}`}return name};function RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast){this.name=name;this.constructor=constructor;this.instancePrototype=instancePrototype;this.rawDestructor=rawDestructor;this.baseClass=baseClass;this.getActualType=getActualType;this.upcast=upcast;this.downcast=downcast;this.pureVirtualFunctions=[]}var upcastPointer=(ptr,ptrClass,desiredClass)=>{while(ptrClass!==desiredClass){if(!ptrClass.upcast){throwBindingError(`Expected null or instance of ${desiredClass.name}, got an instance of ${ptrClass.name}`)}ptr=ptrClass.upcast(ptr);ptrClass=ptrClass.baseClass}return ptr};function constNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function genericPointerToWireType(destructors,handle){var ptr;if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}if(this.isSmartPointer){ptr=this.rawConstructor();if(destructors!==null){destructors.push(this.rawDestructor,ptr)}return ptr}else{return 0}}if(!handle||!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(!this.isConst&&handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);if(this.isSmartPointer){if(undefined===handle.$$.smartPtr){throwBindingError("Passing raw pointer to smart pointer is illegal")}switch(this.sharingPolicy){case 0:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}break;case 1:ptr=handle.$$.smartPtr;break;case 2:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{var clonedHandle=handle["clone"]();ptr=this.rawShare(ptr,Emval.toHandle(()=>clonedHandle["delete"]()));if(destructors!==null){destructors.push(this.rawDestructor,ptr)}}break;default:throwBindingError("Unsupporting sharing policy")}}return ptr}function nonConstNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}var init_RegisteredPointer=()=>{Object.assign(RegisteredPointer.prototype,{getPointee(ptr){if(this.rawGetPointee){ptr=this.rawGetPointee(ptr)}return ptr},destructor(ptr){this.rawDestructor?.(ptr)},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,fromWireType:RegisteredPointer_fromWireType})};function RegisteredPointer(name,registeredClass,isReference,isConst,isSmartPointer,pointeeType,sharingPolicy,rawGetPointee,rawConstructor,rawShare,rawDestructor){this.name=name;this.registeredClass=registeredClass;this.isReference=isReference;this.isConst=isConst;this.isSmartPointer=isSmartPointer;this.pointeeType=pointeeType;this.sharingPolicy=sharingPolicy;this.rawGetPointee=rawGetPointee;this.rawConstructor=rawConstructor;this.rawShare=rawShare;this.rawDestructor=rawDestructor;if(!isSmartPointer&®isteredClass.baseClass===undefined){if(isConst){this["toWireType"]=constNoSmartPtrRawPointerToWireType;this.destructorFunction=null}else{this["toWireType"]=nonConstNoSmartPtrRawPointerToWireType;this.destructorFunction=null}}else{this["toWireType"]=genericPointerToWireType}}var replacePublicSymbol=(name,value,numArguments)=>{if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistent public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var dynCallLegacy=(sig,ptr,args)=>{sig=sig.replace(/p/g,"i");var f=Module["dynCall_"+sig];return f(ptr,...args)};var wasmTableMirror=[];var wasmTable;var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func};var dynCall=(sig,ptr,args=[])=>{if(sig.includes("j")){return dynCallLegacy(sig,ptr,args)}var rtn=getWasmTableEntry(ptr)(...args);return rtn};var getDynCaller=(sig,ptr)=>(...args)=>dynCall(sig,ptr,args);var embind__requireFunction=(signature,rawFunction)=>{signature=readLatin1String(signature);function makeDynCaller(){if(signature.includes("j")){return getDynCaller(signature,rawFunction)}return getWasmTableEntry(rawFunction)}var fp=makeDynCaller();if(typeof fp!="function"){throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`)}return fp};var extendError=(baseErrorType,errorName)=>{var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return`${this.name}: ${this.message}`}};return errorClass};var UnboundTypeError;var getTypeName=type=>{var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv};var throwUnboundTypeError=(message,types)=>{var unboundTypes=[];var seen={};function visit(type){if(seen[type]){return}if(registeredTypes[type]){return}if(typeDependencies[type]){typeDependencies[type].forEach(visit);return}unboundTypes.push(type);seen[type]=true}types.forEach(visit);throw new UnboundTypeError(`${message}: `+unboundTypes.map(getTypeName).join([", "]))};var __embind_register_class=(rawType,rawPointerType,rawConstPointerType,baseClassRawType,getActualTypeSignature,getActualType,upcastSignature,upcast,downcastSignature,downcast,name,destructorSignature,rawDestructor)=>{name=readLatin1String(name);getActualType=embind__requireFunction(getActualTypeSignature,getActualType);upcast&&=embind__requireFunction(upcastSignature,upcast);downcast&&=embind__requireFunction(downcastSignature,downcast);rawDestructor=embind__requireFunction(destructorSignature,rawDestructor);var legalFunctionName=makeLegalFunctionName(name);exposePublicSymbol(legalFunctionName,function(){throwUnboundTypeError(`Cannot construct ${name} due to unbound types`,[baseClassRawType])});whenDependentTypesAreResolved([rawType,rawPointerType,rawConstPointerType],baseClassRawType?[baseClassRawType]:[],base=>{base=base[0];var baseClass;var basePrototype;if(baseClassRawType){baseClass=base.registeredClass;basePrototype=baseClass.instancePrototype}else{basePrototype=ClassHandle.prototype}var constructor=createNamedFunction(name,function(...args){if(Object.getPrototypeOf(this)!==instancePrototype){throw new BindingError("Use 'new' to construct "+name)}if(undefined===registeredClass.constructor_body){throw new BindingError(name+" has no accessible constructor")}var body=registeredClass.constructor_body[args.length];if(undefined===body){throw new BindingError(`Tried to invoke ctor of ${name} with invalid number of parameters (${args.length}) - expected (${Object.keys(registeredClass.constructor_body).toString()}) parameters instead!`)}return body.apply(this,args)});var instancePrototype=Object.create(basePrototype,{constructor:{value:constructor}});constructor.prototype=instancePrototype;var registeredClass=new RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast);if(registeredClass.baseClass){registeredClass.baseClass.__derivedClasses??=[];registeredClass.baseClass.__derivedClasses.push(registeredClass)}var referenceConverter=new RegisteredPointer(name,registeredClass,true,false,false);var pointerConverter=new RegisteredPointer(name+"*",registeredClass,false,false,false);var constPointerConverter=new RegisteredPointer(name+" const*",registeredClass,false,true,false);registeredPointers[rawType]={pointerType:pointerConverter,constPointerType:constPointerConverter};replacePublicSymbol(legalFunctionName,constructor);return[referenceConverter,pointerConverter,constPointerConverter]})};var heap32VectorToArray=(count,firstElement)=>{var array=[];for(var i=0;i>2])}return array};function usesDestructorStack(argTypes){for(var i=1;i0?", ":"")+argsListWired}invokerFnBody+=(returns||isAsync?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i{var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);invoker=embind__requireFunction(invokerSignature,invoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`constructor ${classType.name}`;if(undefined===classType.registeredClass.constructor_body){classType.registeredClass.constructor_body=[]}if(undefined!==classType.registeredClass.constructor_body[argCount-1]){throw new BindingError(`Cannot register multiple constructors with identical number of parameters (${argCount-1}) for class '${classType.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`)}classType.registeredClass.constructor_body[argCount-1]=()=>{throwUnboundTypeError(`Cannot construct ${classType.name} due to unbound types`,rawArgTypes)};whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{argTypes.splice(1,0,null);classType.registeredClass.constructor_body[argCount-1]=craftInvokerFunction(humanName,argTypes,null,invoker,rawConstructor);return[]});return[]})};var getFunctionName=signature=>{signature=signature.trim();const argsIndex=signature.indexOf("(");if(argsIndex!==-1){return signature.substr(0,argsIndex)}else{return signature}};var __embind_register_class_function=(rawClassType,methodName,argCount,rawArgTypesAddr,invokerSignature,rawInvoker,context,isPureVirtual,isAsync)=>{var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);methodName=readLatin1String(methodName);methodName=getFunctionName(methodName);rawInvoker=embind__requireFunction(invokerSignature,rawInvoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`${classType.name}.${methodName}`;if(methodName.startsWith("@@")){methodName=Symbol[methodName.substring(2)]}if(isPureVirtual){classType.registeredClass.pureVirtualFunctions.push(methodName)}function unboundTypesHandler(){throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`,rawArgTypes)}var proto=classType.registeredClass.instancePrototype;var method=proto[methodName];if(undefined===method||undefined===method.overloadTable&&method.className!==classType.name&&method.argCount===argCount-2){unboundTypesHandler.argCount=argCount-2;unboundTypesHandler.className=classType.name;proto[methodName]=unboundTypesHandler}else{ensureOverloadTable(proto,methodName,humanName);proto[methodName].overloadTable[argCount-2]=unboundTypesHandler}whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{var memberFunction=craftInvokerFunction(humanName,argTypes,classType,rawInvoker,context,isAsync);if(undefined===proto[methodName].overloadTable){memberFunction.argCount=argCount-2;proto[methodName]=memberFunction}else{proto[methodName].overloadTable[argCount-2]=memberFunction}return[]});return[]})};var __embind_register_constant=(name,type,value)=>{name=readLatin1String(name);whenDependentTypesAreResolved([],[type],type=>{type=type[0];Module[name]=type["fromWireType"](value);return[]})};var emval_freelist=[];var emval_handles=[];var __emval_decref=handle=>{if(handle>9&&0===--emval_handles[handle+1]){emval_handles[handle]=undefined;emval_freelist.push(handle)}};var count_emval_handles=()=>emval_handles.length/2-5-emval_freelist.length;var init_emval=()=>{emval_handles.push(0,1,undefined,1,null,1,true,1,false,1);Module["count_emval_handles"]=count_emval_handles};var Emval={toValue:handle=>{if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handles[handle]},toHandle:value=>{switch(value){case undefined:return 2;case null:return 4;case true:return 6;case false:return 8;default:{const handle=emval_freelist.pop()||emval_handles.length;emval_handles[handle]=value;emval_handles[handle+1]=1;return handle}}}};var EmValType={name:"emscripten::val",fromWireType:handle=>{var rv=Emval.toValue(handle);__emval_decref(handle);return rv},toWireType:(destructors,value)=>Emval.toHandle(value),argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction:null};var __embind_register_emval=rawType=>registerType(rawType,EmValType);var enumReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?function(pointer){return this["fromWireType"](HEAP8[pointer])}:function(pointer){return this["fromWireType"](HEAPU8[pointer])};case 2:return signed?function(pointer){return this["fromWireType"](HEAP16[pointer>>1])}:function(pointer){return this["fromWireType"](HEAPU16[pointer>>1])};case 4:return signed?function(pointer){return this["fromWireType"](HEAP32[pointer>>2])}:function(pointer){return this["fromWireType"](HEAPU32[pointer>>2])};default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};var __embind_register_enum=(rawType,name,size,isSigned)=>{name=readLatin1String(name);function ctor(){}ctor.values={};registerType(rawType,{name:name,constructor:ctor,fromWireType:function(c){return this.constructor.values[c]},toWireType:(destructors,c)=>c.value,argPackAdvance:GenericWireTypeSize,readValueFromPointer:enumReadValueFromPointer(name,size,isSigned),destructorFunction:null});exposePublicSymbol(name,ctor)};var requireRegisteredType=(rawType,humanName)=>{var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(`${humanName} has unknown type ${getTypeName(rawType)}`)}return impl};var __embind_register_enum_value=(rawEnumType,name,enumValue)=>{var enumType=requireRegisteredType(rawEnumType,"enum");name=readLatin1String(name);var Enum=enumType.constructor;var Value=Object.create(enumType.constructor.prototype,{value:{value:enumValue},constructor:{value:createNamedFunction(`${enumType.name}_${name}`,function(){})}});Enum.values[enumValue]=Value;Enum[name]=Value};var embindRepr=v=>{if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}};var floatReadValueFromPointer=(name,width)=>{switch(width){case 4:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 8:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError(`invalid float width (${width}): ${name}`)}};var __embind_register_float=(rawType,name,size)=>{name=readLatin1String(name);registerType(rawType,{name:name,fromWireType:value=>value,toWireType:(destructors,value)=>value,argPackAdvance:GenericWireTypeSize,readValueFromPointer:floatReadValueFromPointer(name,size),destructorFunction:null})};var __embind_register_function=(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn,isAsync)=>{var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);name=getFunctionName(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,function(){throwUnboundTypeError(`Cannot call ${name} due to unbound types`,argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,argTypes=>{var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn,isAsync),argCount-1);return[]})};var integerReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?pointer=>HEAP8[pointer]:pointer=>HEAPU8[pointer];case 2:return signed?pointer=>HEAP16[pointer>>1]:pointer=>HEAPU16[pointer>>1];case 4:return signed?pointer=>HEAP32[pointer>>2]:pointer=>HEAPU32[pointer>>2];default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};var __embind_register_integer=(primitiveType,name,size,minRange,maxRange)=>{name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var fromWireType=value=>value;if(minRange===0){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift}var isUnsignedType=name.includes("unsigned");var checkAssertions=(value,toTypeName)=>{};var toWireType;if(isUnsignedType){toWireType=function(destructors,value){checkAssertions(value,this.name);return value>>>0}}else{toWireType=function(destructors,value){checkAssertions(value,this.name);return value}}registerType(primitiveType,{name:name,fromWireType:fromWireType,toWireType:toWireType,argPackAdvance:GenericWireTypeSize,readValueFromPointer:integerReadValueFromPointer(name,size,minRange!==0),destructorFunction:null})};var __embind_register_memory_view=(rawType,dataTypeIndex,name)=>{var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){var size=HEAPU32[handle>>2];var data=HEAPU32[handle+4>>2];return new TA(HEAP8.buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,fromWireType:decodeMemoryView,argPackAdvance:GenericWireTypeSize,readValueFromPointer:decodeMemoryView},{ignoreDuplicateRegistrations:true})};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx,maxBytesToRead)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var __embind_register_std_string=(rawType,name)=>{name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,fromWireType(value){var length=HEAPU32[value>>2];var payload=value+4;var str;if(stdStringIsUTF8){var decodeStartPtr=payload;for(var i=0;i<=length;++i){var currentBytePtr=payload+i;if(i==length||HEAPU8[currentBytePtr]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+i]=charCode}}else{for(var i=0;i{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr};var lengthBytesUTF16=str=>str.length*2;var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr};var lengthBytesUTF32=str=>{var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len};var __embind_register_std_wstring=(rawType,charSize,name)=>{name=readLatin1String(name);var decodeString,encodeString,readCharAt,lengthBytesUTF;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16;readCharAt=pointer=>HEAPU16[pointer>>1]}else if(charSize===4){decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32;readCharAt=pointer=>HEAPU32[pointer>>2]}registerType(rawType,{name:name,fromWireType:value=>{var length=HEAPU32[value>>2];var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||readCharAt(currentBytePtr)==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},toWireType:(destructors,value)=>{if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length/charSize;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction(ptr){_free(ptr)}})};var __embind_register_value_object=(rawType,name,constructorSignature,rawConstructor,destructorSignature,rawDestructor)=>{structRegistrations[rawType]={name:readLatin1String(name),rawConstructor:embind__requireFunction(constructorSignature,rawConstructor),rawDestructor:embind__requireFunction(destructorSignature,rawDestructor),fields:[]}};var __embind_register_value_object_field=(structType,fieldName,getterReturnType,getterSignature,getter,getterContext,setterArgumentType,setterSignature,setter,setterContext)=>{structRegistrations[structType].fields.push({fieldName:readLatin1String(fieldName),getterReturnType:getterReturnType,getter:embind__requireFunction(getterSignature,getter),getterContext:getterContext,setterArgumentType:setterArgumentType,setter:embind__requireFunction(setterSignature,setter),setterContext:setterContext})};var __embind_register_void=(rawType,name)=>{name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,argPackAdvance:0,fromWireType:()=>undefined,toWireType:(destructors,o)=>undefined})};var __emscripten_memcpy_js=(dest,src,num)=>HEAPU8.copyWithin(dest,src,src+num);var emval_returnValue=(returnType,destructorsRef,handle)=>{var destructors=[];var result=returnType["toWireType"](destructors,handle);if(destructors.length){HEAPU32[destructorsRef>>2]=Emval.toHandle(destructors)}return result};var __emval_as=(handle,returnType,destructorsRef)=>{handle=Emval.toValue(handle);returnType=requireRegisteredType(returnType,"emval::as");return emval_returnValue(returnType,destructorsRef,handle)};var emval_methodCallers=[];var __emval_call=(caller,handle,destructorsRef,args)=>{caller=emval_methodCallers[caller];handle=Emval.toValue(handle);return caller(null,handle,destructorsRef,args)};var emval_symbols={};var getStringOrSymbol=address=>{var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}return symbol};var __emval_call_method=(caller,objHandle,methodName,destructorsRef,args)=>{caller=emval_methodCallers[caller];objHandle=Emval.toValue(objHandle);methodName=getStringOrSymbol(methodName);return caller(objHandle,objHandle[methodName],destructorsRef,args)};var emval_get_global=()=>{if(typeof globalThis=="object"){return globalThis}return function(){return Function}()("return this")()};var __emval_get_global=name=>{if(name===0){return Emval.toHandle(emval_get_global())}else{name=getStringOrSymbol(name);return Emval.toHandle(emval_get_global()[name])}};var emval_addMethodCaller=caller=>{var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id};var emval_lookupTypes=(argCount,argTypes)=>{var a=new Array(argCount);for(var i=0;i>2],"parameter "+i)}return a};var reflectConstruct=Reflect.construct;var __emval_get_method_caller=(argCount,argTypes,kind)=>{var types=emval_lookupTypes(argCount,argTypes);var retType=types.shift();argCount--;var functionBody=`return function (obj, func, destructorsRef, args) {\n`;var offset=0;var argsList=[];if(kind===0){argsList.push("obj")}var params=["retType"];var args=[retType];for(var i=0;it.name).join(", ")}) => ${retType.name}>`;return emval_addMethodCaller(createNamedFunction(functionName,invokerFunction))};var __emval_get_module_property=name=>{name=getStringOrSymbol(name);return Emval.toHandle(Module[name])};var __emval_get_property=(handle,key)=>{handle=Emval.toValue(handle);key=Emval.toValue(key);return Emval.toHandle(handle[key])};var __emval_incref=handle=>{if(handle>9){emval_handles[handle+1]+=1}};var __emval_new_cstring=v=>Emval.toHandle(getStringOrSymbol(v));var __emval_run_destructors=handle=>{var destructors=Emval.toValue(handle);runDestructors(destructors);__emval_decref(handle)};var getHeapMax=()=>2147483648;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var _fd_close=fd=>52;var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);return 70}var printCharBuffers=[null,[],[]];var printChar=(stream,curr)=>{var buffer=printCharBuffers[stream];if(curr===0||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer,0));buffer.length=0}else{buffer.push(curr)}};var _fd_write=(fd,iov,iovcnt,pnum)=>{var num=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;for(var j=0;j>2]=num;return 0};InternalError=Module["InternalError"]=class InternalError extends Error{constructor(message){super(message);this.name="InternalError"}};embind_init_charCodes();BindingError=Module["BindingError"]=class BindingError extends Error{constructor(message){super(message);this.name="BindingError"}};init_ClassHandle();init_embind();init_RegisteredPointer();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");init_emval();var wasmImports={K:___cxa_throw,G:__abort_js,s:__embind_finalize_value_object,C:__embind_register_bigint,I:__embind_register_bool,w:__embind_register_class,v:__embind_register_class_constructor,d:__embind_register_class_function,m:__embind_register_constant,H:__embind_register_emval,o:__embind_register_enum,a:__embind_register_enum_value,A:__embind_register_float,i:__embind_register_function,l:__embind_register_integer,f:__embind_register_memory_view,z:__embind_register_std_string,u:__embind_register_std_wstring,t:__embind_register_value_object,c:__embind_register_value_object_field,J:__embind_register_void,F:__emscripten_memcpy_js,n:__emval_as,q:__emval_call,p:__emval_call_method,b:__emval_decref,x:__emval_get_global,j:__emval_get_method_caller,r:__emval_get_module_property,g:__emval_get_property,k:__emval_incref,h:__emval_new_cstring,e:__emval_run_destructors,D:_emscripten_resize_heap,E:_fd_close,B:_fd_seek,y:_fd_write};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["M"])();var ___getTypeName=a0=>(___getTypeName=wasmExports["N"])(a0);var _malloc=a0=>(_malloc=wasmExports["O"])(a0);var _free=a0=>(_free=wasmExports["Q"])(a0);var ___cxa_is_pointer_type=a0=>(___cxa_is_pointer_type=wasmExports["R"])(a0);var dynCall_jiji=Module["dynCall_jiji"]=(a0,a1,a2,a3,a4)=>(dynCall_jiji=Module["dynCall_jiji"]=wasmExports["S"])(a0,a1,a2,a3,a4);var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve(Module);Module["onRuntimeInitialized"]?.();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run();moduleRtn=readyPromise; + + + return moduleRtn; +} +); +})(); +if (typeof exports === 'object' && typeof module === 'object') + module.exports = BASIS; +else if (typeof define === 'function' && define['amd']) + define([], () => BASIS); diff --git a/js/lib/jsm/libs/basis/basis_transcoder.wasm b/js/lib/jsm/libs/basis/basis_transcoder.wasm new file mode 100644 index 0000000..bc64682 Binary files /dev/null and b/js/lib/jsm/libs/basis/basis_transcoder.wasm differ diff --git a/js/lib/jsm/libs/ktx-parse.module.js b/js/lib/jsm/libs/ktx-parse.module.js new file mode 100644 index 0000000..3593d43 --- /dev/null +++ b/js/lib/jsm/libs/ktx-parse.module.js @@ -0,0 +1 @@ +const t=0,e=1,n=2,i=3,s=0,a=0,r=2,o=0,l=1,f=160,h=161,U=162,c=163,_=166,p=0,g=1,y=0,x=1,u=2,b=3,d=4,w=5,m=6,D=7,B=8,L=9,v=10,A=11,k=12,V=13,I=14,S=15,F=16,O=17,E=18,T=0,C=1,M=2,P=3,z=4,W=5,H=6,N=7,K=8,X=9,R=10,Y=11,j=0,q=1,G=2,J=13,Q=14,Z=15,$=128,tt=64,et=32,nt=16,it=0,st=1,at=2,rt=3,ot=4,lt=5,ft=6,ht=7,Ut=8,ct=9,_t=10,pt=13,gt=14,yt=15,xt=16,ut=17,bt=20,dt=21,wt=22,mt=23,Dt=24,Bt=27,Lt=28,vt=29,At=30,kt=31,Vt=34,It=35,St=36,Ft=37,Ot=38,Et=41,Tt=42,Ct=43,Mt=44,Pt=45,zt=48,Wt=49,Ht=50,Nt=58,Kt=59,Xt=62,Rt=63,Yt=64,jt=65,qt=68,Gt=69,Jt=70,Qt=71,Zt=74,$t=75,te=76,ee=77,ne=78,ie=81,se=82,ae=83,re=84,oe=85,le=88,fe=89,he=90,Ue=91,ce=92,_e=95,pe=96,ge=97,ye=98,xe=99,ue=100,be=101,de=102,we=103,me=104,De=105,Be=106,Le=107,ve=108,Ae=109,ke=110,Ve=111,Ie=112,Se=113,Fe=114,Oe=115,Ee=116,Te=117,Ce=118,Me=119,Pe=120,ze=121,We=122,He=123,Ne=124,Ke=125,Xe=126,Re=127,Ye=128,je=129,qe=130,Ge=131,Je=132,Qe=133,Ze=134,$e=135,tn=136,en=137,nn=138,sn=139,an=140,rn=141,on=142,ln=143,fn=144,hn=145,Un=146,cn=147,_n=148,pn=149,gn=150,yn=151,xn=152,un=153,bn=154,dn=155,wn=156,mn=157,Dn=158,Bn=159,Ln=160,vn=161,An=162,kn=163,Vn=164,In=165,Sn=166,Fn=167,On=168,En=169,Tn=170,Cn=171,Mn=172,Pn=173,zn=174,Wn=175,Hn=176,Nn=177,Kn=178,Xn=179,Rn=180,Yn=181,jn=182,qn=183,Gn=184,Jn=1000156007,Qn=1000156008,Zn=1000156009,$n=1000156010,ti=1000156011,ei=1000156017,ni=1000156018,ii=1000156019,si=1000156020,ai=1000156021,ri=1000054e3,oi=1000054001,li=1000054002,fi=1000054003,hi=1000054004,Ui=1000054005,ci=1000054006,_i=1000054007,pi=1000066e3,gi=1000066001,yi=1000066002,xi=1000066003,ui=1000066004,bi=1000066005,di=1000066006,wi=1000066007,mi=1000066008,Di=1000066009,Bi=1000066010,Li=1000066011,vi=1000066012,Ai=1000066013,ki=100034e4,Vi=1000340001;class Ii{constructor(){this.vkFormat=0,this.typeSize=1,this.pixelWidth=0,this.pixelHeight=0,this.pixelDepth=0,this.layerCount=0,this.faceCount=1,this.supercompressionScheme=0,this.levels=[],this.dataFormatDescriptor=[{vendorId:0,descriptorType:0,descriptorBlockSize:0,versionNumber:2,colorModel:0,colorPrimaries:1,transferFunction:2,flags:0,texelBlockDimension:[0,0,0,0],bytesPlane:[0,0,0,0,0,0,0,0],samples:[]}],this.keyValue={},this.globalData=null}}class Si{constructor(t,e,n,i){this._dataView=void 0,this._littleEndian=void 0,this._offset=void 0,this._dataView=new DataView(t.buffer,t.byteOffset+e,n),this._littleEndian=i,this._offset=0}_nextUint8(){const t=this._dataView.getUint8(this._offset);return this._offset+=1,t}_nextUint16(){const t=this._dataView.getUint16(this._offset,this._littleEndian);return this._offset+=2,t}_nextUint32(){const t=this._dataView.getUint32(this._offset,this._littleEndian);return this._offset+=4,t}_nextUint64(){const t=this._dataView.getUint32(this._offset,this._littleEndian)+2**32*this._dataView.getUint32(this._offset+4,this._littleEndian);return this._offset+=8,t}_nextInt32(){const t=this._dataView.getInt32(this._offset,this._littleEndian);return this._offset+=4,t}_nextUint8Array(t){const e=new Uint8Array(this._dataView.buffer,this._dataView.byteOffset+this._offset,t);return this._offset+=t,e}_skip(t){return this._offset+=t,this}_scan(t,e){void 0===e&&(e=0);const n=this._offset;let i=0;for(;this._dataView.getUint8(this._offset)!==e&&i0?U+a.byteLength:0;c%8&&(c+=8-c%8);const _=[],p=new DataView(new ArrayBuffer(3*t.levels.length*8)),g=new Uint32Array(t.levels.length);let y=0;0===t.supercompressionScheme&&(y=function(t,e){const n=Math.max(t,4),i=Math.min(t,4);let s=n;for(;s%i!=0;)s+=n;return s}(function(t){return t.levels[0].levelData.byteLength/function(t,e){let n=1;const i=[t.pixelWidth,t.pixelHeight,t.pixelDepth],s=function(t){const[e,n,i]=t.dataFormatDescriptor[0].texelBlockDimension;return[e+1,n+1,i+1]}(t);for(let t=0;t<3;t++)if(i[t]>0){const e=Math.ceil(Math.floor(i[t]*Math.pow(2,-0))/s[t]);n*=Math.max(1,e)}return t.layerCount>0&&(n*=t.layerCount),t.faceCount>0&&(n*=t.faceCount),n}(t)}(t)));let x=(c||U+a.byteLength)+n.byteLength;for(let e=t.levels.length-1;e>=0;e--){if(x%y){const t=Mi(x,y);_.push(new Uint8Array(t)),x+=t}const n=t.levels[e];_.push(n.levelData),g[e]=x,x+=n.levelData.byteLength}for(let e=0;e0?c:0),!0),b.setBigUint64(60,BigInt(n.byteLength),!0),new Uint8Array(Ci([new Uint8Array(Oi).buffer,u,p.buffer,o,a,c>0?new ArrayBuffer(c-(U+a.byteLength)):new ArrayBuffer(0),n,..._]))}export{Z as KHR_DF_CHANNEL_RGBSDA_ALPHA,G as KHR_DF_CHANNEL_RGBSDA_BLUE,Q as KHR_DF_CHANNEL_RGBSDA_DEPTH,q as KHR_DF_CHANNEL_RGBSDA_GREEN,j as KHR_DF_CHANNEL_RGBSDA_RED,J as KHR_DF_CHANNEL_RGBSDA_STENCIL,g as KHR_DF_FLAG_ALPHA_PREMULTIPLIED,p as KHR_DF_FLAG_ALPHA_STRAIGHT,s as KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT,U as KHR_DF_MODEL_ASTC,f as KHR_DF_MODEL_ETC1,c as KHR_DF_MODEL_ETC1S,h as KHR_DF_MODEL_ETC2,l as KHR_DF_MODEL_RGBSDA,_ as KHR_DF_MODEL_UASTC,o as KHR_DF_MODEL_UNSPECIFIED,H as KHR_DF_PRIMARIES_ACES,N as KHR_DF_PRIMARIES_ACESCC,Y as KHR_DF_PRIMARIES_ADOBERGB,z as KHR_DF_PRIMARIES_BT2020,M as KHR_DF_PRIMARIES_BT601_EBU,P as KHR_DF_PRIMARIES_BT601_SMPTE,C as KHR_DF_PRIMARIES_BT709,W as KHR_DF_PRIMARIES_CIEXYZ,R as KHR_DF_PRIMARIES_DISPLAYP3,K as KHR_DF_PRIMARIES_NTSC1953,X as KHR_DF_PRIMARIES_PAL525,T as KHR_DF_PRIMARIES_UNSPECIFIED,et as KHR_DF_SAMPLE_DATATYPE_EXPONENT,$ as KHR_DF_SAMPLE_DATATYPE_FLOAT,nt as KHR_DF_SAMPLE_DATATYPE_LINEAR,tt as KHR_DF_SAMPLE_DATATYPE_SIGNED,F as KHR_DF_TRANSFER_ACESCC,O as KHR_DF_TRANSFER_ACESCCT,E as KHR_DF_TRANSFER_ADOBERGB,D as KHR_DF_TRANSFER_BT1886,k as KHR_DF_TRANSFER_DCIP3,L as KHR_DF_TRANSFER_HLG_EOTF,B as KHR_DF_TRANSFER_HLG_OETF,b as KHR_DF_TRANSFER_ITU,x as KHR_DF_TRANSFER_LINEAR,d as KHR_DF_TRANSFER_NTSC,I as KHR_DF_TRANSFER_PAL625_EOTF,V as KHR_DF_TRANSFER_PAL_OETF,v as KHR_DF_TRANSFER_PQ_EOTF,A as KHR_DF_TRANSFER_PQ_OETF,w as KHR_DF_TRANSFER_SLOG,m as KHR_DF_TRANSFER_SLOG2,u as KHR_DF_TRANSFER_SRGB,S as KHR_DF_TRANSFER_ST240,y as KHR_DF_TRANSFER_UNSPECIFIED,a as KHR_DF_VENDORID_KHRONOS,r as KHR_DF_VERSION,e as KHR_SUPERCOMPRESSION_BASISLZ,t as KHR_SUPERCOMPRESSION_NONE,i as KHR_SUPERCOMPRESSION_ZLIB,n as KHR_SUPERCOMPRESSION_ZSTD,Ii as KTX2Container,Ut as VK_FORMAT_A1R5G5B5_UNORM_PACK16,Gt as VK_FORMAT_A2B10G10R10_SINT_PACK32,jt as VK_FORMAT_A2B10G10R10_SNORM_PACK32,qt as VK_FORMAT_A2B10G10R10_UINT_PACK32,Yt as VK_FORMAT_A2B10G10R10_UNORM_PACK32,Rt as VK_FORMAT_A2R10G10B10_SINT_PACK32,Kt as VK_FORMAT_A2R10G10B10_SNORM_PACK32,Xt as VK_FORMAT_A2R10G10B10_UINT_PACK32,Nt as VK_FORMAT_A2R10G10B10_UNORM_PACK32,Vi as VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT,ki as VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT,Li as VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT,Rn as VK_FORMAT_ASTC_10x10_SRGB_BLOCK,Xn as VK_FORMAT_ASTC_10x10_UNORM_BLOCK,mi as VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT,zn as VK_FORMAT_ASTC_10x5_SRGB_BLOCK,Pn as VK_FORMAT_ASTC_10x5_UNORM_BLOCK,Di as VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT,Hn as VK_FORMAT_ASTC_10x6_SRGB_BLOCK,Wn as VK_FORMAT_ASTC_10x6_UNORM_BLOCK,Bi as VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT,Kn as VK_FORMAT_ASTC_10x8_SRGB_BLOCK,Nn as VK_FORMAT_ASTC_10x8_UNORM_BLOCK,vi as VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT,jn as VK_FORMAT_ASTC_12x10_SRGB_BLOCK,Yn as VK_FORMAT_ASTC_12x10_UNORM_BLOCK,Ai as VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT,Gn as VK_FORMAT_ASTC_12x12_SRGB_BLOCK,qn as VK_FORMAT_ASTC_12x12_UNORM_BLOCK,pi as VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT,Dn as VK_FORMAT_ASTC_4x4_SRGB_BLOCK,mn as VK_FORMAT_ASTC_4x4_UNORM_BLOCK,gi as VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT,Ln as VK_FORMAT_ASTC_5x4_SRGB_BLOCK,Bn as VK_FORMAT_ASTC_5x4_UNORM_BLOCK,yi as VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT,An as VK_FORMAT_ASTC_5x5_SRGB_BLOCK,vn as VK_FORMAT_ASTC_5x5_UNORM_BLOCK,xi as VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT,Vn as VK_FORMAT_ASTC_6x5_SRGB_BLOCK,kn as VK_FORMAT_ASTC_6x5_UNORM_BLOCK,ui as VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT,Sn as VK_FORMAT_ASTC_6x6_SRGB_BLOCK,In as VK_FORMAT_ASTC_6x6_UNORM_BLOCK,bi as VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT,On as VK_FORMAT_ASTC_8x5_SRGB_BLOCK,Fn as VK_FORMAT_ASTC_8x5_UNORM_BLOCK,di as VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT,Tn as VK_FORMAT_ASTC_8x6_SRGB_BLOCK,En as VK_FORMAT_ASTC_8x6_UNORM_BLOCK,wi as VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT,Mn as VK_FORMAT_ASTC_8x8_SRGB_BLOCK,Cn as VK_FORMAT_ASTC_8x8_UNORM_BLOCK,We as VK_FORMAT_B10G11R11_UFLOAT_PACK32,ti as VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,ai as VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,rt as VK_FORMAT_B4G4R4A4_UNORM_PACK16,ht as VK_FORMAT_B5G5R5A1_UNORM_PACK16,lt as VK_FORMAT_B5G6R5_UNORM_PACK16,Wt as VK_FORMAT_B8G8R8A8_SINT,Pt as VK_FORMAT_B8G8R8A8_SNORM,Ht as VK_FORMAT_B8G8R8A8_SRGB,zt as VK_FORMAT_B8G8R8A8_UINT,Mt as VK_FORMAT_B8G8R8A8_UNORM,It as VK_FORMAT_B8G8R8_SINT,kt as VK_FORMAT_B8G8R8_SNORM,St as VK_FORMAT_B8G8R8_SRGB,Vt as VK_FORMAT_B8G8R8_UINT,At as VK_FORMAT_B8G8R8_UNORM,Ze as VK_FORMAT_BC1_RGBA_SRGB_BLOCK,Qe as VK_FORMAT_BC1_RGBA_UNORM_BLOCK,Je as VK_FORMAT_BC1_RGB_SRGB_BLOCK,Ge as VK_FORMAT_BC1_RGB_UNORM_BLOCK,tn as VK_FORMAT_BC2_SRGB_BLOCK,$e as VK_FORMAT_BC2_UNORM_BLOCK,nn as VK_FORMAT_BC3_SRGB_BLOCK,en as VK_FORMAT_BC3_UNORM_BLOCK,an as VK_FORMAT_BC4_SNORM_BLOCK,sn as VK_FORMAT_BC4_UNORM_BLOCK,on as VK_FORMAT_BC5_SNORM_BLOCK,rn as VK_FORMAT_BC5_UNORM_BLOCK,fn as VK_FORMAT_BC6H_SFLOAT_BLOCK,ln as VK_FORMAT_BC6H_UFLOAT_BLOCK,Un as VK_FORMAT_BC7_SRGB_BLOCK,hn as VK_FORMAT_BC7_UNORM_BLOCK,Ne as VK_FORMAT_D16_UNORM,Ye as VK_FORMAT_D16_UNORM_S8_UINT,je as VK_FORMAT_D24_UNORM_S8_UINT,Xe as VK_FORMAT_D32_SFLOAT,qe as VK_FORMAT_D32_SFLOAT_S8_UINT,He as VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,wn as VK_FORMAT_EAC_R11G11_SNORM_BLOCK,dn as VK_FORMAT_EAC_R11G11_UNORM_BLOCK,bn as VK_FORMAT_EAC_R11_SNORM_BLOCK,un as VK_FORMAT_EAC_R11_UNORM_BLOCK,gn as VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,pn as VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,xn as VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,yn as VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,_n as VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,cn as VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,$n as VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,si as VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,hi as VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG,ri as VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG,Ui as VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG,oi as VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG,ci as VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG,li as VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG,_i as VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG,fi as VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG,Zn as VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,Qn as VK_FORMAT_R10X6G10X6_UNORM_2PACK16,Jn as VK_FORMAT_R10X6_UNORM_PACK16,ii as VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,ni as VK_FORMAT_R12X4G12X4_UNORM_2PACK16,ei as VK_FORMAT_R12X4_UNORM_PACK16,ge as VK_FORMAT_R16G16B16A16_SFLOAT,pe as VK_FORMAT_R16G16B16A16_SINT,ce as VK_FORMAT_R16G16B16A16_SNORM,_e as VK_FORMAT_R16G16B16A16_UINT,Ue as VK_FORMAT_R16G16B16A16_UNORM,he as VK_FORMAT_R16G16B16_SFLOAT,fe as VK_FORMAT_R16G16B16_SINT,oe as VK_FORMAT_R16G16B16_SNORM,le as VK_FORMAT_R16G16B16_UINT,re as VK_FORMAT_R16G16B16_UNORM,ae as VK_FORMAT_R16G16_SFLOAT,se as VK_FORMAT_R16G16_SINT,ne as VK_FORMAT_R16G16_SNORM,ie as VK_FORMAT_R16G16_UINT,ee as VK_FORMAT_R16G16_UNORM,te as VK_FORMAT_R16_SFLOAT,$t as VK_FORMAT_R16_SINT,Qt as VK_FORMAT_R16_SNORM,Zt as VK_FORMAT_R16_UINT,Jt as VK_FORMAT_R16_UNORM,Ae as VK_FORMAT_R32G32B32A32_SFLOAT,ve as VK_FORMAT_R32G32B32A32_SINT,Le as VK_FORMAT_R32G32B32A32_UINT,Be as VK_FORMAT_R32G32B32_SFLOAT,De as VK_FORMAT_R32G32B32_SINT,me as VK_FORMAT_R32G32B32_UINT,we as VK_FORMAT_R32G32_SFLOAT,de as VK_FORMAT_R32G32_SINT,be as VK_FORMAT_R32G32_UINT,ue as VK_FORMAT_R32_SFLOAT,xe as VK_FORMAT_R32_SINT,ye as VK_FORMAT_R32_UINT,at as VK_FORMAT_R4G4B4A4_UNORM_PACK16,st as VK_FORMAT_R4G4_UNORM_PACK8,ft as VK_FORMAT_R5G5B5A1_UNORM_PACK16,ot as VK_FORMAT_R5G6B5_UNORM_PACK16,ze as VK_FORMAT_R64G64B64A64_SFLOAT,Pe as VK_FORMAT_R64G64B64A64_SINT,Me as VK_FORMAT_R64G64B64A64_UINT,Ce as VK_FORMAT_R64G64B64_SFLOAT,Te as VK_FORMAT_R64G64B64_SINT,Ee as VK_FORMAT_R64G64B64_UINT,Oe as VK_FORMAT_R64G64_SFLOAT,Fe as VK_FORMAT_R64G64_SINT,Se as VK_FORMAT_R64G64_UINT,Ie as VK_FORMAT_R64_SFLOAT,Ve as VK_FORMAT_R64_SINT,ke as VK_FORMAT_R64_UINT,Tt as VK_FORMAT_R8G8B8A8_SINT,Ot as VK_FORMAT_R8G8B8A8_SNORM,Ct as VK_FORMAT_R8G8B8A8_SRGB,Et as VK_FORMAT_R8G8B8A8_UINT,Ft as VK_FORMAT_R8G8B8A8_UNORM,Lt as VK_FORMAT_R8G8B8_SINT,Dt as VK_FORMAT_R8G8B8_SNORM,vt as VK_FORMAT_R8G8B8_SRGB,Bt as VK_FORMAT_R8G8B8_UINT,mt as VK_FORMAT_R8G8B8_UNORM,dt as VK_FORMAT_R8G8_SINT,ut as VK_FORMAT_R8G8_SNORM,wt as VK_FORMAT_R8G8_SRGB,bt as VK_FORMAT_R8G8_UINT,xt as VK_FORMAT_R8G8_UNORM,gt as VK_FORMAT_R8_SINT,_t as VK_FORMAT_R8_SNORM,yt as VK_FORMAT_R8_SRGB,pt as VK_FORMAT_R8_UINT,ct as VK_FORMAT_R8_UNORM,Re as VK_FORMAT_S8_UINT,it as VK_FORMAT_UNDEFINED,Ke as VK_FORMAT_X8_D24_UNORM_PACK32,Pi as read,Wi as write}; diff --git a/js/lib/jsm/libs/meshopt_decoder.module.js b/js/lib/jsm/libs/meshopt_decoder.module.js new file mode 100644 index 0000000..d0933a9 --- /dev/null +++ b/js/lib/jsm/libs/meshopt_decoder.module.js @@ -0,0 +1,178 @@ +// This file is part of meshoptimizer library and is distributed under the terms of MIT License. +// Copyright (C) 2016-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +var MeshoptDecoder = (function() { + "use strict"; + + // Built with clang version 14.0.4 + // Built from meshoptimizer 0.18 + var wasm_base = "b9H79Tebbbe8Fv9Gbb9Gvuuuuueu9Giuuub9Geueu9Giuuueuikqbeeedddillviebeoweuec:q;iekr;leDo9TW9T9VV95dbH9F9F939H79T9F9J9H229F9Jt9VV7bb8A9TW79O9V9Wt9F9KW9J9V9KW9wWVtW949c919M9MWVbeY9TW79O9V9Wt9F9KW9J9V9KW69U9KW949c919M9MWVbdE9TW79O9V9Wt9F9KW9J9V9KW69U9KW949tWG91W9U9JWbiL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9p9JtblK9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9r919HtbvL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWVT949Wbol79IV9Rbrq:P8Yqdbk;3sezu8Jjjjjbcj;eb9Rgv8Kjjjjbc9:hodnadcefal0mbcuhoaiRbbc:Ge9hmbavaialfgrad9Radz1jjjbhwcj;abad9UhoaicefhldnadTmbaoc;WFbGgocjdaocjd6EhDcbhqinaqae9pmeaDaeaq9RaqaDfae6Egkcsfgocl4cifcd4hxdndndndnaoc9WGgmTmbcbhPcehsawcjdfhzalhHinaraH9Rax6midnaraHaxfgl9RcK6mbczhoinawcj;cbfaogifgoc9WfhOdndndndndnaHaic9WfgAco4fRbbaAci4coG4ciGPlbedibkaO9cb83ibaOcwf9cb83ibxikaOalRblalRbbgAco4gCaCciSgCE86bbaocGfalclfaCfgORbbaAcl4ciGgCaCciSgCE86bbaocVfaOaCfgORbbaAcd4ciGgCaCciSgCE86bbaoc7faOaCfgORbbaAciGgAaAciSgAE86bbaoctfaOaAfgARbbalRbegOco4gCaCciSgCE86bbaoc91faAaCfgARbbaOcl4ciGgCaCciSgCE86bbaoc4faAaCfgARbbaOcd4ciGgCaCciSgCE86bbaoc93faAaCfgARbbaOciGgOaOciSgOE86bbaoc94faAaOfgARbbalRbdgOco4gCaCciSgCE86bbaoc95faAaCfgARbbaOcl4ciGgCaCciSgCE86bbaoc96faAaCfgARbbaOcd4ciGgCaCciSgCE86bbaoc97faAaCfgARbbaOciGgOaOciSgOE86bbaoc98faAaOfgORbbalRbiglco4gAaAciSgAE86bbaoc99faOaAfgORbbalcl4ciGgAaAciSgAE86bbaoc9:faOaAfgORbbalcd4ciGgAaAciSgAE86bbaocufaOaAfgoRbbalciGglalciSglE86bbaoalfhlxdkaOalRbwalRbbgAcl4gCaCcsSgCE86bbaocGfalcwfaCfgORbbaAcsGgAaAcsSgAE86bbaocVfaOaAfgORbbalRbegAcl4gCaCcsSgCE86bbaoc7faOaCfgORbbaAcsGgAaAcsSgAE86bbaoctfaOaAfgORbbalRbdgAcl4gCaCcsSgCE86bbaoc91faOaCfgORbbaAcsGgAaAcsSgAE86bbaoc4faOaAfgORbbalRbigAcl4gCaCcsSgCE86bbaoc93faOaCfgORbbaAcsGgAaAcsSgAE86bbaoc94faOaAfgORbbalRblgAcl4gCaCcsSgCE86bbaoc95faOaCfgORbbaAcsGgAaAcsSgAE86bbaoc96faOaAfgORbbalRbvgAcl4gCaCcsSgCE86bbaoc97faOaCfgORbbaAcsGgAaAcsSgAE86bbaoc98faOaAfgORbbalRbogAcl4gCaCcsSgCE86bbaoc99faOaCfgORbbaAcsGgAaAcsSgAE86bbaoc9:faOaAfgORbbalRbrglcl4gAaAcsSgAE86bbaocufaOaAfgoRbbalcsGglalcsSglE86bbaoalfhlxekaOal8Pbb83bbaOcwfalcwf8Pbb83bbalczfhlkdnaiam9pmbaiczfhoaral9RcL0mekkaiam6mialTmidnakTmbawaPfRbbhOcbhoazhiinaiawcj;cbfaofRbbgAce4cbaAceG9R7aOfgO86bbaiadfhiaocefgoak9hmbkkazcefhzaPcefgPad6hsalhHaPad9hmexvkkcbhlasceGmdxikalaxad2fhCdnakTmbcbhHcehsawcjdfhminaral9Rax6mialTmdalaxfhlawaHfRbbhOcbhoamhiinaiawcj;cbfaofRbbgAce4cbaAceG9R7aOfgO86bbaiadfhiaocefgoak9hmbkamcefhmaHcefgHad6hsaHad9hmbkaChlxikcbhocehsinaral9Rax6mdalTmealaxfhlaocefgoad6hsadao9hmbkaChlxdkcbhlasceGTmekc9:hoxikabaqad2fawcjdfakad2z1jjjb8Aawawcjdfakcufad2fadz1jjjb8Aakaqfhqalmbkc9:hoxekcbc99aral9Radcaadca0ESEhokavcj;ebf8Kjjjjbaok;yzeHu8Jjjjjbc;ae9Rgv8Kjjjjbc9:hodnaeci9UgrcHfal0mbcuhoaiRbbgwc;WeGc;Ge9hmbawcsGgDce0mbavc;abfcFecjez:jjjjb8AavcUf9cu83ibavc8Wf9cu83ibavcyf9cu83ibavcaf9cu83ibavcKf9cu83ibavczf9cu83ibav9cu83iwav9cu83ibaialfc9WfhqaicefgwarfhodnaeTmbcmcsaDceSEhkcbhxcbhmcbhDcbhicbhlindnaoaq9nmbc9:hoxikdndnawRbbgrc;Ve0mbavc;abfalarcl4cu7fcsGcitfgPydlhsaPydbhzdnarcsGgPak9pmbavaiarcu7fcsGcdtfydbaxaPEhraPThPdndnadcd9hmbabaDcetfgHaz87ebaHcdfas87ebaHclfar87ebxekabaDcdtfgHazBdbaHclfasBdbaHcwfarBdbkaxaPfhxavc;abfalcitfgHarBdbaHasBdlavaicdtfarBdbavc;abfalcefcsGglcitfgHazBdbaHarBdlaiaPfhialcefhlxdkdndnaPcsSmbamaPfaPc987fcefhmxekaocefhrao8SbbgPcFeGhHdndnaPcu9mmbarhoxekaocvfhoaHcFbGhHcrhPdninar8SbbgOcFbGaPtaHVhHaOcu9kmearcefhraPcrfgPc8J9hmbxdkkarcefhokaHce4cbaHceG9R7amfhmkdndnadcd9hmbabaDcetfgraz87ebarcdfas87ebarclfam87ebxekabaDcdtfgrazBdbarclfasBdbarcwfamBdbkavc;abfalcitfgramBdbarasBdlavaicdtfamBdbavc;abfalcefcsGglcitfgrazBdbaramBdlaicefhialcefhlxekdnarcpe0mbaxcefgOavaiaqarcsGfRbbgPcl49RcsGcdtfydbaPcz6gHEhravaiaP9RcsGcdtfydbaOaHfgsaPcsGgOEhPaOThOdndnadcd9hmbabaDcetfgzax87ebazcdfar87ebazclfaP87ebxekabaDcdtfgzaxBdbazclfarBdbazcwfaPBdbkavaicdtfaxBdbavc;abfalcitfgzarBdbazaxBdlavaicefgicsGcdtfarBdbavc;abfalcefcsGcitfgzaPBdbazarBdlavaiaHfcsGgicdtfaPBdbavc;abfalcdfcsGglcitfgraxBdbaraPBdlalcefhlaiaOfhiasaOfhxxekaxcbaoRbbgzEgAarc;:eSgrfhsazcsGhCazcl4hXdndnazcs0mbascefhOxekashOavaiaX9RcsGcdtfydbhskdndnaCmbaOcefhxxekaOhxavaiaz9RcsGcdtfydbhOkdndnarTmbaocefhrxekaocdfhrao8SbegHcFeGhPdnaHcu9kmbaocofhAaPcFbGhPcrhodninar8SbbgHcFbGaotaPVhPaHcu9kmearcefhraocrfgoc8J9hmbkaAhrxekarcefhrkaPce4cbaPceG9R7amfgmhAkdndnaXcsSmbarhPxekarcefhPar8SbbgocFeGhHdnaocu9kmbarcvfhsaHcFbGhHcrhodninaP8SbbgrcFbGaotaHVhHarcu9kmeaPcefhPaocrfgoc8J9hmbkashPxekaPcefhPkaHce4cbaHceG9R7amfgmhskdndnaCcsSmbaPhoxekaPcefhoaP8SbbgrcFeGhHdnarcu9kmbaPcvfhOaHcFbGhHcrhrdninao8SbbgPcFbGartaHVhHaPcu9kmeaocefhoarcrfgrc8J9hmbkaOhoxekaocefhokaHce4cbaHceG9R7amfgmhOkdndnadcd9hmbabaDcetfgraA87ebarcdfas87ebarclfaO87ebxekabaDcdtfgraABdbarclfasBdbarcwfaOBdbkavc;abfalcitfgrasBdbaraABdlavaicdtfaABdbavc;abfalcefcsGcitfgraOBdbarasBdlavaicefgicsGcdtfasBdbavc;abfalcdfcsGcitfgraABdbaraOBdlavaiazcz6aXcsSVfgicsGcdtfaOBdbaiaCTaCcsSVfhialcifhlkawcefhwalcsGhlaicsGhiaDcifgDae6mbkkcbc99aoaqSEhokavc;aef8Kjjjjbaok:llevu8Jjjjjbcz9Rhvc9:hodnaecvfal0mbcuhoaiRbbc;:eGc;qe9hmbav9cb83iwaicefhraialfc98fhwdnaeTmbdnadcdSmbcbhDindnaraw6mbc9:skarcefhoar8SbbglcFeGhidndnalcu9mmbaohrxekarcvfhraicFbGhicrhldninao8SbbgdcFbGaltaiVhiadcu9kmeaocefhoalcrfglc8J9hmbxdkkaocefhrkabaDcdtfaicd4cbaice4ceG9R7avcwfaiceGcdtVgoydbfglBdbaoalBdbaDcefgDae9hmbxdkkcbhDindnaraw6mbc9:skarcefhoar8SbbglcFeGhidndnalcu9mmbaohrxekarcvfhraicFbGhicrhldninao8SbbgdcFbGaltaiVhiadcu9kmeaocefhoalcrfglc8J9hmbxdkkaocefhrkabaDcetfaicd4cbaice4ceG9R7avcwfaiceGcdtVgoydbfgl87ebaoalBdbaDcefgDae9hmbkkcbc99arawSEhokaok:Lvoeue99dud99eud99dndnadcl9hmbaeTmeindndnabcdfgd8Sbb:Yab8Sbbgi:Ygl:l:tabcefgv8Sbbgo:Ygr:l:tgwJbb;:9cawawNJbbbbawawJbbbb9GgDEgq:mgkaqaicb9iEalMgwawNakaqaocb9iEarMgqaqNMM:r:vglNJbbbZJbbb:;aDEMgr:lJbbb9p9DTmbar:Ohixekcjjjj94hikadai86bbdndnaqalNJbbbZJbbb:;aqJbbbb9GEMgq:lJbbb9p9DTmbaq:Ohdxekcjjjj94hdkavad86bbdndnawalNJbbbZJbbb:;awJbbbb9GEMgw:lJbbb9p9DTmbaw:Ohdxekcjjjj94hdkabad86bbabclfhbaecufgembxdkkaeTmbindndnabclfgd8Ueb:Yab8Uebgi:Ygl:l:tabcdfgv8Uebgo:Ygr:l:tgwJb;:FSawawNJbbbbawawJbbbb9GgDEgq:mgkaqaicb9iEalMgwawNakaqaocb9iEarMgqaqNMM:r:vglNJbbbZJbbb:;aDEMgr:lJbbb9p9DTmbar:Ohixekcjjjj94hikadai87ebdndnaqalNJbbbZJbbb:;aqJbbbb9GEMgq:lJbbb9p9DTmbaq:Ohdxekcjjjj94hdkavad87ebdndnawalNJbbbZJbbb:;awJbbbb9GEMgw:lJbbb9p9DTmbaw:Ohdxekcjjjj94hdkabad87ebabcwfhbaecufgembkkk;siliui99iue99dnaeTmbcbhiabhlindndnJ;Zl81Zalcof8UebgvciV:Y:vgoal8Ueb:YNgrJb;:FSNJbbbZJbbb:;arJbbbb9GEMgw:lJbbb9p9DTmbaw:OhDxekcjjjj94hDkalclf8Uebhqalcdf8UebhkabavcefciGaiVcetfaD87ebdndnaoak:YNgwJb;:FSNJbbbZJbbb:;awJbbbb9GEMgx:lJbbb9p9DTmbax:Ohkxekcjjjj94hkkabavcdfciGaiVcetfak87ebdndnaoaq:YNgoJb;:FSNJbbbZJbbb:;aoJbbbb9GEMgx:lJbbb9p9DTmbax:Ohqxekcjjjj94hqkabavcufciGaiVcetfaq87ebdndnJbbjZararN:tawawN:taoaoN:tgrJbbbbarJbbbb9GE:rJb;:FSNJbbbZMgr:lJbbb9p9DTmbar:Ohqxekcjjjj94hqkabavciGaiVcetfaq87ebalcwfhlaiclfhiaecufgembkkk9mbdnadcd4ae2geTmbinababydbgdcwtcw91:Yadce91cjjj;8ifcjjj98G::NUdbabclfhbaecufgembkkk9teiucbcbydj1jjbgeabcifc98GfgbBdj1jjbdndnabZbcztgd9nmbcuhiabad9RcFFifcz4nbcuSmekaehikaik;LeeeudndnaeabVciGTmbabhixekdndnadcz9pmbabhixekabhiinaiaeydbBdbaiclfaeclfydbBdbaicwfaecwfydbBdbaicxfaecxfydbBdbaiczfhiaeczfheadc9Wfgdcs0mbkkadcl6mbinaiaeydbBdbaeclfheaiclfhiadc98fgdci0mbkkdnadTmbinaiaeRbb86bbaicefhiaecefheadcufgdmbkkabk;aeedudndnabciGTmbabhixekaecFeGc:b:c:ew2hldndnadcz9pmbabhixekabhiinaialBdbaicxfalBdbaicwfalBdbaiclfalBdbaiczfhiadc9Wfgdcs0mbkkadcl6mbinaialBdbaiclfhiadc98fgdci0mbkkdnadTmbinaiae86bbaicefhiadcufgdmbkkabkkkebcjwklz9Kbb"; + var wasm_simd = "b9H79TebbbeKl9Gbb9Gvuuuuueu9Giuuub9Geueuikqbbebeedddilve9Weeeviebeoweuec:q;Aekr;leDo9TW9T9VV95dbH9F9F939H79T9F9J9H229F9Jt9VV7bb8A9TW79O9V9Wt9F9KW9J9V9KW9wWVtW949c919M9MWVbdY9TW79O9V9Wt9F9KW9J9V9KW69U9KW949c919M9MWVblE9TW79O9V9Wt9F9KW9J9V9KW69U9KW949tWG91W9U9JWbvL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9p9JtboK9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9r919HtbrL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWVT949Wbwl79IV9RbDq;t9tqlbzik9:evu8Jjjjjbcz9Rhbcbheincbhdcbhiinabcwfadfaicjuaead4ceGglE86bbaialfhiadcefgdcw9hmbkaec:q:yjjbfai86bbaecitc:q1jjbfab8Piw83ibaecefgecjd9hmbkk;h8JlHud97euo978Jjjjjbcj;kb9Rgv8Kjjjjbc9:hodnadcefal0mbcuhoaiRbbc:Ge9hmbavaialfgrad9Rad;8qbbcj;abad9UhoaicefhldnadTmbaoc;WFbGgocjdaocjd6EhwcbhDinaDae9pmeawaeaD9RaDawfae6Egqcsfgoc9WGgkci2hxakcethmaocl4cifcd4hPabaDad2fhscbhzdnincehHalhOcbhAdninaraO9RaP6miavcj;cbfaAak2fhCaOaPfhlcbhidnakc;ab6mbaral9Rc;Gb6mbcbhoinaCaofhidndndndndnaOaoco4fRbbgXciGPlbedibkaipxbbbbbbbbbbbbbbbbpklbxikaialpbblalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLgQcdp:meaQpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogLpxiiiiiiiiiiiiiiiip8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklbalclfaYpQbfaKc:q:yjjbfRbbfhlxdkaialpbbwalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogLpxssssssssssssssssp8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklbalcwfaYpQbfaKc:q:yjjbfRbbfhlxekaialpbbbpklbalczfhlkdndndndndnaXcd4ciGPlbedibkaipxbbbbbbbbbbbbbbbbpklzxikaialpbblalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLgQcdp:meaQpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogLpxiiiiiiiiiiiiiiiip8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklzalclfaYpQbfaKc:q:yjjbfRbbfhlxdkaialpbbwalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogLpxssssssssssssssssp8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklzalcwfaYpQbfaKc:q:yjjbfRbbfhlxekaialpbbbpklzalczfhlkdndndndndnaXcl4ciGPlbedibkaipxbbbbbbbbbbbbbbbbpklaxikaialpbblalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLgQcdp:meaQpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogLpxiiiiiiiiiiiiiiiip8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklaalclfaYpQbfaKc:q:yjjbfRbbfhlxdkaialpbbwalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogLpxssssssssssssssssp8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklaalcwfaYpQbfaKc:q:yjjbfRbbfhlxekaialpbbbpklaalczfhlkdndndndndnaXco4Plbedibkaipxbbbbbbbbbbbbbbbbpkl8WxikaialpbblalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLgQcdp:meaQpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogLpxiiiiiiiiiiiiiiiip8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgXcitc:q1jjbfpbibaXc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgXcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spkl8WalclfaYpQbfaXc:q:yjjbfRbbfhlxdkaialpbbwalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogLpxssssssssssssssssp8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgXcitc:q1jjbfpbibaXc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgXcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spkl8WalcwfaYpQbfaXc:q:yjjbfRbbfhlxekaialpbbbpkl8Walczfhlkaoc;abfhiaocjefak0meaihoaral9Rc;Fb0mbkkdndnaiak9pmbaici4hoinaral9RcK6mdaCaifhXdndndndndnaOaico4fRbbaocoG4ciGPlbedibkaXpxbbbbbbbbbbbbbbbbpklbxikaXalpbblalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLgQcdp:meaQpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogLpxiiiiiiiiiiiiiiiip8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklbalclfaYpQbfaKc:q:yjjbfRbbfhlxdkaXalpbbwalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogLpxssssssssssssssssp8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklbalcwfaYpQbfaKc:q:yjjbfRbbfhlxekaXalpbbbpklbalczfhlkaocdfhoaiczfgiak6mbkkalTmbaAci6hHalhOaAcefgohAaoclSmdxekkcbhlaHceGmdkdnakTmbavcjdfazfhiavazfpbdbhYcbhXinaiavcj;cbfaXfgopblbgLcep9TaLpxeeeeeeeeeeeeeeeegQp9op9Hp9rgLaoakfpblbg8Acep9Ta8AaQp9op9Hp9rg8ApmbzeHdOiAlCvXoQrLgEaoamfpblbg3cep9Ta3aQp9op9Hp9rg3aoaxfpblbg5cep9Ta5aQp9op9Hp9rg5pmbzeHdOiAlCvXoQrLg8EpmbezHdiOAlvCXorQLgQaQpmbedibedibedibediaYp9UgYp9AdbbaiadfgoaYaQaQpmlvorlvorlvorlvorp9UgYp9AdbbaoadfgoaYaQaQpmwDqkwDqkwDqkwDqkp9UgYp9AdbbaoadfgoaYaQaQpmxmPsxmPsxmPsxmPsp9UgYp9AdbbaoadfgoaYaEa8EpmwDKYqk8AExm35Ps8E8FgQaQpmbedibedibedibedip9UgYp9AdbbaoadfgoaYaQaQpmlvorlvorlvorlvorp9UgYp9AdbbaoadfgoaYaQaQpmwDqkwDqkwDqkwDqkp9UgYp9AdbbaoadfgoaYaQaQpmxmPsxmPsxmPsxmPsp9UgYp9AdbbaoadfgoaYaLa8ApmwKDYq8AkEx3m5P8Es8FgLa3a5pmwKDYq8AkEx3m5P8Es8Fg8ApmbezHdiOAlvCXorQLgQaQpmbedibedibedibedip9UgYp9AdbbaoadfgoaYaQaQpmlvorlvorlvorlvorp9UgYp9AdbbaoadfgoaYaQaQpmwDqkwDqkwDqkwDqkp9UgYp9AdbbaoadfgoaYaQaQpmxmPsxmPsxmPsxmPsp9UgYp9AdbbaoadfgoaYaLa8ApmwDKYqk8AExm35Ps8E8FgQaQpmbedibedibedibedip9UgYp9AdbbaoadfgoaYaQaQpmlvorlvorlvorlvorp9UgYp9AdbbaoadfgoaYaQaQpmwDqkwDqkwDqkwDqkp9UgYp9AdbbaoadfgoaYaQaQpmxmPsxmPsxmPsxmPsp9UgYp9AdbbaoadfhiaXczfgXak6mbkkazclfgzad6mbkasavcjdfaqad2;8qbbavavcjdfaqcufad2fad;8qbbaqaDfhDc9:hoalmexikkc9:hoxekcbc99aral9Radcaadca0ESEhokavcj;kbf8Kjjjjbaokwbz:bjjjbk;uzeHu8Jjjjjbc;ae9Rgv8Kjjjjbc9:hodnaeci9UgrcHfal0mbcuhoaiRbbgwc;WeGc;Ge9hmbawcsGgDce0mbavc;abfcFecje;8kbavcUf9cu83ibavc8Wf9cu83ibavcyf9cu83ibavcaf9cu83ibavcKf9cu83ibavczf9cu83ibav9cu83iwav9cu83ibaialfc9WfhqaicefgwarfhodnaeTmbcmcsaDceSEhkcbhxcbhmcbhDcbhicbhlindnaoaq9nmbc9:hoxikdndnawRbbgrc;Ve0mbavc;abfalarcl4cu7fcsGcitfgPydlhsaPydbhzdnarcsGgPak9pmbavaiarcu7fcsGcdtfydbaxaPEhraPThPdndnadcd9hmbabaDcetfgHaz87ebaHcdfas87ebaHclfar87ebxekabaDcdtfgHazBdbaHclfasBdbaHcwfarBdbkaxaPfhxavc;abfalcitfgHarBdbaHasBdlavaicdtfarBdbavc;abfalcefcsGglcitfgHazBdbaHarBdlaiaPfhialcefhlxdkdndnaPcsSmbamaPfaPc987fcefhmxekaocefhrao8SbbgPcFeGhHdndnaPcu9mmbarhoxekaocvfhoaHcFbGhHcrhPdninar8SbbgOcFbGaPtaHVhHaOcu9kmearcefhraPcrfgPc8J9hmbxdkkarcefhokaHce4cbaHceG9R7amfhmkdndnadcd9hmbabaDcetfgraz87ebarcdfas87ebarclfam87ebxekabaDcdtfgrazBdbarclfasBdbarcwfamBdbkavc;abfalcitfgramBdbarasBdlavaicdtfamBdbavc;abfalcefcsGglcitfgrazBdbaramBdlaicefhialcefhlxekdnarcpe0mbaxcefgOavaiaqarcsGfRbbgPcl49RcsGcdtfydbaPcz6gHEhravaiaP9RcsGcdtfydbaOaHfgsaPcsGgOEhPaOThOdndnadcd9hmbabaDcetfgzax87ebazcdfar87ebazclfaP87ebxekabaDcdtfgzaxBdbazclfarBdbazcwfaPBdbkavaicdtfaxBdbavc;abfalcitfgzarBdbazaxBdlavaicefgicsGcdtfarBdbavc;abfalcefcsGcitfgzaPBdbazarBdlavaiaHfcsGgicdtfaPBdbavc;abfalcdfcsGglcitfgraxBdbaraPBdlalcefhlaiaOfhiasaOfhxxekaxcbaoRbbgzEgAarc;:eSgrfhsazcsGhCazcl4hXdndnazcs0mbascefhOxekashOavaiaX9RcsGcdtfydbhskdndnaCmbaOcefhxxekaOhxavaiaz9RcsGcdtfydbhOkdndnarTmbaocefhrxekaocdfhrao8SbegHcFeGhPdnaHcu9kmbaocofhAaPcFbGhPcrhodninar8SbbgHcFbGaotaPVhPaHcu9kmearcefhraocrfgoc8J9hmbkaAhrxekarcefhrkaPce4cbaPceG9R7amfgmhAkdndnaXcsSmbarhPxekarcefhPar8SbbgocFeGhHdnaocu9kmbarcvfhsaHcFbGhHcrhodninaP8SbbgrcFbGaotaHVhHarcu9kmeaPcefhPaocrfgoc8J9hmbkashPxekaPcefhPkaHce4cbaHceG9R7amfgmhskdndnaCcsSmbaPhoxekaPcefhoaP8SbbgrcFeGhHdnarcu9kmbaPcvfhOaHcFbGhHcrhrdninao8SbbgPcFbGartaHVhHaPcu9kmeaocefhoarcrfgrc8J9hmbkaOhoxekaocefhokaHce4cbaHceG9R7amfgmhOkdndnadcd9hmbabaDcetfgraA87ebarcdfas87ebarclfaO87ebxekabaDcdtfgraABdbarclfasBdbarcwfaOBdbkavc;abfalcitfgrasBdbaraABdlavaicdtfaABdbavc;abfalcefcsGcitfgraOBdbarasBdlavaicefgicsGcdtfasBdbavc;abfalcdfcsGcitfgraABdbaraOBdlavaiazcz6aXcsSVfgicsGcdtfaOBdbaiaCTaCcsSVfhialcifhlkawcefhwalcsGhlaicsGhiaDcifgDae6mbkkcbc99aoaqSEhokavc;aef8Kjjjjbaok:llevu8Jjjjjbcz9Rhvc9:hodnaecvfal0mbcuhoaiRbbc;:eGc;qe9hmbav9cb83iwaicefhraialfc98fhwdnaeTmbdnadcdSmbcbhDindnaraw6mbc9:skarcefhoar8SbbglcFeGhidndnalcu9mmbaohrxekarcvfhraicFbGhicrhldninao8SbbgdcFbGaltaiVhiadcu9kmeaocefhoalcrfglc8J9hmbxdkkaocefhrkabaDcdtfaicd4cbaice4ceG9R7avcwfaiceGcdtVgoydbfglBdbaoalBdbaDcefgDae9hmbxdkkcbhDindnaraw6mbc9:skarcefhoar8SbbglcFeGhidndnalcu9mmbaohrxekarcvfhraicFbGhicrhldninao8SbbgdcFbGaltaiVhiadcu9kmeaocefhoalcrfglc8J9hmbxdkkaocefhrkabaDcetfaicd4cbaice4ceG9R7avcwfaiceGcdtVgoydbfgl87ebaoalBdbaDcefgDae9hmbkkcbc99arawSEhokaok:EPliuo97eue978Jjjjjbca9Rhidndnadcl9hmbdnaec98GglTmbcbhvabhdinadadpbbbgocKp:RecKp:Sep;6egraocwp:RecKp:Sep;6earp;Geaoczp:RecKp:Sep;6egwp;Gep;Kep;LegDpxbbbbbbbbbbbbbbbbp:2egqarpxbbbjbbbjbbbjbbbjgkp9op9rp;Kegrpxbb;:9cbb;:9cbb;:9cbb;:9cararp;MeaDaDp;Meawaqawakp9op9rp;Kegrarp;Mep;Kep;Kep;Jep;Negwp;Mepxbbn0bbn0bbn0bbn0gqp;KepxFbbbFbbbFbbbFbbbp9oaopxbbbFbbbFbbbFbbbFp9op9qarawp;Meaqp;Kecwp:RepxbFbbbFbbbFbbbFbbp9op9qaDawp;Meaqp;Keczp:RepxbbFbbbFbbbFbbbFbp9op9qpkbbadczfhdavclfgval6mbkkalae9pmeaiaeciGgvcdtgdVcbczad9R;8kbaiabalcdtfglad;8qbbdnavTmbaiaipblbgocKp:RecKp:Sep;6egraocwp:RecKp:Sep;6earp;Geaoczp:RecKp:Sep;6egwp;Gep;Kep;LegDpxbbbbbbbbbbbbbbbbp:2egqarpxbbbjbbbjbbbjbbbjgkp9op9rp;Kegrpxbb;:9cbb;:9cbb;:9cbb;:9cararp;MeaDaDp;Meawaqawakp9op9rp;Kegrarp;Mep;Kep;Kep;Jep;Negwp;Mepxbbn0bbn0bbn0bbn0gqp;KepxFbbbFbbbFbbbFbbbp9oaopxbbbFbbbFbbbFbbbFp9op9qarawp;Meaqp;Kecwp:RepxbFbbbFbbbFbbbFbbp9op9qaDawp;Meaqp;Keczp:RepxbbFbbbFbbbFbbbFbp9op9qpklbkalaiad;8qbbskdnaec98GgxTmbcbhvabhdinadczfglalpbbbgopxbbbbbbFFbbbbbbFFgkp9oadpbbbgDaopmlvorxmPsCXQL358E8FpxFubbFubbFubbFubbp9op;6eaDaopmbediwDqkzHOAKY8AEgoczp:Sep;6egrp;Geaoczp:Reczp:Sep;6egwp;Gep;Kep;Legopxb;:FSb;:FSb;:FSb;:FSawaopxbbbbbbbbbbbbbbbbp:2egqawpxbbbjbbbjbbbjbbbjgmp9op9rp;Kegwawp;Meaoaop;Mearaqaramp9op9rp;Kegoaop;Mep;Kep;Kep;Jep;Negrp;Mepxbbn0bbn0bbn0bbn0gqp;Keczp:Reawarp;Meaqp;KepxFFbbFFbbFFbbFFbbp9op9qgwaoarp;Meaqp;KepxFFbbFFbbFFbbFFbbp9ogopmwDKYqk8AExm35Ps8E8Fp9qpkbbadaDakp9oawaopmbezHdiOAlvCXorQLp9qpkbbadcafhdavclfgvax6mbkkaxae9pmbaiaeciGgvcitgdfcbcaad9R;8kbaiabaxcitfglad;8qbbdnavTmbaiaipblzgopxbbbbbbFFbbbbbbFFgkp9oaipblbgDaopmlvorxmPsCXQL358E8FpxFubbFubbFubbFubbp9op;6eaDaopmbediwDqkzHOAKY8AEgoczp:Sep;6egrp;Geaoczp:Reczp:Sep;6egwp;Gep;Kep;Legopxb;:FSb;:FSb;:FSb;:FSawaopxbbbbbbbbbbbbbbbbp:2egqawpxbbbjbbbjbbbjbbbjgmp9op9rp;Kegwawp;Meaoaop;Mearaqaramp9op9rp;Kegoaop;Mep;Kep;Kep;Jep;Negrp;Mepxbbn0bbn0bbn0bbn0gqp;Keczp:Reawarp;Meaqp;KepxFFbbFFbbFFbbFFbbp9op9qgwaoarp;Meaqp;KepxFFbbFFbbFFbbFFbbp9ogopmwDKYqk8AExm35Ps8E8Fp9qpklzaiaDakp9oawaopmbezHdiOAlvCXorQLp9qpklbkalaiad;8qbbkk;4wllue97euv978Jjjjjbc8W9Rhidnaec98GglTmbcbhvabhoinaiaopbbbgraoczfgwpbbbgDpmlvorxmPsCXQL358E8Fgqczp:Segkclp:RepklbaopxbbjZbbjZbbjZbbjZpx;Zl81Z;Zl81Z;Zl81Z;Zl81Zakpxibbbibbbibbbibbbp9qp;6ep;NegkaraDpmbediwDqkzHOAKY8AEgrczp:Reczp:Sep;6ep;MegDaDp;Meakarczp:Sep;6ep;Megxaxp;Meakaqczp:Reczp:Sep;6ep;Megqaqp;Mep;Kep;Kep;Lepxbbbbbbbbbbbbbbbbp:4ep;Jepxb;:FSb;:FSb;:FSb;:FSgkp;Mepxbbn0bbn0bbn0bbn0grp;KepxFFbbFFbbFFbbFFbbgmp9oaxakp;Mearp;Keczp:Rep9qgxaqakp;Mearp;Keczp:ReaDakp;Mearp;Keamp9op9qgkpmbezHdiOAlvCXorQLgrp5baipblbpEb:T:j83ibaocwfarp5eaipblbpEe:T:j83ibawaxakpmwDKYqk8AExm35Ps8E8Fgkp5baipblbpEd:T:j83ibaocKfakp5eaipblbpEi:T:j83ibaocafhoavclfgval6mbkkdnalae9pmbaiaeciGgvcitgofcbcaao9R;8kbaiabalcitfgwao;8qbbdnavTmbaiaipblbgraipblzgDpmlvorxmPsCXQL358E8Fgqczp:Segkclp:RepklaaipxbbjZbbjZbbjZbbjZpx;Zl81Z;Zl81Z;Zl81Z;Zl81Zakpxibbbibbbibbbibbbp9qp;6ep;NegkaraDpmbediwDqkzHOAKY8AEgrczp:Reczp:Sep;6ep;MegDaDp;Meakarczp:Sep;6ep;Megxaxp;Meakaqczp:Reczp:Sep;6ep;Megqaqp;Mep;Kep;Kep;Lepxbbbbbbbbbbbbbbbbp:4ep;Jepxb;:FSb;:FSb;:FSb;:FSgkp;Mepxbbn0bbn0bbn0bbn0grp;KepxFFbbFFbbFFbbFFbbgmp9oaxakp;Mearp;Keczp:Rep9qgxaqakp;Mearp;Keczp:ReaDakp;Mearp;Keamp9op9qgkpmbezHdiOAlvCXorQLgrp5baipblapEb:T:j83ibaiarp5eaipblapEe:T:j83iwaiaxakpmwDKYqk8AExm35Ps8E8Fgkp5baipblapEd:T:j83izaiakp5eaipblapEi:T:j83iKkawaiao;8qbbkk:Pddiue978Jjjjjbc;ab9Rhidnadcd4ae2glc98GgvTmbcbhdabheinaeaepbbbgocwp:Recwp:Sep;6eaocep:SepxbbjZbbjZbbjZbbjZp:UepxbbjFbbjFbbjFbbjFp9op;Mepkbbaeczfheadclfgdav6mbkkdnaval9pmbaialciGgdcdtgeVcbc;abae9R;8kbaiabavcdtfgvae;8qbbdnadTmbaiaipblbgocwp:Recwp:Sep;6eaocep:SepxbbjZbbjZbbjZbbjZp:UepxbbjFbbjFbbjFbbjFp9op;Mepklbkavaiae;8qbbkk9teiucbcbydj1jjbgeabcifc98GfgbBdj1jjbdndnabZbcztgd9nmbcuhiabad9RcFFifcz4nbcuSmekaehikaikkkebcjwklz9Tbb"; + + var detector = new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,3,2,0,0,5,3,1,0,1,12,1,0,10,22,2,12,0,65,0,65,0,65,0,252,10,0,0,11,7,0,65,0,253,15,26,11]); + var wasmpack = new Uint8Array([32,0,65,2,1,106,34,33,3,128,11,4,13,64,6,253,10,7,15,116,127,5,8,12,40,16,19,54,20,9,27,255,113,17,42,67,24,23,146,148,18,14,22,45,70,69,56,114,101,21,25,63,75,136,108,28,118,29,73,115]); + + if (typeof WebAssembly !== 'object') { + return { + supported: false, + }; + } + + var wasm = WebAssembly.validate(detector) ? wasm_simd : wasm_base; + + var instance; + + var ready = + WebAssembly.instantiate(unpack(wasm), {}) + .then(function(result) { + instance = result.instance; + instance.exports.__wasm_call_ctors(); + }); + + function unpack(data) { + var result = new Uint8Array(data.length); + for (var i = 0; i < data.length; ++i) { + var ch = data.charCodeAt(i); + result[i] = ch > 96 ? ch - 97 : ch > 64 ? ch - 39 : ch + 4; + } + var write = 0; + for (var i = 0; i < data.length; ++i) { + result[write++] = (result[i] < 60) ? wasmpack[result[i]] : (result[i] - 60) * 64 + result[++i]; + } + return result.buffer.slice(0, write); + } + + function decode(fun, target, count, size, source, filter) { + var sbrk = instance.exports.sbrk; + var count4 = (count + 3) & ~3; + var tp = sbrk(count4 * size); + var sp = sbrk(source.length); + var heap = new Uint8Array(instance.exports.memory.buffer); + heap.set(source, sp); + var res = fun(tp, count, size, sp, source.length); + if (res == 0 && filter) { + filter(tp, count4, size); + } + target.set(heap.subarray(tp, tp + count * size)); + sbrk(tp - sbrk(0)); + if (res != 0) { + throw new Error("Malformed buffer data: " + res); + } + } + + var filters = { + NONE: "", + OCTAHEDRAL: "meshopt_decodeFilterOct", + QUATERNION: "meshopt_decodeFilterQuat", + EXPONENTIAL: "meshopt_decodeFilterExp", + }; + + var decoders = { + ATTRIBUTES: "meshopt_decodeVertexBuffer", + TRIANGLES: "meshopt_decodeIndexBuffer", + INDICES: "meshopt_decodeIndexSequence", + }; + + var workers = []; + var requestId = 0; + + function createWorker(url) { + var worker = { + object: new Worker(url), + pending: 0, + requests: {} + }; + + worker.object.onmessage = function(event) { + var data = event.data; + + worker.pending -= data.count; + worker.requests[data.id][data.action](data.value); + + delete worker.requests[data.id]; + }; + + return worker; + } + + function initWorkers(count) { + var source = + "var instance; var ready = WebAssembly.instantiate(new Uint8Array([" + new Uint8Array(unpack(wasm)) + "]), {})" + + ".then(function(result) { instance = result.instance; instance.exports.__wasm_call_ctors(); });" + + "self.onmessage = workerProcess;" + + decode.toString() + workerProcess.toString(); + + var blob = new Blob([source], {type: 'text/javascript'}); + var url = URL.createObjectURL(blob); + + for (var i = 0; i < count; ++i) { + workers[i] = createWorker(url); + } + + URL.revokeObjectURL(url); + } + + function decodeWorker(count, size, source, mode, filter) { + var worker = workers[0]; + + for (var i = 1; i < workers.length; ++i) { + if (workers[i].pending < worker.pending) { + worker = workers[i]; + } + } + + return new Promise(function (resolve, reject) { + var data = new Uint8Array(source); + var id = requestId++; + + worker.pending += count; + worker.requests[id] = { resolve: resolve, reject: reject }; + worker.object.postMessage({ id: id, count: count, size: size, source: data, mode: mode, filter: filter }, [ data.buffer ]); + }); + } + + function workerProcess(event) { + ready.then(function() { + var data = event.data; + try { + var target = new Uint8Array(data.count * data.size); + decode(instance.exports[data.mode], target, data.count, data.size, data.source, instance.exports[data.filter]); + self.postMessage({ id: data.id, count: data.count, action: "resolve", value: target }, [ target.buffer ]); + } catch (error) { + self.postMessage({ id: data.id, count: data.count, action: "reject", value: error }); + } + }); + } + + return { + ready: ready, + supported: true, + useWorkers: function(count) { + initWorkers(count); + }, + decodeVertexBuffer: function(target, count, size, source, filter) { + decode(instance.exports.meshopt_decodeVertexBuffer, target, count, size, source, instance.exports[filters[filter]]); + }, + decodeIndexBuffer: function(target, count, size, source) { + decode(instance.exports.meshopt_decodeIndexBuffer, target, count, size, source); + }, + decodeIndexSequence: function(target, count, size, source) { + decode(instance.exports.meshopt_decodeIndexSequence, target, count, size, source); + }, + decodeGltfBuffer: function(target, count, size, source, mode, filter) { + decode(instance.exports[decoders[mode]], target, count, size, source, instance.exports[filters[filter]]); + }, + decodeGltfBufferAsync: function(count, size, source, mode, filter) { + if (workers.length > 0) { + return decodeWorker(count, size, source, decoders[mode], filters[filter]); + } + + return ready.then(function() { + var target = new Uint8Array(count * size); + decode(instance.exports[decoders[mode]], target, count, size, source, instance.exports[filters[filter]]); + return target; + }); + } + }; +})(); + +export { MeshoptDecoder }; diff --git a/js/lib/jsm/libs/zstddec.module.js b/js/lib/jsm/libs/zstddec.module.js new file mode 100644 index 0000000..ed19f91 --- /dev/null +++ b/js/lib/jsm/libs/zstddec.module.js @@ -0,0 +1 @@ +let A,I,B;const g={env:{emscripten_notify_memory_growth:function(A){B=new Uint8Array(I.exports.memory.buffer)}}};class Q{init(){return A||(A="undefined"!=typeof fetch?fetch("data:application/wasm;base64,"+C).then(A=>A.arrayBuffer()).then(A=>WebAssembly.instantiate(A,g)).then(this._init):WebAssembly.instantiate(Buffer.from(C,"base64"),g).then(this._init),A)}_init(A){I=A.instance,g.env.emscripten_notify_memory_growth(0)}decode(A,g=0){if(!I)throw new Error("ZSTDDecoder: Await .init() before decoding.");const Q=A.byteLength,C=I.exports.malloc(Q);B.set(A,C),g=g||Number(I.exports.ZSTD_findDecompressedSize(C,Q));const E=I.exports.malloc(g),i=I.exports.ZSTD_decompress(E,g,C,Q),D=B.slice(E,E+i);return I.exports.free(C),I.exports.free(E),D}}const C="AGFzbQEAAAABpQEVYAF/AX9gAn9/AGADf39/AX9gBX9/f39/AX9gAX8AYAJ/fwF/YAR/f39/AX9gA39/fwBgBn9/f39/fwF/YAd/f39/f39/AX9gAn9/AX5gAn5+AX5gAABgBX9/f39/AGAGf39/f39/AGAIf39/f39/f38AYAl/f39/f39/f38AYAABf2AIf39/f39/f38Bf2ANf39/f39/f39/f39/fwF/YAF/AX4CJwEDZW52H2Vtc2NyaXB0ZW5fbm90aWZ5X21lbW9yeV9ncm93dGgABANpaAEFAAAFAgEFCwACAQABAgIFBQcAAwABDgsBAQcAEhMHAAUBDAQEAAANBwQCAgYCBAgDAwMDBgEACQkHBgICAAYGAgQUBwYGAwIGAAMCAQgBBwUGCgoEEQAEBAEIAwgDBQgDEA8IAAcABAUBcAECAgUEAQCAAgYJAX8BQaCgwAILB2AHBm1lbW9yeQIABm1hbGxvYwAoBGZyZWUAJgxaU1REX2lzRXJyb3IAaBlaU1REX2ZpbmREZWNvbXByZXNzZWRTaXplAFQPWlNURF9kZWNvbXByZXNzAEoGX3N0YXJ0ACQJBwEAQQELASQKussBaA8AIAAgACgCBCABajYCBAsZACAAKAIAIAAoAgRBH3F0QQAgAWtBH3F2CwgAIABBiH9LC34BBH9BAyEBIAAoAgQiA0EgTQRAIAAoAggiASAAKAIQTwRAIAAQDQ8LIAAoAgwiAiABRgRAQQFBAiADQSBJGw8LIAAgASABIAJrIANBA3YiBCABIARrIAJJIgEbIgJrIgQ2AgggACADIAJBA3RrNgIEIAAgBCgAADYCAAsgAQsUAQF/IAAgARACIQIgACABEAEgAgv3AQECfyACRQRAIABCADcCACAAQQA2AhAgAEIANwIIQbh/DwsgACABNgIMIAAgAUEEajYCECACQQRPBEAgACABIAJqIgFBfGoiAzYCCCAAIAMoAAA2AgAgAUF/ai0AACIBBEAgAEEIIAEQFGs2AgQgAg8LIABBADYCBEF/DwsgACABNgIIIAAgAS0AACIDNgIAIAJBfmoiBEEBTQRAIARBAWtFBEAgACABLQACQRB0IANyIgM2AgALIAAgAS0AAUEIdCADajYCAAsgASACakF/ai0AACIBRQRAIABBADYCBEFsDwsgAEEoIAEQFCACQQN0ams2AgQgAgsWACAAIAEpAAA3AAAgACABKQAINwAICy8BAX8gAUECdEGgHWooAgAgACgCAEEgIAEgACgCBGprQR9xdnEhAiAAIAEQASACCyEAIAFCz9bTvtLHq9lCfiAAfEIfiUKHla+vmLbem55/fgsdAQF/IAAoAgggACgCDEYEfyAAKAIEQSBGBUEACwuCBAEDfyACQYDAAE8EQCAAIAEgAhBnIAAPCyAAIAJqIQMCQCAAIAFzQQNxRQRAAkAgAkEBSARAIAAhAgwBCyAAQQNxRQRAIAAhAgwBCyAAIQIDQCACIAEtAAA6AAAgAUEBaiEBIAJBAWoiAiADTw0BIAJBA3ENAAsLAkAgA0F8cSIEQcAASQ0AIAIgBEFAaiIFSw0AA0AgAiABKAIANgIAIAIgASgCBDYCBCACIAEoAgg2AgggAiABKAIMNgIMIAIgASgCEDYCECACIAEoAhQ2AhQgAiABKAIYNgIYIAIgASgCHDYCHCACIAEoAiA2AiAgAiABKAIkNgIkIAIgASgCKDYCKCACIAEoAiw2AiwgAiABKAIwNgIwIAIgASgCNDYCNCACIAEoAjg2AjggAiABKAI8NgI8IAFBQGshASACQUBrIgIgBU0NAAsLIAIgBE8NAQNAIAIgASgCADYCACABQQRqIQEgAkEEaiICIARJDQALDAELIANBBEkEQCAAIQIMAQsgA0F8aiIEIABJBEAgACECDAELIAAhAgNAIAIgAS0AADoAACACIAEtAAE6AAEgAiABLQACOgACIAIgAS0AAzoAAyABQQRqIQEgAkEEaiICIARNDQALCyACIANJBEADQCACIAEtAAA6AAAgAUEBaiEBIAJBAWoiAiADRw0ACwsgAAsMACAAIAEpAAA3AAALQQECfyAAKAIIIgEgACgCEEkEQEEDDwsgACAAKAIEIgJBB3E2AgQgACABIAJBA3ZrIgE2AgggACABKAAANgIAQQALDAAgACABKAIANgAAC/cCAQJ/AkAgACABRg0AAkAgASACaiAASwRAIAAgAmoiBCABSw0BCyAAIAEgAhALDwsgACABc0EDcSEDAkACQCAAIAFJBEAgAwRAIAAhAwwDCyAAQQNxRQRAIAAhAwwCCyAAIQMDQCACRQ0EIAMgAS0AADoAACABQQFqIQEgAkF/aiECIANBAWoiA0EDcQ0ACwwBCwJAIAMNACAEQQNxBEADQCACRQ0FIAAgAkF/aiICaiIDIAEgAmotAAA6AAAgA0EDcQ0ACwsgAkEDTQ0AA0AgACACQXxqIgJqIAEgAmooAgA2AgAgAkEDSw0ACwsgAkUNAgNAIAAgAkF/aiICaiABIAJqLQAAOgAAIAINAAsMAgsgAkEDTQ0AIAIhBANAIAMgASgCADYCACABQQRqIQEgA0EEaiEDIARBfGoiBEEDSw0ACyACQQNxIQILIAJFDQADQCADIAEtAAA6AAAgA0EBaiEDIAFBAWohASACQX9qIgINAAsLIAAL8wICAn8BfgJAIAJFDQAgACACaiIDQX9qIAE6AAAgACABOgAAIAJBA0kNACADQX5qIAE6AAAgACABOgABIANBfWogAToAACAAIAE6AAIgAkEHSQ0AIANBfGogAToAACAAIAE6AAMgAkEJSQ0AIABBACAAa0EDcSIEaiIDIAFB/wFxQYGChAhsIgE2AgAgAyACIARrQXxxIgRqIgJBfGogATYCACAEQQlJDQAgAyABNgIIIAMgATYCBCACQXhqIAE2AgAgAkF0aiABNgIAIARBGUkNACADIAE2AhggAyABNgIUIAMgATYCECADIAE2AgwgAkFwaiABNgIAIAJBbGogATYCACACQWhqIAE2AgAgAkFkaiABNgIAIAQgA0EEcUEYciIEayICQSBJDQAgAa0iBUIghiAFhCEFIAMgBGohAQNAIAEgBTcDGCABIAU3AxAgASAFNwMIIAEgBTcDACABQSBqIQEgAkFgaiICQR9LDQALCyAACy8BAn8gACgCBCAAKAIAQQJ0aiICLQACIQMgACACLwEAIAEgAi0AAxAIajYCACADCy8BAn8gACgCBCAAKAIAQQJ0aiICLQACIQMgACACLwEAIAEgAi0AAxAFajYCACADCx8AIAAgASACKAIEEAg2AgAgARAEGiAAIAJBCGo2AgQLCAAgAGdBH3MLugUBDX8jAEEQayIKJAACfyAEQQNNBEAgCkEANgIMIApBDGogAyAEEAsaIAAgASACIApBDGpBBBAVIgBBbCAAEAMbIAAgACAESxsMAQsgAEEAIAEoAgBBAXRBAmoQECENQVQgAygAACIGQQ9xIgBBCksNABogAiAAQQVqNgIAIAMgBGoiAkF8aiEMIAJBeWohDiACQXtqIRAgAEEGaiELQQQh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ASIDNgLE4AEgACgCvOABIQQgACABNgK84AEgACABIAJqNgK44AEgACABIAQgA2tqNgLA4AELpgEBAX8gACAAKALs4QEQFjYCyOABIABCADcD+OABIABCADcDuOABIABBwOABakIANwMAIABBqNAAaiIBQYyAgOAANgIAIABBADYCmOIBIABCADcDiOEBIABCAzcDgOEBIABBrNABakHgEikCADcCACAAQbTQAWpB6BIoAgA2AgAgACABNgIMIAAgAEGYIGo2AgggACAAQaAwajYCBCAAIABBEGo2AgALYQEBf0G4fyEDAkAgAUEDSQ0AIAIgABAhIgFBA3YiADYCCCACIAFBAXE2AgQgAiABQQF2QQNxIgM2AgACQCADQX9qIgFBAksNAAJAIAFBAWsOAgEAAgtBbA8LIAAhAwsgAwsMACAAIAEgAkEAEC4LiAQCA38CfiADEBYhBCAAQQBBKBAQIQAgBCACSwRAIAQPCyABRQRAQX8PCwJAAkAgA0EBRg0AIAEoAAAiBkGo6r5pRg0AQXYhAyAGQXBxQdDUtMIBRw0BQQghAyACQQhJDQEgAEEAQSgQECEAIAEoAAQhASAAQQE2AhQgACABrTcDAEEADwsgASACIAMQLyIDIAJLDQAgACADNgIYQXIhAyABIARqIgVBf2otAAAiAkEIcQ0AIAJBIHEiBkUEQEFwIQMgBS0AACIFQacBSw0BIAVBB3GtQgEgBUEDdkEKaq2GIgdCA4h+IAd8IQggBEEBaiEECyACQQZ2IQMgAkECdiEFAkAgAkEDcUF/aiICQQJLBEBBACECDAELAkACQAJAIAJBAWsOAgECAAsgASAEai0AACECIARBAWohBAwCCyABIARqLwAAIQIgBEECaiEEDAELIAEgBGooAAAhAiAEQQRqIQQLIAVBAXEhBQJ+AkACQAJAIANBf2oiA0ECTQRAIANBAWsOAgIDAQtCfyAGRQ0DGiABIARqMQAADAMLIAEgBGovAACtQoACfAwCCyABIARqKAAArQwBCyABIARqKQAACyEHIAAgBTYCICAAIAI2AhwgACAHNwMAQQAhAyAAQQA2AhQgACAHIAggBhsiBzcDCCAAIAdCgIAIIAdCgIAIVBs+AhALIAMLWwEBf0G4fyEDIAIQFiICIAFNBH8gACACakF/ai0AACIAQQNxQQJ0QaAeaigC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C0Egak8NAQsgByAHKQNoNwMQIAcgBykDYDcDCCAEIA0gB0EIaiAHQdwAaiAPIA4gESAQEB4hCwwBCyACIARqIQggBCAKEAcgAkERTwRAIARBEGohAgNAIAIgCkEQaiIKEAcgAkEQaiICIAhJDQALCyAIIAlrIQIgByATNgJcIAkgCCAOa0sEQCAJIAggEWtLBEBBbCELDAILIBAgAiAOayICaiIKIANqIBBNBEAgCCAKIAMQDxoMAgsgCCAKQQAgAmsQDyEIIAcgAiADaiIDNgJkIAggAmshCCAOIQILIAlBEE8EQCADIAhqIQMDQCAIIAIQByACQRBqIQIgCEEQaiIIIANJDQALDAELAkAgCUEHTQRAIAggAi0AADoAACAIIAItAAE6AAEgCCACLQACOgACIAggAi0AAzoAAyAIQQRqIAIgCUECdCIDQcAeaigCAGoiAhAXIAIgA0HgHmooAgBrIQIgBygCZCEDDAELIAggAhAMCyADQQlJDQAgAyAIaiEDIAhBCGoiCCACQQhqIgJrQQ9MBEADQCAIIAIQDCACQQhqIQIgCEEIaiIIIANJDQAMAgALAAsDQCAIIAIQByACQRBqIQIgCEEQaiIIIANJDQALCyAHQRhqEAQaIAsgDCALEAMiAhshDCAEIAQgC2ogAhshBCAFQX9qIgUNAAsgDBADDQFBbCEMIAdBGGoQBEECSQ0BQQAhCANAIAhBA0cEQCAAIAhBAnQiAmpBrNABaiACIAdqKAJENgIAIAhBAWohCAwBCwsgBygCXCEIC0G6fyEMIA8gCGsiACANIARrSw0AIAQEfyAEIAggABALIABqBUEACyABayEMCyAHQfAAaiQAIAwLkRcCFn8FfiMAQdABayIHJAAgByAAKALw4QEiCDYCvAEgASACaiESIAggACgCgOIBaiETAkACQCAFRQRAIAEhAwwBCyAAKALE4AEhESAAKALA4AEhFSAAKAK84AEhDyAAQQE2AozhAUEAIQgDQCAIQQNHBEAgByAIQQJ0IgJqIAAgAmpBrNABaigCADYCVCAIQQFqIQgMAQsLIAcgETYCZCAHIA82AmAgByABIA9rNgJoQWwhECAHQShqIAMgBBAGEAMNASAFQQQgBUEESBshFyAHQTxqIAdBKGogACgCABATIAdBxABqIAdBKGogACgCCBATIAdBzABqIAdB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IAdB0AFqJAAgEAslACAAQgA3AgAgAEEAOwEIIABBADoACyAAIAE2AgwgACACOgAKC7QFAQN/IwBBMGsiBCQAIABB/wFqIgVBfWohBgJAIAMvAQIEQCAEQRhqIAEgAhAGIgIQAw0BIARBEGogBEEYaiADEBwgBEEIaiAEQRhqIAMQHCAAIQMDQAJAIARBGGoQBCADIAZPckUEQCADIARBEGogBEEYahASOgAAIAMgBEEIaiAEQRhqEBI6AAEgBEEYahAERQ0BIANBAmohAwsgBUF+aiEFAn8DQEG6fyECIAMiASAFSw0FIAEgBEEQaiAEQRhqEBI6AAAgAUEBaiEDIARBGGoQBEEDRgRAQQIhAiAEQQhqDAILIAMgBUsNBSABIARBCGogBEEYahASOgABIAFBAmohA0EDIQIgBEEYahAEQQNHDQALIARBEGoLIQUgAyAFIARBGGoQEjoAACABIAJqIABrIQIMAwsgAyAEQRBqIARBGGoQEjoAAiADIARBCGogBEEYahASOgADIANBBGohAwwAAAsACyAEQRhqIAEgAhAGIgIQAw0AIARBEGogBEEYaiADEBwgBEEIaiAEQRhqIAMQHCAAIQMDQAJAIARBGGoQBCADIAZPckUEQCADIARBEGogBEEYahAROgAAIAMgBEEIaiAEQRhqEBE6AAEgBEEYahAERQ0BIANBAmohAwsgBUF+aiEFAn8DQEG6fyECIAMiASAFSw0EIAEgBEEQaiAEQRhqEBE6AAAgAUEBaiEDIARBGGoQBEEDRgRAQQIhAiAEQQhqDAILIAMgBUsNBCABIARBCGogBEEYahAROgABIAFBAmohA0EDIQIgBEEYahAEQQNHDQALIARBEGoLIQUgAyAFIARBGGoQEToAACABIAJqIABrIQIMAgsgAyAEQRBqIARBGGoQEToAAiADIARBCGogBEEYahAROgADIANBBGohAwwAAAsACyAEQTBqJAAgAgtpAQF/An8CQAJAIAJBB00NACABKAAAQbfIwuF+Rw0AIAAgASgABDYCmOIBQWIgAEEQaiABIAIQPiIDEAMNAhogAEKBgICAEDcDiOEBIAAgASADaiACIANrECoMAQsgACABIAIQKgtBAAsLrQMBBn8jAEGAAWsiAyQAQWIhCAJAIAJBCUkNACAAQZjQAGogAUEIaiIEIAJBeGogAEGY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wOABCwutAgIEfwF+IwBBQGoiBCQAAkACQCACQQhJDQAgASgAAEFwcUHQ1LTCAUcNACABIAIQIiEBIABCADcDCCAAQQA2AgQgACABNgIADAELIARBGGogASACEC0iAxADBEAgACADEBoMAQsgAwRAIABBuH8QGgwBCyACIAQoAjAiA2shAiABIANqIQMDQAJAIAAgAyACIARBCGoQLCIFEAMEfyAFBSACIAVBA2oiBU8NAUG4fwsQGgwCCyAGQQFqIQYgAiAFayECIAMgBWohAyAEKAIMRQ0ACyAEKAI4BEAgAkEDTQRAIABBuH8QGgwCCyADQQRqIQMLIAQoAighAiAEKQMYIQcgAEEANgIEIAAgAyABazYCACAAIAIgBmytIAcgB0J/URs3AwgLIARBQGskAAslAQF/IwBBEGsiAiQAIAIgACABEFEgAigCACEAIAJBEGokACAAC30BBH8jAEGQBGsiBCQAIARB/wE2AggCQCAEQRBqIARBCGogBEEMaiABIAIQFSIGEAMEQCAGIQUMAQtBVCEFIAQoAgwiB0EGSw0AIAMgBEEQaiAEKAIIIAcQQSIFEAMNACAAIAEgBmogAiAGayADEDwhBQsgBEGQBGokACAFC4cBAgJ/An5BABAWIQMCQANAIAEgA08EQAJAIAAoAABBcHFB0NS0wgFGBEAgACABECIiAhADRQ0BQn4PCyAAIAEQVSIEQn1WDQMgBCAFfCIFIARUIQJCfiEEIAINAyAAIAEQUiICEAMNAwsgASACayEBIAAgAmohAAwBCwtCfiAFIAEbIQQLIAQLPwIBfwF+IwBBMGsiAiQAAn5CfiACQQhqIAAgARAtDQAaQgAgAigCHEEBRg0AGiACKQMICyEDIAJBMGokACADC40BAQJ/IwBBMGsiASQAAkAgAEUNACAAKAKI4gENACABIABB/OEBaigCADYCKCABIAApAvThATcDICAAEDAgACgCqOIBIQIgASABKAIoNgIYIAEgASkDIDcDECACIAFBEGoQGyAAQQA2AqjiASABIAEoAig2AgggASABKQMgNwMAIAAgARAbCyABQTBqJAALKgECfyMAQRBrIgAkACAAQQA2AgggAEIANwMAIAAQWCEBIABBEGokACABC4cBAQN/IwBBEGsiAiQAAkAgACgCAEUgACgCBEVzDQAgAiAAKAIINgIIIAIgACkCADcDAAJ/IAIoAgAiAQRAIAIoAghBqOMJIAERBQAMAQtBqOMJECgLIgFFDQAgASAAKQIANwL04QEgAUH84QFqIAAoAgg2AgAgARBZIAEhAwsgAkEQaiQAIAMLywEBAn8jAEEgayIBJAAgAEGBgIDAADYCtOIBIABBADYCiOIBIABBADYC7OEBIABCADcDkOIBIABBADYCpOMJIABBADYC3OIBIABCADcCzOIBIABBADYCvOIBIABBADYCxOABIABCADcCnOIBIABBpOIBakIANwIAIABBrOIBakEANgIAIAFCADcCECABQgA3AhggASABKQMYNwMIIAEgASkDEDcDACABKAIIQQh2QQFxIQIgAEEANgLg4gEgACACNgKM4gEgAUEgaiQAC3YBA38jAEEwayIBJAAgAARAIAEgAEHE0AFqIgIoAgA2AiggASAAKQK80AE3AyAgACgCACEDIAEgAigCADYCGCABIAApArzQATcDECADIAFBEGoQGyABIAEoAig2AgggASABKQMgNwMAIAAgARAbCyABQTBqJAALzAEBAX8gACABKAK00AE2ApjiASAAIAEoAgQiAjYCwOABIAAgAjYCvOABIAAgAiABKAIIaiICNgK44AEgACACNgLE4AEgASgCuNABBEAgAEKBgICAEDcDiOEBIAAgAUGk0ABqNgIMIAAgAUGUIGo2AgggACABQZwwajYCBCAAIAFBDGo2AgAgAEGs0AFqIAFBqNABaigCADYCACAAQbDQAWogAUGs0AFqKAIANgIAIABBtNABaiABQbDQAWooAgA2AgAPCyAAQgA3A4jhAQs7ACACRQRAQbp/DwsgBEUEQEFsDwsgAiAEEGAEQCAAIAEgAiADIAQgBRBhDwsgACABIAIgAyAEIAUQZQtGAQF/IwBBEGsiBSQAIAVBCGogBBAOAn8gBS0ACQRAIAAgASACIAMgBBAyDAELIAAgASACIAMgBBA0CyEAIAVBEGokACAACzQAIAAgAyAEIAUQNiIFEAMEQCAFDwsgBSAESQR/IAEgAiADIAVqIAQgBWsgABA1BUG4fwsLRgEBfyMAQRBrIgUkACAFQQhqIAQQDgJ/IAUtAAkEQCAAIAEgAiADIAQQYgwBCyAAIAEgAiADIAQQNQshACAFQRBqJAAgAAtZAQF/QQ8hAiABIABJBEAgAUEEdCAAbiECCyAAQQh2IgEgAkEYbCIAQYwIaigCAGwgAEGICGooAgBqIgJBA3YgAmogAEGACGooAgAgAEGECGooAgAgAWxqSQs3ACAAIAMgBCAFQYAQEDMiBRADBEAgBQ8LIAUgBEkEfyABIAIgAyAFaiAEIAVrIAAQMgVBuH8LC78DAQN/IwBBIGsiBSQAIAVBCGogAiADEAYiAhADRQRAIAAgAWoiB0F9aiEGIAUgBBAOIARBBGohAiAFLQACIQMDQEEAIAAgBkkgBUEIahAEGwRAIAAgAiAFQQhqIAMQAkECdGoiBC8BADsAACAFQQhqIAQtAAIQASAAIAQtAANqIgQgAiAFQQhqIAMQAkECdGoiAC8BADsAACAFQQhqIAAtAAIQASAEIAAtAANqIQAMAQUgB0F+aiEEA0AgBUEIahAEIAAgBEtyRQRAIAAgAiAFQQhqIAMQAkECdGoiBi8BADsAACAFQQhqIAYtAAIQASAAIAYtAANqIQAMAQsLA0AgACAES0UEQCAAIAIgBUEIaiADEAJBAnRqIgYvAQA7AAAgBUEIaiAGLQACEAEgACAGLQADaiEADAELCwJAIAAgB08NACAAIAIgBUEIaiADEAIiA0ECdGoiAC0AADoAACAALQADQQFGBEAgBUEIaiAALQACEAEMAQsgBSgCDEEfSw0AIAVBCGogAiADQQJ0ai0AAhABIAUoAgxBIUkNACAFQSA2AgwLIAFBbCAFQQhqEAobIQILCwsgBUEgaiQAIAILkgIBBH8jAEFAaiIJJAAgCSADQTQQCyEDAkAgBEECSA0AIAMgBEECdGooAgAhCSADQTxqIAgQIyADQQE6AD8gAyACOgA+QQAhBCADKAI8IQoDQCAEIAlGDQEgACAEQQJ0aiAKNgEAIARBAWohBAwAAAsAC0EAIQkDQCAGIAlGRQRAIAMgBSAJQQF0aiIKLQABIgtBAnRqIgwoAgAhBCADQTxqIAotAABBCHQgCGpB//8DcRAjIANBAjoAPyADIAcgC2siCiACajoAPiAEQQEgASAKa3RqIQogAygCPCELA0AgACAEQQJ0aiALNgEAIARBAWoiBCAKSQ0ACyAMIAo2AgAgCUEBaiEJDAELCyADQUBrJAALowIBCX8jAEHQAGsiCSQAIAlBEGogBUE0EAsaIAcgBmshDyAHIAFrIRADQAJAIAMgCkcEQEEBIAEgByACIApBAXRqIgYtAAEiDGsiCGsiC3QhDSAGLQAAIQ4gCUEQaiAMQQJ0aiIMKAIAIQYgCyAPTwRAIAAgBkECdGogCyAIIAUgCEE0bGogCCAQaiIIQQEgCEEBShsiCCACIAQgCEECdGooAgAiCEEBdGogAyAIayAHIA4QYyAGIA1qIQgMAgsgCUEMaiAOECMgCUEBOgAPIAkgCDoADiAGIA1qIQggCSgCDCELA0AgBiAITw0CIAAgBkECdGogCzYBACAGQQFqIQYMAAALAAsgCUHQAGokAA8LIAwgCDYCACAKQQFqIQoMAAALAAs0ACAAIAMgBCAFEDYiBRADBEAgBQ8LIAUgBEkEfyABIAIgAyAFaiAEIAVrIAAQNAVBuH8LCyMAIAA/AEEQdGtB//8DakEQdkAAQX9GBEBBAA8LQQAQAEEBCzsBAX8gAgRAA0AgACABIAJBgCAgAkGAIEkbIgMQCyEAIAFBgCBqIQEgAEGAIGohACACIANrIgINAAsLCwYAIAAQAwsLqBUJAEGICAsNAQAAAAEAAAACAAAAAgBBoAgLswYBAAAAAQAAAAIAAAACAAAAJgAAAIIAAAAhBQAASgAAAGcIAAAmAAAAwAEAAIAAAABJBQAASgAAAL4IAAApAAAALAIAAIAAAABJBQAASgAAAL4IAAAvAAAAygIAAIAAAACKBQAASgAAAIQJAAA1AAAAcwMAAIAAAACdBQAASgAAAKAJAAA9AAAAgQMAAIAAAADrBQAASwAAAD4KAABEAAAAngMAAIAAAABNBgAASwAAAKoKAABLAAAAswMAAIAAAADBBgAATQAAAB8NAABNAAAAUwQAAIAAAAAjCAAAUQAAAKYPAABUAAAAmQQAAIAAAABLCQAAVwAAALESAABYAAAA2gQAAIAAAABvCQAAXQAAACMUAABUAAAARQUAAIAAAABUCgAAagAAAIwUAABqAAAArwUAAIAAAAB2CQAAfAAAAE4QAAB8AAAA0gIAAIAAAABjBwAAkQAAAJAHAACSAAAAAAAAAAEAAAABAAAABQAAAA0AAAAdAAAAPQAAAH0AAAD9AAAA/QEAAP0DAAD9BwAA/Q8AAP0fAAD9PwAA/X8AAP3/AAD9/wEA/f8DAP3/BwD9/w8A/f8fAP3/PwD9/38A/f//AP3//wH9//8D/f//B/3//w/9//8f/f//P/3//38AAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAACwAAAAwAAAANAAAADgAAAA8AAAAQAAAAEQAAABIAAAATAAAAFAAAABUAAAAWAAAAFwAAABgAAAAZAAAAGgAAABsAAAAcAAAAHQAAAB4AAAAfAAAAIAAAACEAAAAiAAAAIwAAACUAAAAnAAAAKQAAACsAAAAvAAAAMwAAADsAAABDAAAAUwAAAGMAAACDAAAAAwEAAAMCAAADBAAAAwgAAAMQAAADIAAAA0AAAAOAAAADAAEAQeAPC1EBAAAAAQAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAQcQQC4sBAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABIAAAAUAAAAFgAAABgAAAAcAAAAIAAAACgAAAAwAAAAQAAAAIAAAAAAAQAAAAIAAAAEAAAACAAAABAAAAAgAAAAQAAAAIAAAAAAAQBBkBIL5gQBAAAAAQAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAAAEAAAAEAAAACAAAAAAAAAABAAEBBgAAAAAAAAQAAAAAEAAABAAAAAAgAAAFAQAAAAAAAAUDAAAAAAAABQQAAAAAAAAFBgAAAAAAAAUHAAAAAAAABQkAAAAAAAAFCgAAAAAAAAUMAAAAAAAABg4AAAAAAAEFEAAAAAAAAQUUAAAAAAABBRYAAAAAAAIFHAAAAAAAAwUgAAAAAAAEBTAAAAAgAAYFQAAAAAAABwWAAAAAAAAIBgABAAAAAAoGAAQAAAAADAYAEAAAIAAABAAAAAAAAAAEAQAAAAAAAAUCAAAAIAAABQQAAAAAAAAFBQAAACAAAAUHAAAAAAAABQgAAAAgAAAFCgAAAAAAAAULAAAAAAAABg0AAAAgAAEFEAAAAAAAAQUSAAAAIAABBRYAAAAAAAIFGAAAACAAAwUgAAAAAAADBSgAAAAAAAYEQAAAABAABgRAAAAAIAAHBYAAAAAAAAkGAAIAAAAACwYACAAAMAAABAAAAAAQAAAEAQAAACAAAAUCAAAAIAAABQMAAAAgAAAFBQAAACAAAAUGAAAAIAAABQgAAAAgAAAFCQAAACAAAAULAAAAIAAABQwAAAAAAAAGDwAAACAAAQUSAAAAIAABBRQAAAAgAAIFGAAAACAAAgUcAAAAIAADBSgAAAAgAAQFMAAAAAAAEAYAAAEAAAAPBgCAAAAAAA4GAEAAAAAADQYAIABBgBcLhwIBAAEBBQAAAAAAAAUAAAAAAAAGBD0AAAAAAAkF/QEAAAAADwX9fwAAAAAVBf3/HwAAAAMFBQAAAAAABwR9AAAAAAAMBf0PAAAAABIF/f8DAAAAFwX9/38AAAAFBR0AAAAAAAgE/QAAAAAADgX9PwAAAAAUBf3/DwAAAAIFAQAAABAABwR9AAAAAAALBf0HAAAAABEF/f8BAAAAFgX9/z8AAAAEBQ0AAAAQAAgE/QAAAAAADQX9HwAAAAATBf3/BwAAAAEFAQAAABAABgQ9AAAAAAAKBf0DAAAAABAF/f8AAAAAHAX9//8PAAAbBf3//wcAABoF/f//AwAAGQX9//8BAAAYBf3//wBBkBkLhgQBAAEBBgAAAAAAAAYDAAAAAAAABAQAAAAgAAAFBQAAAAAAAAUGAAAAAAAABQgAAAAAAAAFCQAAAAAAAAULAAAAAAAABg0AAAAAAAAGEAAAAAAAAAYTAAAAAAAABhYAAAAAAAAGGQAAAAAAAAYcAAAAAAAABh8AAAAAAAAGIgAAAAAAAQYlAAAAAAABBikAAAAAAAIGLwAAAAAAAwY7AAAAAAAEBlMAAAAAAAcGgwAAAAAACQYDAgAAEAAABAQAAAAAAAAEBQAAACAAAAUGAAAAAAAABQcAAAAgAAAFCQAAAAAAAAUKAAAAAAAABgwAAAAAAAAGDwAAAAAAAAYSAAAAAAAABhUAAAAAAAAGGAAAAAAAAAYbAAAAAAAABh4AAAAAAAAGIQAAAAAAAQYjAAAAAAABBicAAAAAAAIGKwAAAAAAAwYzAAAAAAAEBkMAAAAAAAUGYwAAAAAACAYDAQAAIAAABAQAAAAwAAAEBAAAABAAAAQFAAAAIAAABQcAAAAgAAAFCAAAACAAAAUKAAAAIAAABQsAAAAAAAAGDgAAAAAAAAYRAAAAAAAABhQAAAAAAAAGFwAAAAAAAAYaAAAAAAAABh0AAAAAAAAGIAAAAAAAEAYDAAEAAAAPBgOAAAAAAA4GA0AAAAAADQYDIAAAAAAMBgMQAAAAAAsGAwgAAAAACgYDBABBpB0L2QEBAAAAAwAAAAcAAAAPAAAAHwAAAD8AAAB/AAAA/wAAAP8BAAD/AwAA/wcAAP8PAAD/HwAA/z8AAP9/AAD//wAA//8BAP//AwD//wcA//8PAP//HwD//z8A//9/AP///wD///8B////A////wf///8P////H////z////9/AAAAAAEAAAACAAAABAAAAAAAAAACAAAABAAAAAgAAAAAAAAAAQAAAAIAAAABAAAABAAAAAQAAAAEAAAABAAAAAgAAAAIAAAACAAAAAcAAAAIAAAACQAAAAoAAAALAEGgIAsDwBBQ";export{Q as ZSTDDecoder}; diff --git a/js/lib/jsm/loaders/EXRLoader.js b/js/lib/jsm/loaders/EXRLoader.js new file mode 100644 index 0000000..e37e81c --- /dev/null +++ b/js/lib/jsm/loaders/EXRLoader.js @@ -0,0 +1,2563 @@ +import { + DataTextureLoader, + DataUtils, + FloatType, + HalfFloatType, + NoColorSpace, + LinearFilter, + LinearSRGBColorSpace, + RedFormat, + RGBAFormat +} from '../../three.module.js'; +import * as fflate from '../libs/fflate.module.js'; + +/** + * OpenEXR loader currently supports uncompressed, ZIP(S), RLE, PIZ and DWA/B compression. + * Supports reading as UnsignedByte, HalfFloat and Float type data texture. + * + * Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita + * implementation, so I have preserved their copyright notices. + */ + +// /* +// Copyright (c) 2014 - 2017, Syoyo Fujita +// All rights reserved. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the Syoyo Fujita nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. + +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// */ + +// // TinyEXR contains some OpenEXR code, which is licensed under ------------ + +// /////////////////////////////////////////////////////////////////////////// +// // +// // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas +// // Digital Ltd. LLC +// // +// // All rights reserved. +// // +// // Redistribution and use in source and binary forms, with or without +// // modification, are permitted provided that the following conditions are +// // met: +// // * Redistributions of source code must retain the above copyright +// // notice, this list of conditions and the following disclaimer. +// // * Redistributions in binary form must reproduce the above +// // copyright notice, this list of conditions and the following disclaimer +// // in the documentation and/or other materials provided with the +// // distribution. +// // * Neither the name of Industrial Light & Magic nor the names of +// // its contributors may be used to endorse or promote products derived +// // from this software without specific prior written permission. +// // +// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// // +// /////////////////////////////////////////////////////////////////////////// + +// // End of OpenEXR license ------------------------------------------------- + +class EXRLoader extends DataTextureLoader { + + constructor( manager ) { + + super( manager ); + + this.type = HalfFloatType; + + } + + parse( buffer ) { + + const USHORT_RANGE = ( 1 << 16 ); + const BITMAP_SIZE = ( USHORT_RANGE >> 3 ); + + const HUF_ENCBITS = 16; // literal (value) bit length + const HUF_DECBITS = 14; // decoding bit size (>= 8) + + const HUF_ENCSIZE = ( 1 << HUF_ENCBITS ) + 1; // encoding table size + const HUF_DECSIZE = 1 << HUF_DECBITS; // decoding table size + const HUF_DECMASK = HUF_DECSIZE - 1; + + const NBITS = 16; + const A_OFFSET = 1 << ( NBITS - 1 ); + const MOD_MASK = ( 1 << NBITS ) - 1; + + const SHORT_ZEROCODE_RUN = 59; + const LONG_ZEROCODE_RUN = 63; + const SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN; + + const ULONG_SIZE = 8; + const FLOAT32_SIZE = 4; + const INT32_SIZE = 4; + const INT16_SIZE = 2; + const INT8_SIZE = 1; + + const STATIC_HUFFMAN = 0; + const DEFLATE = 1; + + const UNKNOWN = 0; + const LOSSY_DCT = 1; + const RLE = 2; + + const logBase = Math.pow( 2.7182818, 2.2 ); + + function reverseLutFromBitmap( bitmap, lut ) { + + let k = 0; + + for ( let i = 0; i < USHORT_RANGE; ++ i ) { + + if ( ( i == 0 ) || ( bitmap[ i >> 3 ] & ( 1 << ( i & 7 ) ) ) ) { + + lut[ k ++ ] = i; + + } + + } + + const n = k - 1; + + while ( k < USHORT_RANGE ) lut[ k ++ ] = 0; + + return n; + + } + + function hufClearDecTable( hdec ) { + + for ( let i = 0; i < HUF_DECSIZE; i ++ ) { + + hdec[ i ] = {}; + hdec[ i ].len = 0; + hdec[ i ].lit = 0; + hdec[ i ].p = null; + + } + + } + + const getBitsReturn = { l: 0, c: 0, lc: 0 }; + + function getBits( nBits, c, lc, uInt8Array, inOffset ) { + + while ( lc < nBits ) { + + c = ( c << 8 ) | parseUint8Array( uInt8Array, inOffset ); + lc += 8; + + } + + lc -= nBits; + + getBitsReturn.l = ( c >> lc ) & ( ( 1 << nBits ) - 1 ); + getBitsReturn.c = c; + getBitsReturn.lc = lc; + + } + + const hufTableBuffer = new Array( 59 ); + + function hufCanonicalCodeTable( hcode ) { + + for ( let i = 0; i <= 58; ++ i ) hufTableBuffer[ i ] = 0; + for ( let i = 0; i < HUF_ENCSIZE; ++ i ) hufTableBuffer[ hcode[ i ] ] += 1; + + let c = 0; + + for ( let i = 58; i > 0; -- i ) { + + const nc = ( ( c + hufTableBuffer[ i ] ) >> 1 ); + hufTableBuffer[ i ] = c; + c = nc; + + } + + for ( let i = 0; i < HUF_ENCSIZE; ++ i ) { + + const l = hcode[ i ]; + if ( l > 0 ) hcode[ i ] = l | ( hufTableBuffer[ l ] ++ << 6 ); + + } + + } + + function hufUnpackEncTable( uInt8Array, inOffset, ni, im, iM, hcode ) { + + const p = inOffset; + let c = 0; + let lc = 0; + + for ( ; im <= iM; im ++ ) { + + if ( p.value - inOffset.value > ni ) return false; + + getBits( 6, c, lc, uInt8Array, p ); + + const l = getBitsReturn.l; + c = getBitsReturn.c; + lc = getBitsReturn.lc; + + hcode[ im ] = l; + + if ( l == LONG_ZEROCODE_RUN ) { + + if ( p.value - inOffset.value > ni ) { + + throw new Error( 'Something wrong with hufUnpackEncTable' ); + + } + + getBits( 8, c, lc, uInt8Array, p ); + + let zerun = getBitsReturn.l + SHORTEST_LONG_RUN; + c = getBitsReturn.c; + lc = getBitsReturn.lc; + + if ( im + zerun > iM + 1 ) { + + throw new Error( 'Something wrong with hufUnpackEncTable' ); + + } + + while ( zerun -- ) hcode[ im ++ ] = 0; + + im --; + + } else if ( l >= SHORT_ZEROCODE_RUN ) { + + let zerun = l - SHORT_ZEROCODE_RUN + 2; + + if ( im + zerun > iM + 1 ) { + + throw new Error( 'Something wrong with hufUnpackEncTable' ); + + } + + while ( zerun -- ) hcode[ im ++ ] = 0; + + im --; + + } + + } + + hufCanonicalCodeTable( hcode ); + + } + + function hufLength( code ) { + + return code & 63; + + } + + function hufCode( code ) { + + return code >> 6; + + } + + function hufBuildDecTable( hcode, im, iM, hdecod ) { + + for ( ; im <= iM; im ++ ) { + + const c = hufCode( hcode[ im ] ); + const l = hufLength( hcode[ im ] ); + + if ( c >> l ) { + + throw new Error( 'Invalid table entry' ); + + } + + if ( l > HUF_DECBITS ) { + + const pl = hdecod[ ( c >> ( l - HUF_DECBITS ) ) ]; + + if ( pl.len ) { + + throw new Error( 'Invalid table entry' ); + + } + + pl.lit ++; + + if ( pl.p ) { + + const p = pl.p; + pl.p = new Array( pl.lit ); + + for ( let i = 0; i < pl.lit - 1; ++ i ) { + + pl.p[ i ] = p[ i ]; + + } + + } else { + + pl.p = new Array( 1 ); + + } + + pl.p[ pl.lit - 1 ] = im; + + } else if ( l ) { + + let plOffset = 0; + + for ( let i = 1 << ( HUF_DECBITS - l ); i > 0; i -- ) { + + const pl = hdecod[ ( c << ( HUF_DECBITS - l ) ) + plOffset ]; + + if ( pl.len || pl.p ) { + + throw new Error( 'Invalid table entry' ); + + } + + pl.len = l; + pl.lit = im; + + plOffset ++; + + } + + } + + } + + return true; + + } + + const getCharReturn = { c: 0, lc: 0 }; + + function getChar( c, lc, uInt8Array, inOffset ) { + + c = ( c << 8 ) | parseUint8Array( uInt8Array, inOffset ); + lc += 8; + + getCharReturn.c = c; + getCharReturn.lc = lc; + + } + + const getCodeReturn = { c: 0, lc: 0 }; + + function getCode( po, rlc, c, lc, uInt8Array, inOffset, outBuffer, outBufferOffset, outBufferEndOffset ) { + + if ( po == rlc ) { + + if ( lc < 8 ) { + + getChar( c, lc, uInt8Array, inOffset ); + c = getCharReturn.c; + lc = getCharReturn.lc; + + } + + lc -= 8; + + let cs = ( c >> lc ); + cs = new Uint8Array( [ cs ] )[ 0 ]; + + if ( outBufferOffset.value + cs > outBufferEndOffset ) { + + return false; + + } + + const s = outBuffer[ outBufferOffset.value - 1 ]; + + while ( cs -- > 0 ) { + + outBuffer[ outBufferOffset.value ++ ] = s; + + } + + } else if ( outBufferOffset.value < outBufferEndOffset ) { + + outBuffer[ outBufferOffset.value ++ ] = po; + + } else { + + return false; + + } + + getCodeReturn.c = c; + getCodeReturn.lc = lc; + + } + + function UInt16( value ) { + + return ( value & 0xFFFF ); + + } + + function Int16( value ) { + + const ref = UInt16( value ); + return ( ref > 0x7FFF ) ? ref - 0x10000 : ref; + + } + + const wdec14Return = { a: 0, b: 0 }; + + function wdec14( l, h ) { + + const ls = Int16( l ); + const hs = Int16( h ); + + const hi = hs; + const ai = ls + ( hi & 1 ) + ( hi >> 1 ); + + const as = ai; + const bs = ai - hi; + + wdec14Return.a = as; + wdec14Return.b = bs; + + } + + function wdec16( l, h ) { + + const m = UInt16( l ); + const d = UInt16( h ); + + const bb = ( m - ( d >> 1 ) ) & MOD_MASK; + const aa = ( d + bb - A_OFFSET ) & MOD_MASK; + + wdec14Return.a = aa; + wdec14Return.b = bb; + + } + + function wav2Decode( buffer, j, nx, ox, ny, oy, mx ) { + + const w14 = mx < ( 1 << 14 ); + const n = ( nx > ny ) ? ny : nx; + let p = 1; + let p2; + let py; + + while ( p <= n ) p <<= 1; + + p >>= 1; + p2 = p; + p >>= 1; + + while ( p >= 1 ) { + + py = 0; + const ey = py + oy * ( ny - p2 ); + const oy1 = oy * p; + const oy2 = oy * p2; + const ox1 = ox * p; + const ox2 = ox * p2; + let i00, i01, i10, i11; + + for ( ; py <= ey; py += oy2 ) { + + let px = py; + const ex = py + ox * ( nx - p2 ); + + for ( ; px <= ex; px += ox2 ) { + + const p01 = px + ox1; + const p10 = px + oy1; + const p11 = p10 + ox1; + + if ( w14 ) { + + wdec14( buffer[ px + j ], buffer[ p10 + j ] ); + + i00 = wdec14Return.a; + i10 = wdec14Return.b; + + wdec14( buffer[ p01 + j ], buffer[ p11 + j ] ); + + i01 = wdec14Return.a; + i11 = wdec14Return.b; + + wdec14( i00, i01 ); + + buffer[ px + j ] = wdec14Return.a; + buffer[ p01 + j ] = wdec14Return.b; + + wdec14( i10, i11 ); + + buffer[ p10 + j ] = wdec14Return.a; + buffer[ p11 + j ] = wdec14Return.b; + + } else { + + wdec16( buffer[ px + j ], buffer[ p10 + j ] ); + + i00 = wdec14Return.a; + i10 = wdec14Return.b; + + wdec16( buffer[ p01 + j ], buffer[ p11 + j ] ); + + i01 = wdec14Return.a; + i11 = wdec14Return.b; + + wdec16( i00, i01 ); + + buffer[ px + j ] = wdec14Return.a; + buffer[ p01 + j ] = wdec14Return.b; + + wdec16( i10, i11 ); + + buffer[ p10 + j ] = wdec14Return.a; + buffer[ p11 + j ] = wdec14Return.b; + + + } + + } + + if ( nx & p ) { + + const p10 = px + oy1; + + if ( w14 ) + wdec14( buffer[ px + j ], buffer[ p10 + j ] ); + else + wdec16( buffer[ px + j ], buffer[ p10 + j ] ); + + i00 = wdec14Return.a; + buffer[ p10 + j ] = wdec14Return.b; + + buffer[ px + j ] = i00; + + } + + } + + if ( ny & p ) { + + let px = py; + const ex = py + ox * ( nx - p2 ); + + for ( ; px <= ex; px += ox2 ) { + + const p01 = px + ox1; + + if ( w14 ) + wdec14( buffer[ px + j ], buffer[ p01 + j ] ); + else + wdec16( buffer[ px + j ], buffer[ p01 + j ] ); + + i00 = wdec14Return.a; + buffer[ p01 + j ] = wdec14Return.b; + + buffer[ px + j ] = i00; + + } + + } + + p2 = p; + p >>= 1; + + } + + return py; + + } + + function hufDecode( encodingTable, decodingTable, uInt8Array, inOffset, ni, rlc, no, outBuffer, outOffset ) { + + let c = 0; + let lc = 0; + const outBufferEndOffset = no; + const inOffsetEnd = Math.trunc( inOffset.value + ( ni + 7 ) / 8 ); + + while ( inOffset.value < inOffsetEnd ) { + + getChar( c, lc, uInt8Array, inOffset ); + + c = getCharReturn.c; + lc = getCharReturn.lc; + + while ( lc >= HUF_DECBITS ) { + + const index = ( c >> ( lc - HUF_DECBITS ) ) & HUF_DECMASK; + const pl = decodingTable[ index ]; + + if ( pl.len ) { + + lc -= pl.len; + + getCode( pl.lit, rlc, c, lc, uInt8Array, inOffset, outBuffer, outOffset, outBufferEndOffset ); + + c = getCodeReturn.c; + lc = getCodeReturn.lc; + + } else { + + if ( ! pl.p ) { + + throw new Error( 'hufDecode issues' ); + + } + + let j; + + for ( j = 0; j < pl.lit; j ++ ) { + + const l = hufLength( encodingTable[ pl.p[ j ] ] ); + + while ( lc < l && inOffset.value < inOffsetEnd ) { + + getChar( c, lc, uInt8Array, inOffset ); + + c = getCharReturn.c; + lc = getCharReturn.lc; + + } + + if ( lc >= l ) { + + if ( hufCode( encodingTable[ pl.p[ j ] ] ) == ( ( c >> ( lc - l ) ) & ( ( 1 << l ) - 1 ) ) ) { + + lc -= l; + + getCode( pl.p[ j ], rlc, c, lc, uInt8Array, inOffset, outBuffer, outOffset, outBufferEndOffset ); + + c = getCodeReturn.c; + lc = getCodeReturn.lc; + + break; + + } + + } + + } + + if ( j == pl.lit ) { + + throw new Error( 'hufDecode issues' ); + + } + + } + + } + + } + + const i = ( 8 - ni ) & 7; + + c >>= i; + lc -= i; + + while ( lc > 0 ) { + + const pl = decodingTable[ ( c << ( HUF_DECBITS - lc ) ) & HUF_DECMASK ]; + + if ( pl.len ) { + + lc -= pl.len; + + getCode( pl.lit, rlc, c, lc, uInt8Array, inOffset, outBuffer, outOffset, outBufferEndOffset ); + + c = getCodeReturn.c; + lc = getCodeReturn.lc; + + } else { + + throw new Error( 'hufDecode issues' ); + + } + + } + + return true; + + } + + function hufUncompress( uInt8Array, inDataView, inOffset, nCompressed, outBuffer, nRaw ) { + + const outOffset = { value: 0 }; + const initialInOffset = inOffset.value; + + const im = parseUint32( inDataView, inOffset ); + const iM = parseUint32( inDataView, inOffset ); + + inOffset.value += 4; + + const nBits = parseUint32( inDataView, inOffset ); + + inOffset.value += 4; + + if ( im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE ) { + + throw new Error( 'Something wrong with HUF_ENCSIZE' ); + + } + + const freq = new Array( HUF_ENCSIZE ); + const hdec = new Array( HUF_DECSIZE ); + + hufClearDecTable( hdec ); + + const ni = nCompressed - ( inOffset.value - initialInOffset ); + + hufUnpackEncTable( uInt8Array, inOffset, ni, im, iM, freq ); + + if ( nBits > 8 * ( nCompressed - ( inOffset.value - initialInOffset ) ) ) { + + throw new Error( 'Something wrong with hufUncompress' ); + + } + + hufBuildDecTable( freq, im, iM, hdec ); + + hufDecode( freq, hdec, uInt8Array, inOffset, nBits, iM, nRaw, outBuffer, outOffset ); + + } + + function applyLut( lut, data, nData ) { + + for ( let i = 0; i < nData; ++ i ) { + + data[ i ] = lut[ data[ i ] ]; + + } + + } + + function predictor( source ) { + + for ( let t = 1; t < source.length; t ++ ) { + + const d = source[ t - 1 ] + source[ t ] - 128; + source[ t ] = d; + + } + + } + + function interleaveScalar( source, out ) { + + let t1 = 0; + let t2 = Math.floor( ( source.length + 1 ) / 2 ); + let s = 0; + const stop = source.length - 1; + + while ( true ) { + + if ( s > stop ) break; + out[ s ++ ] = source[ t1 ++ ]; + + if ( s > stop ) break; + out[ s ++ ] = source[ t2 ++ ]; + + } + + } + + function decodeRunLength( source ) { + + let size = source.byteLength; + const out = new Array(); + let p = 0; + + const reader = new DataView( source ); + + while ( size > 0 ) { + + const l = reader.getInt8( p ++ ); + + if ( l < 0 ) { + + const count = - l; + size -= count + 1; + + for ( let i = 0; i < count; i ++ ) { + + out.push( reader.getUint8( p ++ ) ); + + } + + + } else { + + const count = l; + size -= 2; + + const value = reader.getUint8( p ++ ); + + for ( let i = 0; i < count + 1; i ++ ) { + + out.push( value ); + + } + + } + + } + + return out; + + } + + function lossyDctDecode( cscSet, rowPtrs, channelData, acBuffer, dcBuffer, outBuffer ) { + + let dataView = new DataView( outBuffer.buffer ); + + const width = channelData[ cscSet.idx[ 0 ] ].width; + const height = channelData[ cscSet.idx[ 0 ] ].height; + + const numComp = 3; + + const numFullBlocksX = Math.floor( width / 8.0 ); + const numBlocksX = Math.ceil( width / 8.0 ); + const numBlocksY = Math.ceil( height / 8.0 ); + const leftoverX = width - ( numBlocksX - 1 ) * 8; + const leftoverY = height - ( numBlocksY - 1 ) * 8; + + const currAcComp = { value: 0 }; + const currDcComp = new Array( numComp ); + const dctData = new Array( numComp ); + const halfZigBlock = new Array( numComp ); + const rowBlock = new Array( numComp ); + const rowOffsets = new Array( numComp ); + + for ( let comp = 0; comp < numComp; ++ comp ) { + + rowOffsets[ comp ] = rowPtrs[ cscSet.idx[ comp ] ]; + currDcComp[ comp ] = ( comp < 1 ) ? 0 : currDcComp[ comp - 1 ] + numBlocksX * numBlocksY; + dctData[ comp ] = new Float32Array( 64 ); + halfZigBlock[ comp ] = new Uint16Array( 64 ); + rowBlock[ comp ] = new Uint16Array( numBlocksX * 64 ); + + } + + for ( let blocky = 0; blocky < numBlocksY; ++ blocky ) { + + let maxY = 8; + + if ( blocky == numBlocksY - 1 ) + maxY = leftoverY; + + let maxX = 8; + + for ( let blockx = 0; blockx < numBlocksX; ++ blockx ) { + + if ( blockx == numBlocksX - 1 ) + maxX = leftoverX; + + for ( let comp = 0; comp < numComp; ++ comp ) { + + halfZigBlock[ comp ].fill( 0 ); + + // set block DC component + halfZigBlock[ comp ][ 0 ] = dcBuffer[ currDcComp[ comp ] ++ ]; + // set block AC components + unRleAC( currAcComp, acBuffer, halfZigBlock[ comp ] ); + + // UnZigZag block to float + unZigZag( halfZigBlock[ comp ], dctData[ comp ] ); + // decode float dct + dctInverse( dctData[ comp ] ); + + } + + if ( numComp == 3 ) { + + csc709Inverse( dctData ); + + } + + for ( let comp = 0; comp < numComp; ++ comp ) { + + convertToHalf( dctData[ comp ], rowBlock[ comp ], blockx * 64 ); + + } + + } // blockx + + let offset = 0; + + for ( let comp = 0; comp < numComp; ++ comp ) { + + const type = channelData[ cscSet.idx[ comp ] ].type; + + for ( let y = 8 * blocky; y < 8 * blocky + maxY; ++ y ) { + + offset = rowOffsets[ comp ][ y ]; + + for ( let blockx = 0; blockx < numFullBlocksX; ++ blockx ) { + + const src = blockx * 64 + ( ( y & 0x7 ) * 8 ); + + dataView.setUint16( offset + 0 * INT16_SIZE * type, rowBlock[ comp ][ src + 0 ], true ); + dataView.setUint16( offset + 1 * INT16_SIZE * type, rowBlock[ comp ][ src + 1 ], true ); + dataView.setUint16( offset + 2 * INT16_SIZE * type, rowBlock[ comp ][ src + 2 ], true ); + dataView.setUint16( offset + 3 * INT16_SIZE * type, rowBlock[ comp ][ src + 3 ], true ); + + dataView.setUint16( offset + 4 * INT16_SIZE * type, rowBlock[ comp ][ src + 4 ], true ); + dataView.setUint16( offset + 5 * INT16_SIZE * type, rowBlock[ comp ][ src + 5 ], true ); + dataView.setUint16( offset + 6 * INT16_SIZE * type, rowBlock[ comp ][ src + 6 ], true ); + dataView.setUint16( offset + 7 * INT16_SIZE * type, rowBlock[ comp ][ src + 7 ], true ); + + offset += 8 * INT16_SIZE * type; + + } + + } + + // handle partial X blocks + if ( numFullBlocksX != numBlocksX ) { + + for ( let y = 8 * blocky; y < 8 * blocky + maxY; ++ y ) { + + const offset = rowOffsets[ comp ][ y ] + 8 * numFullBlocksX * INT16_SIZE * type; + const src = numFullBlocksX * 64 + ( ( y & 0x7 ) * 8 ); + + for ( let x = 0; x < maxX; ++ x ) { + + dataView.setUint16( offset + x * INT16_SIZE * type, rowBlock[ comp ][ src + x ], true ); + + } + + } + + } + + } // comp + + } // blocky + + const halfRow = new Uint16Array( width ); + dataView = new DataView( outBuffer.buffer ); + + // convert channels back to float, if needed + for ( let comp = 0; comp < numComp; ++ comp ) { + + channelData[ cscSet.idx[ comp ] ].decoded = true; + const type = channelData[ cscSet.idx[ comp ] ].type; + + if ( channelData[ comp ].type != 2 ) continue; + + for ( let y = 0; y < height; ++ y ) { + + const offset = rowOffsets[ comp ][ y ]; + + for ( let x = 0; x < width; ++ x ) { + + halfRow[ x ] = dataView.getUint16( offset + x * INT16_SIZE * type, true ); + + } + + for ( let x = 0; x < width; ++ x ) { + + dataView.setFloat32( offset + x * INT16_SIZE * type, decodeFloat16( halfRow[ x ] ), true ); + + } + + } + + } + + } + + function unRleAC( currAcComp, acBuffer, halfZigBlock ) { + + let acValue; + let dctComp = 1; + + while ( dctComp < 64 ) { + + acValue = acBuffer[ currAcComp.value ]; + + if ( acValue == 0xff00 ) { + + dctComp = 64; + + } else if ( acValue >> 8 == 0xff ) { + + dctComp += acValue & 0xff; + + } else { + + halfZigBlock[ dctComp ] = acValue; + dctComp ++; + + } + + currAcComp.value ++; + + } + + } + + function unZigZag( src, dst ) { + + dst[ 0 ] = decodeFloat16( src[ 0 ] ); + dst[ 1 ] = decodeFloat16( src[ 1 ] ); + dst[ 2 ] = decodeFloat16( src[ 5 ] ); + dst[ 3 ] = decodeFloat16( src[ 6 ] ); + dst[ 4 ] = decodeFloat16( src[ 14 ] ); + dst[ 5 ] = decodeFloat16( src[ 15 ] ); + dst[ 6 ] = decodeFloat16( src[ 27 ] ); + dst[ 7 ] = decodeFloat16( src[ 28 ] ); + dst[ 8 ] = decodeFloat16( src[ 2 ] ); + dst[ 9 ] = decodeFloat16( src[ 4 ] ); + + dst[ 10 ] = decodeFloat16( src[ 7 ] ); + dst[ 11 ] = decodeFloat16( src[ 13 ] ); + dst[ 12 ] = decodeFloat16( src[ 16 ] ); + dst[ 13 ] = decodeFloat16( src[ 26 ] ); + dst[ 14 ] = decodeFloat16( src[ 29 ] ); + dst[ 15 ] = decodeFloat16( src[ 42 ] ); + dst[ 16 ] = decodeFloat16( src[ 3 ] ); + dst[ 17 ] = decodeFloat16( src[ 8 ] ); + dst[ 18 ] = decodeFloat16( src[ 12 ] ); + dst[ 19 ] = decodeFloat16( src[ 17 ] ); + + dst[ 20 ] = decodeFloat16( src[ 25 ] ); + dst[ 21 ] = decodeFloat16( src[ 30 ] ); + dst[ 22 ] = decodeFloat16( src[ 41 ] ); + dst[ 23 ] = decodeFloat16( src[ 43 ] ); + dst[ 24 ] = decodeFloat16( src[ 9 ] ); + dst[ 25 ] = decodeFloat16( src[ 11 ] ); + dst[ 26 ] = decodeFloat16( src[ 18 ] ); + dst[ 27 ] = decodeFloat16( src[ 24 ] ); + dst[ 28 ] = decodeFloat16( src[ 31 ] ); + dst[ 29 ] = decodeFloat16( src[ 40 ] ); + + dst[ 30 ] = decodeFloat16( src[ 44 ] ); + dst[ 31 ] = decodeFloat16( src[ 53 ] ); + dst[ 32 ] = decodeFloat16( src[ 10 ] ); + dst[ 33 ] = decodeFloat16( src[ 19 ] ); + dst[ 34 ] = decodeFloat16( src[ 23 ] ); + dst[ 35 ] = decodeFloat16( src[ 32 ] ); + dst[ 36 ] = decodeFloat16( src[ 39 ] ); + dst[ 37 ] = decodeFloat16( src[ 45 ] ); + dst[ 38 ] = decodeFloat16( src[ 52 ] ); + dst[ 39 ] = decodeFloat16( src[ 54 ] ); + + dst[ 40 ] = decodeFloat16( src[ 20 ] ); + dst[ 41 ] = decodeFloat16( src[ 22 ] ); + dst[ 42 ] = decodeFloat16( src[ 33 ] ); + dst[ 43 ] = decodeFloat16( src[ 38 ] ); + dst[ 44 ] = decodeFloat16( src[ 46 ] ); + dst[ 45 ] = decodeFloat16( src[ 51 ] ); + dst[ 46 ] = decodeFloat16( src[ 55 ] ); + dst[ 47 ] = decodeFloat16( src[ 60 ] ); + dst[ 48 ] = decodeFloat16( src[ 21 ] ); + dst[ 49 ] = decodeFloat16( src[ 34 ] ); + + dst[ 50 ] = decodeFloat16( src[ 37 ] ); + dst[ 51 ] = decodeFloat16( src[ 47 ] ); + dst[ 52 ] = decodeFloat16( src[ 50 ] ); + dst[ 53 ] = decodeFloat16( src[ 56 ] ); + dst[ 54 ] = decodeFloat16( src[ 59 ] ); + dst[ 55 ] = decodeFloat16( src[ 61 ] ); + dst[ 56 ] = decodeFloat16( src[ 35 ] ); + dst[ 57 ] = decodeFloat16( src[ 36 ] ); + dst[ 58 ] = decodeFloat16( src[ 48 ] ); + dst[ 59 ] = decodeFloat16( src[ 49 ] ); + + dst[ 60 ] = decodeFloat16( src[ 57 ] ); + dst[ 61 ] = decodeFloat16( src[ 58 ] ); + dst[ 62 ] = decodeFloat16( src[ 62 ] ); + dst[ 63 ] = decodeFloat16( src[ 63 ] ); + + } + + function dctInverse( data ) { + + const a = 0.5 * Math.cos( 3.14159 / 4.0 ); + const b = 0.5 * Math.cos( 3.14159 / 16.0 ); + const c = 0.5 * Math.cos( 3.14159 / 8.0 ); + const d = 0.5 * Math.cos( 3.0 * 3.14159 / 16.0 ); + const e = 0.5 * Math.cos( 5.0 * 3.14159 / 16.0 ); + const f = 0.5 * Math.cos( 3.0 * 3.14159 / 8.0 ); + const g = 0.5 * Math.cos( 7.0 * 3.14159 / 16.0 ); + + const alpha = new Array( 4 ); + const beta = new Array( 4 ); + const theta = new Array( 4 ); + const gamma = new Array( 4 ); + + for ( let row = 0; row < 8; ++ row ) { + + const rowPtr = row * 8; + + alpha[ 0 ] = c * data[ rowPtr + 2 ]; + alpha[ 1 ] = f * data[ rowPtr + 2 ]; + alpha[ 2 ] = c * data[ rowPtr + 6 ]; + alpha[ 3 ] = f * data[ rowPtr + 6 ]; + + beta[ 0 ] = b * data[ rowPtr + 1 ] + d * data[ rowPtr + 3 ] + e * data[ rowPtr + 5 ] + g * data[ rowPtr + 7 ]; + beta[ 1 ] = d * data[ rowPtr + 1 ] - g * data[ rowPtr + 3 ] - b * data[ rowPtr + 5 ] - e * data[ rowPtr + 7 ]; + beta[ 2 ] = e * data[ rowPtr + 1 ] - b * data[ rowPtr + 3 ] + g * data[ rowPtr + 5 ] + d * data[ rowPtr + 7 ]; + beta[ 3 ] = g * data[ rowPtr + 1 ] - e * data[ rowPtr + 3 ] + d * data[ rowPtr + 5 ] - b * data[ rowPtr + 7 ]; + + theta[ 0 ] = a * ( data[ rowPtr + 0 ] + data[ rowPtr + 4 ] ); + theta[ 3 ] = a * ( data[ rowPtr + 0 ] - data[ rowPtr + 4 ] ); + theta[ 1 ] = alpha[ 0 ] + alpha[ 3 ]; + theta[ 2 ] = alpha[ 1 ] - alpha[ 2 ]; + + gamma[ 0 ] = theta[ 0 ] + theta[ 1 ]; + gamma[ 1 ] = theta[ 3 ] + theta[ 2 ]; + gamma[ 2 ] = theta[ 3 ] - theta[ 2 ]; + gamma[ 3 ] = theta[ 0 ] - theta[ 1 ]; + + data[ rowPtr + 0 ] = gamma[ 0 ] + beta[ 0 ]; + data[ rowPtr + 1 ] = gamma[ 1 ] + beta[ 1 ]; + data[ rowPtr + 2 ] = gamma[ 2 ] + beta[ 2 ]; + data[ rowPtr + 3 ] = gamma[ 3 ] + beta[ 3 ]; + + data[ rowPtr + 4 ] = gamma[ 3 ] - beta[ 3 ]; + data[ rowPtr + 5 ] = gamma[ 2 ] - beta[ 2 ]; + data[ rowPtr + 6 ] = gamma[ 1 ] - beta[ 1 ]; + data[ rowPtr + 7 ] = gamma[ 0 ] - beta[ 0 ]; + + } + + for ( let column = 0; column < 8; ++ column ) { + + alpha[ 0 ] = c * data[ 16 + column ]; + alpha[ 1 ] = f * data[ 16 + column ]; + alpha[ 2 ] = c * data[ 48 + column ]; + alpha[ 3 ] = f * data[ 48 + column ]; + + beta[ 0 ] = b * data[ 8 + column ] + d * data[ 24 + column ] + e * data[ 40 + column ] + g * data[ 56 + column ]; + beta[ 1 ] = d * data[ 8 + column ] - g * data[ 24 + column ] - b * data[ 40 + column ] - e * data[ 56 + column ]; + beta[ 2 ] = e * data[ 8 + column ] - b * data[ 24 + column ] + g * data[ 40 + column ] + d * data[ 56 + column ]; + beta[ 3 ] = g * data[ 8 + column ] - e * data[ 24 + column ] + d * data[ 40 + column ] - b * data[ 56 + column ]; + + theta[ 0 ] = a * ( data[ column ] + data[ 32 + column ] ); + theta[ 3 ] = a * ( data[ column ] - data[ 32 + column ] ); + + theta[ 1 ] = alpha[ 0 ] + alpha[ 3 ]; + theta[ 2 ] = alpha[ 1 ] - alpha[ 2 ]; + + gamma[ 0 ] = theta[ 0 ] + theta[ 1 ]; + gamma[ 1 ] = theta[ 3 ] + theta[ 2 ]; + gamma[ 2 ] = theta[ 3 ] - theta[ 2 ]; + gamma[ 3 ] = theta[ 0 ] - theta[ 1 ]; + + data[ 0 + column ] = gamma[ 0 ] + beta[ 0 ]; + data[ 8 + column ] = gamma[ 1 ] + beta[ 1 ]; + data[ 16 + column ] = gamma[ 2 ] + beta[ 2 ]; + data[ 24 + column ] = gamma[ 3 ] + beta[ 3 ]; + + data[ 32 + column ] = gamma[ 3 ] - beta[ 3 ]; + data[ 40 + column ] = gamma[ 2 ] - beta[ 2 ]; + data[ 48 + column ] = gamma[ 1 ] - beta[ 1 ]; + data[ 56 + column ] = gamma[ 0 ] - beta[ 0 ]; + + } + + } + + function csc709Inverse( data ) { + + for ( let i = 0; i < 64; ++ i ) { + + const y = data[ 0 ][ i ]; + const cb = data[ 1 ][ i ]; + const cr = data[ 2 ][ i ]; + + data[ 0 ][ i ] = y + 1.5747 * cr; + data[ 1 ][ i ] = y - 0.1873 * cb - 0.4682 * cr; + data[ 2 ][ i ] = y + 1.8556 * cb; + + } + + } + + function convertToHalf( src, dst, idx ) { + + for ( let i = 0; i < 64; ++ i ) { + + dst[ idx + i ] = DataUtils.toHalfFloat( toLinear( src[ i ] ) ); + + } + + } + + function toLinear( float ) { + + if ( float <= 1 ) { + + return Math.sign( float ) * Math.pow( Math.abs( float ), 2.2 ); + + } else { + + return Math.sign( float ) * Math.pow( logBase, Math.abs( float ) - 1.0 ); + + } + + } + + function uncompressRAW( info ) { + + return new DataView( info.array.buffer, info.offset.value, info.size ); + + } + + function uncompressRLE( info ) { + + const compressed = info.viewer.buffer.slice( info.offset.value, info.offset.value + info.size ); + + const rawBuffer = new Uint8Array( decodeRunLength( compressed ) ); + const tmpBuffer = new Uint8Array( rawBuffer.length ); + + predictor( rawBuffer ); // revert predictor + + interleaveScalar( rawBuffer, tmpBuffer ); // interleave pixels + + return new DataView( tmpBuffer.buffer ); + + } + + function uncompressZIP( info ) { + + const compressed = info.array.slice( info.offset.value, info.offset.value + info.size ); + + const rawBuffer = fflate.unzlibSync( compressed ); + const tmpBuffer = new Uint8Array( rawBuffer.length ); + + predictor( rawBuffer ); // revert predictor + + interleaveScalar( rawBuffer, tmpBuffer ); // interleave pixels + + return new DataView( tmpBuffer.buffer ); + + } + + function uncompressPIZ( info ) { + + const inDataView = info.viewer; + const inOffset = { value: info.offset.value }; + + const outBuffer = new Uint16Array( info.columns * info.lines * ( info.inputChannels.length * info.type ) ); + const bitmap = new Uint8Array( BITMAP_SIZE ); + + // Setup channel info + let outBufferEnd = 0; + const pizChannelData = new Array( info.inputChannels.length ); + for ( let i = 0, il = info.inputChannels.length; i < il; i ++ ) { + + pizChannelData[ i ] = {}; + pizChannelData[ i ][ 'start' ] = outBufferEnd; + pizChannelData[ i ][ 'end' ] = pizChannelData[ i ][ 'start' ]; + pizChannelData[ i ][ 'nx' ] = info.columns; + pizChannelData[ i ][ 'ny' ] = info.lines; + pizChannelData[ i ][ 'size' ] = info.type; + + outBufferEnd += pizChannelData[ i ].nx * pizChannelData[ i ].ny * pizChannelData[ i ].size; + + } + + // Read range compression data + + const minNonZero = parseUint16( inDataView, inOffset ); + const maxNonZero = parseUint16( inDataView, inOffset ); + + if ( maxNonZero >= BITMAP_SIZE ) { + + throw new Error( 'Something is wrong with PIZ_COMPRESSION BITMAP_SIZE' ); + + } + + if ( minNonZero <= maxNonZero ) { + + for ( let i = 0; i < maxNonZero - minNonZero + 1; i ++ ) { + + bitmap[ i + minNonZero ] = parseUint8( inDataView, inOffset ); + + } + + } + + // Reverse LUT + const lut = new Uint16Array( USHORT_RANGE ); + const maxValue = reverseLutFromBitmap( bitmap, lut ); + + const length = parseUint32( inDataView, inOffset ); + + // Huffman decoding + hufUncompress( info.array, inDataView, inOffset, length, outBuffer, outBufferEnd ); + + // Wavelet decoding + for ( let i = 0; i < info.inputChannels.length; ++ i ) { + + const cd = pizChannelData[ i ]; + + for ( let j = 0; j < pizChannelData[ i ].size; ++ j ) { + + wav2Decode( + outBuffer, + cd.start + j, + cd.nx, + cd.size, + cd.ny, + cd.nx * cd.size, + maxValue + ); + + } + + } + + // Expand the pixel data to their original range + applyLut( lut, outBuffer, outBufferEnd ); + + // Rearrange the pixel data into the format expected by the caller. + let tmpOffset = 0; + const tmpBuffer = new Uint8Array( outBuffer.buffer.byteLength ); + for ( let y = 0; y < info.lines; y ++ ) { + + for ( let c = 0; c < info.inputChannels.length; c ++ ) { + + const cd = pizChannelData[ c ]; + + const n = cd.nx * cd.size; + const cp = new Uint8Array( outBuffer.buffer, cd.end * INT16_SIZE, n * INT16_SIZE ); + + tmpBuffer.set( cp, tmpOffset ); + tmpOffset += n * INT16_SIZE; + cd.end += n; + + } + + } + + return new DataView( tmpBuffer.buffer ); + + } + + function uncompressPXR( info ) { + + const compressed = info.array.slice( info.offset.value, info.offset.value + info.size ); + + const rawBuffer = fflate.unzlibSync( compressed ); + + const byteSize = info.inputChannels.length * info.lines * info.columns * info.totalBytes; + const tmpBuffer = new ArrayBuffer( byteSize ); + const viewer = new DataView( tmpBuffer ); + + let tmpBufferEnd = 0; + let writePtr = 0; + const ptr = new Array( 4 ); + + for ( let y = 0; y < info.lines; y ++ ) { + + for ( let c = 0; c < info.inputChannels.length; c ++ ) { + + let pixel = 0; + + const type = info.inputChannels[ c ].pixelType; + switch ( type ) { + + case 1: + + ptr[ 0 ] = tmpBufferEnd; + ptr[ 1 ] = ptr[ 0 ] + info.columns; + tmpBufferEnd = ptr[ 1 ] + info.columns; + + for ( let j = 0; j < info.columns; ++ j ) { + + const diff = ( rawBuffer[ ptr[ 0 ] ++ ] << 8 ) | rawBuffer[ ptr[ 1 ] ++ ]; + + pixel += diff; + + viewer.setUint16( writePtr, pixel, true ); + writePtr += 2; + + } + + break; + + case 2: + + ptr[ 0 ] = tmpBufferEnd; + ptr[ 1 ] = ptr[ 0 ] + info.columns; + ptr[ 2 ] = ptr[ 1 ] + info.columns; + tmpBufferEnd = ptr[ 2 ] + info.columns; + + for ( let j = 0; j < info.columns; ++ j ) { + + const diff = ( rawBuffer[ ptr[ 0 ] ++ ] << 24 ) | ( rawBuffer[ ptr[ 1 ] ++ ] << 16 ) | ( rawBuffer[ ptr[ 2 ] ++ ] << 8 ); + + pixel += diff; + + viewer.setUint32( writePtr, pixel, true ); + writePtr += 4; + + } + + break; + + } + + } + + } + + return viewer; + + } + + function uncompressDWA( info ) { + + const inDataView = info.viewer; + const inOffset = { value: info.offset.value }; + const outBuffer = new Uint8Array( info.columns * info.lines * ( info.inputChannels.length * info.type * INT16_SIZE ) ); + + // Read compression header information + const dwaHeader = { + + version: parseInt64( inDataView, inOffset ), + unknownUncompressedSize: parseInt64( inDataView, inOffset ), + unknownCompressedSize: parseInt64( inDataView, inOffset ), + acCompressedSize: parseInt64( inDataView, inOffset ), + dcCompressedSize: parseInt64( inDataView, inOffset ), + rleCompressedSize: parseInt64( inDataView, inOffset ), + rleUncompressedSize: parseInt64( inDataView, inOffset ), + rleRawSize: parseInt64( inDataView, inOffset ), + totalAcUncompressedCount: parseInt64( inDataView, inOffset ), + totalDcUncompressedCount: parseInt64( inDataView, inOffset ), + acCompression: parseInt64( inDataView, inOffset ) + + }; + + if ( dwaHeader.version < 2 ) + throw new Error( 'EXRLoader.parse: ' + EXRHeader.compression + ' version ' + dwaHeader.version + ' is unsupported' ); + + // Read channel ruleset information + const channelRules = new Array(); + let ruleSize = parseUint16( inDataView, inOffset ) - INT16_SIZE; + + while ( ruleSize > 0 ) { + + const name = parseNullTerminatedString( inDataView.buffer, inOffset ); + const value = parseUint8( inDataView, inOffset ); + const compression = ( value >> 2 ) & 3; + const csc = ( value >> 4 ) - 1; + const index = new Int8Array( [ csc ] )[ 0 ]; + const type = parseUint8( inDataView, inOffset ); + + channelRules.push( { + name: name, + index: index, + type: type, + compression: compression, + } ); + + ruleSize -= name.length + 3; + + } + + // Classify channels + const channels = EXRHeader.channels; + const channelData = new Array( info.inputChannels.length ); + + for ( let i = 0; i < info.inputChannels.length; ++ i ) { + + const cd = channelData[ i ] = {}; + const channel = channels[ i ]; + + cd.name = channel.name; + cd.compression = UNKNOWN; + cd.decoded = false; + cd.type = channel.pixelType; + cd.pLinear = channel.pLinear; + cd.width = info.columns; + cd.height = info.lines; + + } + + const cscSet = { + idx: new Array( 3 ) + }; + + for ( let offset = 0; offset < info.inputChannels.length; ++ offset ) { + + const cd = channelData[ offset ]; + + for ( let i = 0; i < channelRules.length; ++ i ) { + + const rule = channelRules[ i ]; + + if ( cd.name == rule.name ) { + + cd.compression = rule.compression; + + if ( rule.index >= 0 ) { + + cscSet.idx[ rule.index ] = offset; + + } + + cd.offset = offset; + + } + + } + + } + + let acBuffer, dcBuffer, rleBuffer; + + // Read DCT - AC component data + if ( dwaHeader.acCompressedSize > 0 ) { + + switch ( dwaHeader.acCompression ) { + + case STATIC_HUFFMAN: + + acBuffer = new Uint16Array( dwaHeader.totalAcUncompressedCount ); + hufUncompress( info.array, inDataView, inOffset, dwaHeader.acCompressedSize, acBuffer, dwaHeader.totalAcUncompressedCount ); + break; + + case DEFLATE: + + const compressed = info.array.slice( inOffset.value, inOffset.value + dwaHeader.totalAcUncompressedCount ); + const data = fflate.unzlibSync( compressed ); + acBuffer = new Uint16Array( data.buffer ); + inOffset.value += dwaHeader.totalAcUncompressedCount; + break; + + } + + + } + + // Read DCT - DC component data + if ( dwaHeader.dcCompressedSize > 0 ) { + + const zlibInfo = { + array: info.array, + offset: inOffset, + size: dwaHeader.dcCompressedSize + }; + dcBuffer = new Uint16Array( uncompressZIP( zlibInfo ).buffer ); + inOffset.value += dwaHeader.dcCompressedSize; + + } + + // Read RLE compressed data + if ( dwaHeader.rleRawSize > 0 ) { + + const compressed = info.array.slice( inOffset.value, inOffset.value + dwaHeader.rleCompressedSize ); + const data = fflate.unzlibSync( compressed ); + rleBuffer = decodeRunLength( data.buffer ); + + inOffset.value += dwaHeader.rleCompressedSize; + + } + + // Prepare outbuffer data offset + let outBufferEnd = 0; + const rowOffsets = new Array( channelData.length ); + for ( let i = 0; i < rowOffsets.length; ++ i ) { + + rowOffsets[ i ] = new Array(); + + } + + for ( let y = 0; y < info.lines; ++ y ) { + + for ( let chan = 0; chan < channelData.length; ++ chan ) { + + rowOffsets[ chan ].push( outBufferEnd ); + outBufferEnd += channelData[ chan ].width * info.type * INT16_SIZE; + + } + + } + + // Lossy DCT decode RGB channels + lossyDctDecode( cscSet, rowOffsets, channelData, acBuffer, dcBuffer, outBuffer ); + + // Decode other channels + for ( let i = 0; i < channelData.length; ++ i ) { + + const cd = channelData[ i ]; + + if ( cd.decoded ) continue; + + switch ( cd.compression ) { + + case RLE: + + let row = 0; + let rleOffset = 0; + + for ( let y = 0; y < info.lines; ++ y ) { + + let rowOffsetBytes = rowOffsets[ i ][ row ]; + + for ( let x = 0; x < cd.width; ++ x ) { + + for ( let byte = 0; byte < INT16_SIZE * cd.type; ++ byte ) { + + outBuffer[ rowOffsetBytes ++ ] = rleBuffer[ rleOffset + byte * cd.width * cd.height ]; + + } + + rleOffset ++; + + } + + row ++; + + } + + break; + + case LOSSY_DCT: // skip + + default: + throw new Error( 'EXRLoader.parse: unsupported channel compression' ); + + } + + } + + return new DataView( outBuffer.buffer ); + + } + + function parseNullTerminatedString( buffer, offset ) { + + const uintBuffer = new Uint8Array( buffer ); + let endOffset = 0; + + while ( uintBuffer[ offset.value + endOffset ] != 0 ) { + + endOffset += 1; + + } + + const stringValue = new TextDecoder().decode( + uintBuffer.slice( offset.value, offset.value + endOffset ) + ); + + offset.value = offset.value + endOffset + 1; + + return stringValue; + + } + + function parseFixedLengthString( buffer, offset, size ) { + + const stringValue = new TextDecoder().decode( + new Uint8Array( buffer ).slice( offset.value, offset.value + size ) + ); + + offset.value = offset.value + size; + + return stringValue; + + } + + function parseRational( dataView, offset ) { + + const x = parseInt32( dataView, offset ); + const y = parseUint32( dataView, offset ); + + return [ x, y ]; + + } + + function parseTimecode( dataView, offset ) { + + const x = parseUint32( dataView, offset ); + const y = parseUint32( dataView, offset ); + + return [ x, y ]; + + } + + function parseInt32( dataView, offset ) { + + const Int32 = dataView.getInt32( offset.value, true ); + + offset.value = offset.value + INT32_SIZE; + + return Int32; + + } + + function parseUint32( dataView, offset ) { + + const Uint32 = dataView.getUint32( offset.value, true ); + + offset.value = offset.value + INT32_SIZE; + + return Uint32; + + } + + function parseUint8Array( uInt8Array, offset ) { + + const Uint8 = uInt8Array[ offset.value ]; + + offset.value = offset.value + INT8_SIZE; + + return Uint8; + + } + + function parseUint8( dataView, offset ) { + + const Uint8 = dataView.getUint8( offset.value ); + + offset.value = offset.value + INT8_SIZE; + + return Uint8; + + } + + const parseInt64 = function ( dataView, offset ) { + + let int; + + if ( 'getBigInt64' in DataView.prototype ) { + + int = Number( dataView.getBigInt64( offset.value, true ) ); + + } else { + + int = dataView.getUint32( offset.value + 4, true ) + Number( dataView.getUint32( offset.value, true ) << 32 ); + + } + + offset.value += ULONG_SIZE; + + return int; + + }; + + function parseFloat32( dataView, offset ) { + + const float = dataView.getFloat32( offset.value, true ); + + offset.value += FLOAT32_SIZE; + + return float; + + } + + function decodeFloat32( dataView, offset ) { + + return DataUtils.toHalfFloat( parseFloat32( dataView, offset ) ); + + } + + // https://stackoverflow.com/questions/5678432/decompressing-half-precision-floats-in-javascript + function decodeFloat16( binary ) { + + const exponent = ( binary & 0x7C00 ) >> 10, + fraction = binary & 0x03FF; + + return ( binary >> 15 ? - 1 : 1 ) * ( + exponent ? + ( + exponent === 0x1F ? + fraction ? NaN : Infinity : + Math.pow( 2, exponent - 15 ) * ( 1 + fraction / 0x400 ) + ) : + 6.103515625e-5 * ( fraction / 0x400 ) + ); + + } + + function parseUint16( dataView, offset ) { + + const Uint16 = dataView.getUint16( offset.value, true ); + + offset.value += INT16_SIZE; + + return Uint16; + + } + + function parseFloat16( buffer, offset ) { + + return decodeFloat16( parseUint16( buffer, offset ) ); + + } + + function parseChlist( dataView, buffer, offset, size ) { + + const startOffset = offset.value; + const channels = []; + + while ( offset.value < ( startOffset + size - 1 ) ) { + + const name = parseNullTerminatedString( buffer, offset ); + const pixelType = parseInt32( dataView, offset ); + const pLinear = parseUint8( dataView, offset ); + offset.value += 3; // reserved, three chars + const xSampling = parseInt32( dataView, offset ); + const ySampling = parseInt32( dataView, offset ); + + channels.push( { + name: name, + pixelType: pixelType, + pLinear: pLinear, + xSampling: xSampling, + ySampling: ySampling + } ); + + } + + offset.value += 1; + + return channels; + + } + + function parseChromaticities( dataView, offset ) { + + const redX = parseFloat32( dataView, offset ); + const redY = parseFloat32( dataView, offset ); + const greenX = parseFloat32( dataView, offset ); + const greenY = parseFloat32( dataView, offset ); + const blueX = parseFloat32( dataView, offset ); + const blueY = parseFloat32( dataView, offset ); + const whiteX = parseFloat32( dataView, offset ); + const whiteY = parseFloat32( dataView, offset ); + + return { redX: redX, redY: redY, greenX: greenX, greenY: greenY, blueX: blueX, blueY: blueY, whiteX: whiteX, whiteY: whiteY }; + + } + + function parseCompression( dataView, offset ) { + + const compressionCodes = [ + 'NO_COMPRESSION', + 'RLE_COMPRESSION', + 'ZIPS_COMPRESSION', + 'ZIP_COMPRESSION', + 'PIZ_COMPRESSION', + 'PXR24_COMPRESSION', + 'B44_COMPRESSION', + 'B44A_COMPRESSION', + 'DWAA_COMPRESSION', + 'DWAB_COMPRESSION' + ]; + + const compression = parseUint8( dataView, offset ); + + return compressionCodes[ compression ]; + + } + + function parseBox2i( dataView, offset ) { + + const xMin = parseInt32( dataView, offset ); + const yMin = parseInt32( dataView, offset ); + const xMax = parseInt32( dataView, offset ); + const yMax = parseInt32( dataView, offset ); + + return { xMin: xMin, yMin: yMin, xMax: xMax, yMax: yMax }; + + } + + function parseLineOrder( dataView, offset ) { + + const lineOrders = [ + 'INCREASING_Y', + 'DECREASING_Y', + 'RANDOM_Y', + ]; + + const lineOrder = parseUint8( dataView, offset ); + + return lineOrders[ lineOrder ]; + + } + + function parseEnvmap( dataView, offset ) { + + const envmaps = [ + 'ENVMAP_LATLONG', + 'ENVMAP_CUBE' + ]; + + const envmap = parseUint8( dataView, offset ); + + return envmaps[ envmap ]; + + } + + function parseTiledesc( dataView, offset ) { + + const levelModes = [ + 'ONE_LEVEL', + 'MIPMAP_LEVELS', + 'RIPMAP_LEVELS', + ]; + + const roundingModes = [ + 'ROUND_DOWN', + 'ROUND_UP', + ]; + + const xSize = parseUint32( dataView, offset ); + const ySize = parseUint32( dataView, offset ); + const modes = parseUint8( dataView, offset ); + + return { + xSize: xSize, + ySize: ySize, + levelMode: levelModes[ modes & 0xf ], + roundingMode: roundingModes[ modes >> 4 ] + }; + + } + + function parseV2f( dataView, offset ) { + + const x = parseFloat32( dataView, offset ); + const y = parseFloat32( dataView, offset ); + + return [ x, y ]; + + } + + function parseV3f( dataView, offset ) { + + const x = parseFloat32( dataView, offset ); + const y = parseFloat32( dataView, offset ); + const z = parseFloat32( dataView, offset ); + + return [ x, y, z ]; + + } + + function parseValue( dataView, buffer, offset, type, size ) { + + if ( type === 'string' || type === 'stringvector' || type === 'iccProfile' ) { + + return parseFixedLengthString( buffer, offset, size ); + + } else if ( type === 'chlist' ) { + + return parseChlist( dataView, buffer, offset, size ); + + } else if ( type === 'chromaticities' ) { + + return parseChromaticities( dataView, offset ); + + } else if ( type === 'compression' ) { + + return parseCompression( dataView, offset ); + + } else if ( type === 'box2i' ) { + + return parseBox2i( dataView, offset ); + + } else if ( type === 'envmap' ) { + + return parseEnvmap( dataView, offset ); + + } else if ( type === 'tiledesc' ) { + + return parseTiledesc( dataView, offset ); + + } else if ( type === 'lineOrder' ) { + + return parseLineOrder( dataView, offset ); + + } else if ( type === 'float' ) { + + return parseFloat32( dataView, offset ); + + } else if ( type === 'v2f' ) { + + return parseV2f( dataView, offset ); + + } else if ( type === 'v3f' ) { + + return parseV3f( dataView, offset ); + + } else if ( type === 'int' ) { + + return parseInt32( dataView, offset ); + + } else if ( type === 'rational' ) { + + return parseRational( dataView, offset ); + + } else if ( type === 'timecode' ) { + + return parseTimecode( dataView, offset ); + + } else if ( type === 'preview' ) { + + offset.value += size; + return 'skipped'; + + } else { + + offset.value += size; + return undefined; + + } + + } + + function roundLog2( x, mode ) { + + const log2 = Math.log2( x ); + return mode == 'ROUND_DOWN' ? Math.floor( log2 ) : Math.ceil( log2 ); + + } + + function calculateTileLevels( tiledesc, w, h ) { + + let num = 0; + + switch ( tiledesc.levelMode ) { + + case 'ONE_LEVEL': + num = 1; + break; + + case 'MIPMAP_LEVELS': + num = roundLog2( Math.max( w, h ), tiledesc.roundingMode ) + 1; + break; + + case 'RIPMAP_LEVELS': + throw new Error( 'THREE.EXRLoader: RIPMAP_LEVELS tiles currently unsupported.' ); + + } + + return num; + + } + + function calculateTiles( count, dataSize, size, roundingMode ) { + + const tiles = new Array( count ); + + for ( let i = 0; i < count; i ++ ) { + + const b = ( 1 << i ); + let s = ( dataSize / b ) | 0; + + if ( roundingMode == 'ROUND_UP' && s * b < dataSize ) s += 1; + + const l = Math.max( s, 1 ); + + tiles[ i ] = ( ( l + size - 1 ) / size ) | 0; + + } + + return tiles; + + } + + function parseTiles() { + + const EXRDecoder = this; + const offset = EXRDecoder.offset; + const tmpOffset = { value: 0 }; + + for ( let tile = 0; tile < EXRDecoder.tileCount; tile ++ ) { + + const tileX = parseInt32( EXRDecoder.viewer, offset ); + const tileY = parseInt32( EXRDecoder.viewer, offset ); + offset.value += 8; // skip levels - only parsing top-level + EXRDecoder.size = parseUint32( EXRDecoder.viewer, offset ); + + const startX = tileX * EXRDecoder.blockWidth; + const startY = tileY * EXRDecoder.blockHeight; + EXRDecoder.columns = ( startX + EXRDecoder.blockWidth > EXRDecoder.width ) ? EXRDecoder.width - startX : EXRDecoder.blockWidth; + EXRDecoder.lines = ( startY + EXRDecoder.blockHeight > EXRDecoder.height ) ? EXRDecoder.height - startY : EXRDecoder.blockHeight; + + const bytesBlockLine = EXRDecoder.columns * EXRDecoder.totalBytes; + const isCompressed = EXRDecoder.size < EXRDecoder.lines * bytesBlockLine; + const viewer = isCompressed ? EXRDecoder.uncompress( EXRDecoder ) : uncompressRAW( EXRDecoder ); + + offset.value += EXRDecoder.size; + + for ( let line = 0; line < EXRDecoder.lines; line ++ ) { + + const lineOffset = line * EXRDecoder.columns * EXRDecoder.totalBytes; + + for ( let channelID = 0; channelID < EXRDecoder.inputChannels.length; channelID ++ ) { + + const name = EXRHeader.channels[ channelID ].name; + const lOff = EXRDecoder.channelByteOffsets[ name ] * EXRDecoder.columns; + const cOff = EXRDecoder.decodeChannels[ name ]; + + if ( cOff === undefined ) continue; + + tmpOffset.value = lineOffset + lOff; + const outLineOffset = ( EXRDecoder.height - ( 1 + startY + line ) ) * EXRDecoder.outLineWidth; + + for ( let x = 0; x < EXRDecoder.columns; x ++ ) { + + const outIndex = outLineOffset + ( x + startX ) * EXRDecoder.outputChannels + cOff; + EXRDecoder.byteArray[ outIndex ] = EXRDecoder.getter( viewer, tmpOffset ); + + } + + } + + } + + } + + } + + function parseScanline() { + + const EXRDecoder = this; + const offset = EXRDecoder.offset; + const tmpOffset = { value: 0 }; + + for ( let scanlineBlockIdx = 0; scanlineBlockIdx < EXRDecoder.height / EXRDecoder.blockHeight; scanlineBlockIdx ++ ) { + + const line = parseInt32( EXRDecoder.viewer, offset ) - EXRHeader.dataWindow.yMin; // line_no + EXRDecoder.size = parseUint32( EXRDecoder.viewer, offset ); // data_len + EXRDecoder.lines = ( ( line + EXRDecoder.blockHeight > EXRDecoder.height ) ? ( EXRDecoder.height - line ) : EXRDecoder.blockHeight ); + + const bytesPerLine = EXRDecoder.columns * EXRDecoder.totalBytes; + const isCompressed = EXRDecoder.size < EXRDecoder.lines * bytesPerLine; + const viewer = isCompressed ? EXRDecoder.uncompress( EXRDecoder ) : uncompressRAW( EXRDecoder ); + + offset.value += EXRDecoder.size; + + for ( let line_y = 0; line_y < EXRDecoder.blockHeight; line_y ++ ) { + + const scan_y = scanlineBlockIdx * EXRDecoder.blockHeight; + const true_y = line_y + EXRDecoder.scanOrder( scan_y ); + if ( true_y >= EXRDecoder.height ) continue; + + const lineOffset = line_y * bytesPerLine; + const outLineOffset = ( EXRDecoder.height - 1 - true_y ) * EXRDecoder.outLineWidth; + + for ( let channelID = 0; channelID < EXRDecoder.inputChannels.length; channelID ++ ) { + + const name = EXRHeader.channels[ channelID ].name; + const lOff = EXRDecoder.channelByteOffsets[ name ] * EXRDecoder.columns; + const cOff = EXRDecoder.decodeChannels[ name ]; + + if ( cOff === undefined ) continue; + + tmpOffset.value = lineOffset + lOff; + + for ( let x = 0; x < EXRDecoder.columns; x ++ ) { + + const outIndex = outLineOffset + x * EXRDecoder.outputChannels + cOff; + EXRDecoder.byteArray[ outIndex ] = EXRDecoder.getter( viewer, tmpOffset ); + + } + + } + + } + + } + + } + + function parseHeader( dataView, buffer, offset ) { + + const EXRHeader = {}; + + if ( dataView.getUint32( 0, true ) != 20000630 ) { // magic + + throw new Error( 'THREE.EXRLoader: Provided file doesn\'t appear to be in OpenEXR format.' ); + + } + + EXRHeader.version = dataView.getUint8( 4 ); + + const spec = dataView.getUint8( 5 ); // fullMask + + EXRHeader.spec = { + singleTile: !! ( spec & 2 ), + longName: !! ( spec & 4 ), + deepFormat: !! ( spec & 8 ), + multiPart: !! ( spec & 16 ), + }; + + // start of header + + offset.value = 8; // start at 8 - after pre-amble + + let keepReading = true; + + while ( keepReading ) { + + const attributeName = parseNullTerminatedString( buffer, offset ); + + if ( attributeName == 0 ) { + + keepReading = false; + + } else { + + const attributeType = parseNullTerminatedString( buffer, offset ); + const attributeSize = parseUint32( dataView, offset ); + const attributeValue = parseValue( dataView, buffer, offset, attributeType, attributeSize ); + + if ( attributeValue === undefined ) { + + console.warn( `THREE.EXRLoader: Skipped unknown header attribute type \'${attributeType}\'.` ); + + } else { + + EXRHeader[ attributeName ] = attributeValue; + + } + + } + + } + + if ( ( spec & ~ 0x06 ) != 0 ) { // unsupported deep-image, multi-part + + console.error( 'THREE.EXRHeader:', EXRHeader ); + throw new Error( 'THREE.EXRLoader: Provided file is currently unsupported.' ); + + } + + return EXRHeader; + + } + + function setupDecoder( EXRHeader, dataView, uInt8Array, offset, outputType ) { + + const EXRDecoder = { + size: 0, + viewer: dataView, + array: uInt8Array, + offset: offset, + width: EXRHeader.dataWindow.xMax - EXRHeader.dataWindow.xMin + 1, + height: EXRHeader.dataWindow.yMax - EXRHeader.dataWindow.yMin + 1, + inputChannels: EXRHeader.channels, + channelByteOffsets: {}, + scanOrder: null, + totalBytes: null, + columns: null, + lines: null, + type: null, + uncompress: null, + getter: null, + format: null, + colorSpace: LinearSRGBColorSpace, + }; + + switch ( EXRHeader.compression ) { + + case 'NO_COMPRESSION': + EXRDecoder.blockHeight = 1; + EXRDecoder.uncompress = uncompressRAW; + break; + + case 'RLE_COMPRESSION': + EXRDecoder.blockHeight = 1; + EXRDecoder.uncompress = uncompressRLE; + break; + + case 'ZIPS_COMPRESSION': + EXRDecoder.blockHeight = 1; + EXRDecoder.uncompress = uncompressZIP; + break; + + case 'ZIP_COMPRESSION': + EXRDecoder.blockHeight = 16; + EXRDecoder.uncompress = uncompressZIP; + break; + + case 'PIZ_COMPRESSION': + EXRDecoder.blockHeight = 32; + EXRDecoder.uncompress = uncompressPIZ; + break; + + case 'PXR24_COMPRESSION': + EXRDecoder.blockHeight = 16; + EXRDecoder.uncompress = uncompressPXR; + break; + + case 'DWAA_COMPRESSION': + EXRDecoder.blockHeight = 32; + EXRDecoder.uncompress = uncompressDWA; + break; + + case 'DWAB_COMPRESSION': + EXRDecoder.blockHeight = 256; + EXRDecoder.uncompress = uncompressDWA; + break; + + default: + throw new Error( 'EXRLoader.parse: ' + EXRHeader.compression + ' is unsupported' ); + + } + + const channels = {}; + for ( const channel of EXRHeader.channels ) { + + switch ( channel.name ) { + + case 'Y': + case 'R': + case 'G': + case 'B': + case 'A': + channels[ channel.name ] = true; + EXRDecoder.type = channel.pixelType; + + } + + } + + // RGB images will be converted to RGBA format, preventing software emulation in select devices. + let fillAlpha = false; + + if ( channels.R && channels.G && channels.B ) { + + fillAlpha = ! channels.A; + EXRDecoder.outputChannels = 4; + EXRDecoder.decodeChannels = { R: 0, G: 1, B: 2, A: 3 }; + + } else if ( channels.Y ) { + + EXRDecoder.outputChannels = 1; + EXRDecoder.decodeChannels = { Y: 0 }; + + } else { + + throw new Error( 'EXRLoader.parse: file contains unsupported data channels.' ); + + } + + if ( EXRDecoder.type == 1 ) { + + // half + switch ( outputType ) { + + case FloatType: + EXRDecoder.getter = parseFloat16; + break; + + case HalfFloatType: + EXRDecoder.getter = parseUint16; + break; + + } + + } else if ( EXRDecoder.type == 2 ) { + + // float + switch ( outputType ) { + + case FloatType: + EXRDecoder.getter = parseFloat32; + break; + + case HalfFloatType: + EXRDecoder.getter = decodeFloat32; + + } + + } else { + + throw new Error( 'EXRLoader.parse: unsupported pixelType ' + EXRDecoder.type + ' for ' + EXRHeader.compression + '.' ); + + } + + EXRDecoder.columns = EXRDecoder.width; + const size = EXRDecoder.width * EXRDecoder.height * EXRDecoder.outputChannels; + + switch ( outputType ) { + + case FloatType: + EXRDecoder.byteArray = new Float32Array( size ); + + // Fill initially with 1s for the alpha value if the texture is not RGBA, RGB values will be overwritten + if ( fillAlpha ) + EXRDecoder.byteArray.fill( 1, 0, size ); + + break; + + case HalfFloatType: + EXRDecoder.byteArray = new Uint16Array( size ); + + if ( fillAlpha ) + EXRDecoder.byteArray.fill( 0x3C00, 0, size ); // Uint16Array holds half float data, 0x3C00 is 1 + + break; + + default: + console.error( 'THREE.EXRLoader: unsupported type: ', outputType ); + break; + + } + + let byteOffset = 0; + for ( const channel of EXRHeader.channels ) { + + if ( EXRDecoder.decodeChannels[ channel.name ] !== undefined ) { + + EXRDecoder.channelByteOffsets[ channel.name ] = byteOffset; + + } + + byteOffset += channel.pixelType * 2; + + } + + EXRDecoder.totalBytes = byteOffset; + EXRDecoder.outLineWidth = EXRDecoder.width * EXRDecoder.outputChannels; + + if ( EXRHeader.lineOrder === 'INCREASING_Y' ) { + + EXRDecoder.scanOrder = ( y ) => y; + + } else { + + EXRDecoder.scanOrder = ( y ) => EXRDecoder.height - 1 - y; + + } + + if ( EXRDecoder.outputChannels == 4 ) { + + EXRDecoder.format = RGBAFormat; + EXRDecoder.colorSpace = LinearSRGBColorSpace; + + } else { + + EXRDecoder.format = RedFormat; + EXRDecoder.colorSpace = NoColorSpace; + + } + + if ( EXRHeader.spec.singleTile ) { + + EXRDecoder.blockHeight = EXRHeader.tiles.ySize; + EXRDecoder.blockWidth = EXRHeader.tiles.xSize; + + const numXLevels = calculateTileLevels( EXRHeader.tiles, EXRDecoder.width, EXRDecoder.height ); + // const numYLevels = calculateTileLevels( EXRHeader.tiles, EXRDecoder.width, EXRDecoder.height ); + + const numXTiles = calculateTiles( numXLevels, EXRDecoder.width, EXRHeader.tiles.xSize, EXRHeader.tiles.roundingMode ); + const numYTiles = calculateTiles( numXLevels, EXRDecoder.height, EXRHeader.tiles.ySize, EXRHeader.tiles.roundingMode ); + + EXRDecoder.tileCount = numXTiles[ 0 ] * numYTiles[ 0 ]; + + for ( let l = 0; l < numXLevels; l ++ ) + for ( let y = 0; y < numYTiles[ l ]; y ++ ) + for ( let x = 0; x < numXTiles[ l ]; x ++ ) + parseInt64( dataView, offset ); // tileOffset + + EXRDecoder.decode = parseTiles.bind( EXRDecoder ); + + } else { + + EXRDecoder.blockWidth = EXRDecoder.width; + const blockCount = Math.ceil( EXRDecoder.height / EXRDecoder.blockHeight ); + + for ( let i = 0; i < blockCount; i ++ ) + parseInt64( dataView, offset ); // scanlineOffset + + EXRDecoder.decode = parseScanline.bind( EXRDecoder ); + + } + + return EXRDecoder; + + } + + // start parsing file [START] + const offset = { value: 0 }; + const bufferDataView = new DataView( buffer ); + const uInt8Array = new Uint8Array( buffer ); + + // get header information and validate format. + const EXRHeader = parseHeader( bufferDataView, buffer, offset ); + + // get input compression information and prepare decoding. + const EXRDecoder = setupDecoder( EXRHeader, bufferDataView, uInt8Array, offset, this.type ); + + // parse input data + EXRDecoder.decode(); + + return { + header: EXRHeader, + width: EXRDecoder.width, + height: EXRDecoder.height, + data: EXRDecoder.byteArray, + format: EXRDecoder.format, + colorSpace: EXRDecoder.colorSpace, + type: this.type, + }; + + } + + setDataType( value ) { + + this.type = value; + return this; + + } + + load( url, onLoad, onProgress, onError ) { + + function onLoadCallback( texture, texData ) { + + texture.colorSpace = texData.colorSpace; + texture.minFilter = LinearFilter; + texture.magFilter = LinearFilter; + texture.generateMipmaps = false; + texture.flipY = false; + + if ( onLoad ) onLoad( texture, texData ); + + } + + return super.load( url, onLoadCallback, onProgress, onError ); + + } + +} + +export { EXRLoader }; diff --git a/js/lib/jsm/loaders/KTX2Loader.js b/js/lib/jsm/loaders/KTX2Loader.js new file mode 100644 index 0000000..d0f4a2f --- /dev/null +++ b/js/lib/jsm/loaders/KTX2Loader.js @@ -0,0 +1,1034 @@ +/** + * Loader for KTX 2.0 GPU Texture containers. + * + * KTX 2.0 is a container format for various GPU texture formats. The loader + * supports Basis Universal GPU textures, which can be quickly transcoded to + * a wide variety of GPU texture compression formats, as well as some + * uncompressed DataTexture and Data3DTexture formats. + * + * References: + * - KTX: http://github.khronos.org/KTX-Specification/ + * - DFD: https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.html#basicdescriptor + * - BasisU HDR: https://github.com/BinomialLLC/basis_universal/wiki/UASTC-HDR-Texture-Specification-v1.0 + */ + +import { + CompressedTexture, + CompressedArrayTexture, + CompressedCubeTexture, + Data3DTexture, + DataTexture, + FileLoader, + FloatType, + HalfFloatType, + NoColorSpace, + LinearFilter, + LinearMipmapLinearFilter, + LinearSRGBColorSpace, + Loader, + RedFormat, + RGB_BPTC_UNSIGNED_Format, + RGB_ETC1_Format, + RGB_ETC2_Format, + RGB_PVRTC_4BPPV1_Format, + RGBA_ASTC_4x4_Format, + RGBA_ASTC_6x6_Format, + RGBA_BPTC_Format, + RGBA_ETC2_EAC_Format, + RGBA_PVRTC_4BPPV1_Format, + RGBA_S3TC_DXT5_Format, + RGBA_S3TC_DXT1_Format, + RGBAFormat, + RGFormat, + SRGBColorSpace, + UnsignedByteType, +} from '../../three.module.js'; +import { WorkerPool } from '../utils/WorkerPool.js'; +import { + read, + KHR_DF_FLAG_ALPHA_PREMULTIPLIED, + KHR_DF_TRANSFER_SRGB, + KHR_SUPERCOMPRESSION_NONE, + KHR_SUPERCOMPRESSION_ZSTD, + VK_FORMAT_UNDEFINED, + VK_FORMAT_R16_SFLOAT, + VK_FORMAT_R16G16_SFLOAT, + VK_FORMAT_R16G16B16A16_SFLOAT, + VK_FORMAT_R32_SFLOAT, + VK_FORMAT_R32G32_SFLOAT, + VK_FORMAT_R32G32B32A32_SFLOAT, + VK_FORMAT_R8_SRGB, + VK_FORMAT_R8_UNORM, + VK_FORMAT_R8G8_SRGB, + VK_FORMAT_R8G8_UNORM, + VK_FORMAT_R8G8B8A8_SRGB, + VK_FORMAT_R8G8B8A8_UNORM, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT, + VK_FORMAT_ASTC_6x6_SRGB_BLOCK, + VK_FORMAT_ASTC_6x6_UNORM_BLOCK, + KHR_DF_PRIMARIES_UNSPECIFIED, + KHR_DF_PRIMARIES_BT709, + KHR_DF_PRIMARIES_DISPLAYP3 +} from '../libs/ktx-parse.module.js'; +import { ZSTDDecoder } from '../libs/zstddec.module.js'; +import { DisplayP3ColorSpace, LinearDisplayP3ColorSpace } from '../math/ColorSpaces.js'; + +const _taskCache = new WeakMap(); + +let _activeLoaders = 0; + +let _zstd; + +class KTX2Loader extends Loader { + + constructor( manager ) { + + super( manager ); + + this.transcoderPath = ''; + this.transcoderBinary = null; + this.transcoderPending = null; + + this.workerPool = new WorkerPool(); + this.workerSourceURL = ''; + this.workerConfig = null; + + if ( typeof MSC_TRANSCODER !== 'undefined' ) { + + console.warn( + + 'THREE.KTX2Loader: Please update to latest "basis_transcoder".' + + ' "msc_basis_transcoder" is no longer supported in three.js r125+.' + + ); + + } + + } + + setTranscoderPath( path ) { + + this.transcoderPath = path; + + return this; + + } + + setWorkerLimit( num ) { + + this.workerPool.setWorkerLimit( num ); + + return this; + + } + + async detectSupportAsync( renderer ) { + + this.workerConfig = { + astcSupported: await renderer.hasFeatureAsync( 'texture-compression-astc' ), + astcHDRSupported: false, // https://github.com/gpuweb/gpuweb/issues/3856 + etc1Supported: await renderer.hasFeatureAsync( 'texture-compression-etc1' ), + etc2Supported: await renderer.hasFeatureAsync( 'texture-compression-etc2' ), + dxtSupported: await renderer.hasFeatureAsync( 'texture-compression-bc' ), + bptcSupported: await renderer.hasFeatureAsync( 'texture-compression-bptc' ), + pvrtcSupported: await renderer.hasFeatureAsync( 'texture-compression-pvrtc' ) + }; + + return this; + + } + + detectSupport( renderer ) { + + if ( renderer.isWebGPURenderer === true ) { + + this.workerConfig = { + astcSupported: renderer.hasFeature( 'texture-compression-astc' ), + astcHDRSupported: false, // https://github.com/gpuweb/gpuweb/issues/3856 + etc1Supported: renderer.hasFeature( 'texture-compression-etc1' ), + etc2Supported: renderer.hasFeature( 'texture-compression-etc2' ), + dxtSupported: renderer.hasFeature( 'texture-compression-bc' ), + bptcSupported: renderer.hasFeature( 'texture-compression-bptc' ), + pvrtcSupported: renderer.hasFeature( 'texture-compression-pvrtc' ) + }; + + } else { + + this.workerConfig = { + astcSupported: renderer.extensions.has( 'WEBGL_compressed_texture_astc' ), + astcHDRSupported: renderer.extensions.has( 'WEBGL_compressed_texture_astc' ) + && renderer.extensions.get( 'WEBGL_compressed_texture_astc' ).getSupportedProfiles().includes( 'hdr' ), + etc1Supported: renderer.extensions.has( 'WEBGL_compressed_texture_etc1' ), + etc2Supported: renderer.extensions.has( 'WEBGL_compressed_texture_etc' ), + dxtSupported: renderer.extensions.has( 'WEBGL_compressed_texture_s3tc' ), + bptcSupported: renderer.extensions.has( 'EXT_texture_compression_bptc' ), + pvrtcSupported: renderer.extensions.has( 'WEBGL_compressed_texture_pvrtc' ) + || renderer.extensions.has( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ) + }; + + } + + return this; + + } + + init() { + + if ( ! this.transcoderPending ) { + + // Load transcoder wrapper. + const jsLoader = new FileLoader( this.manager ); + jsLoader.setPath( this.transcoderPath ); + jsLoader.setWithCredentials( this.withCredentials ); + const jsContent = jsLoader.loadAsync( 'basis_transcoder.js' ); + + // Load transcoder WASM binary. + const binaryLoader = new FileLoader( this.manager ); + binaryLoader.setPath( this.transcoderPath ); + binaryLoader.setResponseType( 'arraybuffer' ); + binaryLoader.setWithCredentials( this.withCredentials ); + const binaryContent = binaryLoader.loadAsync( 'basis_transcoder.wasm' ); + + this.transcoderPending = Promise.all( [ jsContent, binaryContent ] ) + .then( ( [ jsContent, binaryContent ] ) => { + + const fn = KTX2Loader.BasisWorker.toString(); + + const body = [ + '/* constants */', + 'let _EngineFormat = ' + JSON.stringify( KTX2Loader.EngineFormat ), + 'let _EngineType = ' + JSON.stringify( KTX2Loader.EngineType ), + 'let _TranscoderFormat = ' + JSON.stringify( KTX2Loader.TranscoderFormat ), + 'let _BasisFormat = ' + JSON.stringify( KTX2Loader.BasisFormat ), + '/* basis_transcoder.js */', + jsContent, + '/* worker */', + fn.substring( fn.indexOf( '{' ) + 1, fn.lastIndexOf( '}' ) ) + ].join( '\n' ); + + this.workerSourceURL = URL.createObjectURL( new Blob( [ body ] ) ); + this.transcoderBinary = binaryContent; + + this.workerPool.setWorkerCreator( () => { + + const worker = new Worker( this.workerSourceURL ); + const transcoderBinary = this.transcoderBinary.slice( 0 ); + + worker.postMessage( { type: 'init', config: this.workerConfig, transcoderBinary }, [ transcoderBinary ] ); + + return worker; + + } ); + + } ); + + if ( _activeLoaders > 0 ) { + + // Each instance loads a transcoder and allocates workers, increasing network and memory cost. + + console.warn( + + 'THREE.KTX2Loader: Multiple active KTX2 loaders may cause performance issues.' + + ' Use a single KTX2Loader instance, or call .dispose() on old instances.' + + ); + + } + + _activeLoaders ++; + + } + + return this.transcoderPending; + + } + + load( url, onLoad, onProgress, onError ) { + + if ( this.workerConfig === null ) { + + throw new Error( 'THREE.KTX2Loader: Missing initialization with `.detectSupport( renderer )`.' ); + + } + + const loader = new FileLoader( this.manager ); + + loader.setResponseType( 'arraybuffer' ); + loader.setWithCredentials( this.withCredentials ); + + loader.load( url, ( buffer ) => { + + this.parse( buffer, onLoad, onError ); + + }, onProgress, onError ); + + } + + parse( buffer, onLoad, onError ) { + + if ( this.workerConfig === null ) { + + throw new Error( 'THREE.KTX2Loader: Missing initialization with `.detectSupport( renderer )`.' ); + + } + + // Check for an existing task using this buffer. A transferred buffer cannot be transferred + // again from this thread. + if ( _taskCache.has( buffer ) ) { + + const cachedTask = _taskCache.get( buffer ); + + return cachedTask.promise.then( onLoad ).catch( onError ); + + } + + this._createTexture( buffer ) + .then( ( texture ) => onLoad ? onLoad( texture ) : null ) + .catch( onError ); + + } + + _createTextureFrom( transcodeResult, container ) { + + const { type: messageType, error, data: { faces, width, height, format, type, dfdFlags } } = transcodeResult; + + if ( messageType === 'error' ) return Promise.reject( error ); + + let texture; + + if ( container.faceCount === 6 ) { + + texture = new CompressedCubeTexture( faces, format, type ); + + } else { + + const mipmaps = faces[ 0 ].mipmaps; + + texture = container.layerCount > 1 + ? new CompressedArrayTexture( mipmaps, width, height, container.layerCount, format, type ) + : new CompressedTexture( mipmaps, width, height, format, type ); + + } + + texture.minFilter = faces[ 0 ].mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter; + texture.magFilter = LinearFilter; + texture.generateMipmaps = false; + + texture.needsUpdate = true; + texture.colorSpace = parseColorSpace( container ); + texture.premultiplyAlpha = !! ( dfdFlags & KHR_DF_FLAG_ALPHA_PREMULTIPLIED ); + + return texture; + + } + + /** + * @param {ArrayBuffer} buffer + * @param {object?} config + * @return {Promise} + */ + async _createTexture( buffer, config = {} ) { + + const container = read( new Uint8Array( buffer ) ); + + // Basis UASTC HDR is a subset of ASTC, which can be transcoded efficiently + // to BC6H. To detect whether a KTX2 file uses Basis UASTC HDR, or default + // ASTC, inspect the DFD color model. + // + // Source: https://github.com/BinomialLLC/basis_universal/issues/381 + const isBasisHDR = container.vkFormat === VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT + && container.dataFormatDescriptor[ 0 ].colorModel === 0xA7; + + // If the device supports ASTC, Basis UASTC HDR requires no transcoder. + const needsTranscoder = container.vkFormat === VK_FORMAT_UNDEFINED + || isBasisHDR && ! this.workerConfig.astcHDRSupported; + + if ( ! needsTranscoder ) { + + return createRawTexture( container ); + + } + + // + const taskConfig = config; + const texturePending = this.init().then( () => { + + return this.workerPool.postMessage( { type: 'transcode', buffer, taskConfig: taskConfig }, [ buffer ] ); + + } ).then( ( e ) => this._createTextureFrom( e.data, container ) ); + + // Cache the task result. + _taskCache.set( buffer, { promise: texturePending } ); + + return texturePending; + + } + + dispose() { + + this.workerPool.dispose(); + if ( this.workerSourceURL ) URL.revokeObjectURL( this.workerSourceURL ); + + _activeLoaders --; + + return this; + + } + +} + + +/* CONSTANTS */ + +KTX2Loader.BasisFormat = { + ETC1S: 0, + UASTC: 1, + UASTC_HDR: 2, +}; + +// Source: https://github.com/BinomialLLC/basis_universal/blob/master/webgl/texture_test/index.html +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, + BC6H: 22, + RGB_HALF: 24, + RGBA_HALF: 25, +}; + +KTX2Loader.EngineFormat = { + RGBAFormat: RGBAFormat, + RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format, + RGB_BPTC_UNSIGNED_Format: RGB_BPTC_UNSIGNED_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, + RGBA_S3TC_DXT1_Format: RGBA_S3TC_DXT1_Format, +}; + +KTX2Loader.EngineType = { + UnsignedByteType: UnsignedByteType, + HalfFloatType: HalfFloatType, + FloatType: FloatType, +}; + +/* WEB WORKER */ + +KTX2Loader.BasisWorker = function () { + + let config; + let transcoderPending; + let BasisModule; + + const EngineFormat = _EngineFormat; // eslint-disable-line no-undef + const EngineType = _EngineType; // eslint-disable-line no-undef + const TranscoderFormat = _TranscoderFormat; // eslint-disable-line no-undef + const BasisFormat = _BasisFormat; // eslint-disable-line no-undef + + 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 { faces, buffers, width, height, hasAlpha, format, type, dfdFlags } = transcode( message.buffer ); + + self.postMessage( { type: 'transcode', id: message.id, data: { faces, width, height, hasAlpha, format, type, 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 ); // eslint-disable-line no-undef + + } ).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' ); + + } + + let basisFormat; + + if ( ktx2File.isUASTC() ) { + + basisFormat = BasisFormat.UASTC; + + } else if ( ktx2File.isETC1S() ) { + + basisFormat = BasisFormat.ETC1S; + + } else if ( ktx2File.isHDR() ) { + + basisFormat = BasisFormat.UASTC_HDR; + + } else { + + throw new Error( 'THREE.KTX2Loader: Unknown Basis encoding' ); + + } + + const width = ktx2File.getWidth(); + const height = ktx2File.getHeight(); + const layerCount = ktx2File.getLayers() || 1; + const levelCount = ktx2File.getLevels(); + const faceCount = ktx2File.getFaces(); + const hasAlpha = ktx2File.getHasAlpha(); + const dfdFlags = ktx2File.getDFDFlags(); + + const { transcoderFormat, engineFormat, engineType } = getTranscoderFormat( basisFormat, width, height, hasAlpha ); + + if ( ! width || ! height || ! levelCount ) { + + cleanup(); + throw new Error( 'THREE.KTX2Loader: Invalid texture' ); + + } + + if ( ! ktx2File.startTranscoding() ) { + + cleanup(); + throw new Error( 'THREE.KTX2Loader: .startTranscoding failed' ); + + } + + const faces = []; + const buffers = []; + + for ( let face = 0; face < faceCount; face ++ ) { + + const mipmaps = []; + + for ( let mip = 0; mip < levelCount; mip ++ ) { + + const layerMips = []; + + let mipWidth, mipHeight; + + for ( let layer = 0; layer < layerCount; layer ++ ) { + + const levelInfo = ktx2File.getImageLevelInfo( mip, layer, face ); + + if ( face === 0 && mip === 0 && layer === 0 && ( levelInfo.origWidth % 4 !== 0 || levelInfo.origHeight % 4 !== 0 ) ) { + + console.warn( 'THREE.KTX2Loader: ETC1S and UASTC textures should use multiple-of-four dimensions.' ); + + } + + if ( levelCount > 1 ) { + + mipWidth = levelInfo.origWidth; + mipHeight = levelInfo.origHeight; + + } else { + + // Handles non-multiple-of-four dimensions in textures without mipmaps. Textures with + // mipmaps must use multiple-of-four dimensions, for some texture formats and APIs. + // See mrdoob/three.js#25908. + mipWidth = levelInfo.width; + mipHeight = levelInfo.height; + + } + + let dst = new Uint8Array( ktx2File.getImageTranscodedSizeInBytes( mip, layer, 0, transcoderFormat ) ); + const status = ktx2File.transcodeImage( dst, mip, layer, face, transcoderFormat, 0, - 1, - 1 ); + + if ( engineType === EngineType.HalfFloatType ) { + + dst = new Uint16Array( dst.buffer, dst.byteOffset, dst.byteLength / Uint16Array.BYTES_PER_ELEMENT ); + + } + + if ( ! status ) { + + cleanup(); + throw new Error( 'THREE.KTX2Loader: .transcodeImage failed.' ); + + } + + layerMips.push( dst ); + + } + + const mipData = concat( layerMips ); + + mipmaps.push( { data: mipData, width: mipWidth, height: mipHeight } ); + buffers.push( mipData.buffer ); + + } + + faces.push( { mipmaps, width, height, format: engineFormat, type: engineType } ); + + } + + cleanup(); + + return { faces, buffers, width, height, hasAlpha, dfdFlags, format: engineFormat, type: engineType }; + + } + + // + + // Optimal choice of a transcoder target format depends on the Basis format (ETC1S, UASTC, or + // UASTC HDR), device capabilities, and texture dimensions. The list below ranks the formats + // separately for each format. Currently, priority is assigned based on: + // + // high quality > low quality > uncompressed + // + // Prioritization may be revisited, or exposed for configuration, in the future. + // + // Reference: https://github.com/KhronosGroup/3D-Formats-Guidelines/blob/main/KTXDeveloperGuide.md + const FORMAT_OPTIONS = [ + { + if: 'astcSupported', + basisFormat: [ BasisFormat.UASTC ], + transcoderFormat: [ TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4 ], + engineFormat: [ EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format ], + engineType: [ EngineType.UnsignedByteType ], + priorityETC1S: Infinity, + priorityUASTC: 1, + needsPowerOfTwo: false, + }, + { + if: 'bptcSupported', + basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC ], + transcoderFormat: [ TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5 ], + engineFormat: [ EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format ], + engineType: [ EngineType.UnsignedByteType ], + priorityETC1S: 3, + priorityUASTC: 2, + needsPowerOfTwo: false, + }, + { + if: 'dxtSupported', + basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC ], + transcoderFormat: [ TranscoderFormat.BC1, TranscoderFormat.BC3 ], + engineFormat: [ EngineFormat.RGBA_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format ], + engineType: [ EngineType.UnsignedByteType ], + priorityETC1S: 4, + priorityUASTC: 5, + needsPowerOfTwo: false, + }, + { + if: 'etc2Supported', + basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC ], + transcoderFormat: [ TranscoderFormat.ETC1, TranscoderFormat.ETC2 ], + engineFormat: [ EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format ], + engineType: [ EngineType.UnsignedByteType ], + priorityETC1S: 1, + priorityUASTC: 3, + needsPowerOfTwo: false, + }, + { + if: 'etc1Supported', + basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC ], + transcoderFormat: [ TranscoderFormat.ETC1 ], + engineFormat: [ EngineFormat.RGB_ETC1_Format ], + engineType: [ EngineType.UnsignedByteType ], + priorityETC1S: 2, + priorityUASTC: 4, + needsPowerOfTwo: false, + }, + { + if: 'pvrtcSupported', + basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC ], + transcoderFormat: [ TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA ], + engineFormat: [ EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format ], + engineType: [ EngineType.UnsignedByteType ], + priorityETC1S: 5, + priorityUASTC: 6, + needsPowerOfTwo: true, + }, + { + if: 'bptcSupported', + basisFormat: [ BasisFormat.UASTC_HDR ], + transcoderFormat: [ TranscoderFormat.BC6H ], + engineFormat: [ EngineFormat.RGB_BPTC_UNSIGNED_Format ], + engineType: [ EngineType.HalfFloatType ], + priorityHDR: 1, + needsPowerOfTwo: false, + }, + + // Uncompressed fallbacks. + + { + basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC ], + transcoderFormat: [ TranscoderFormat.RGBA32, TranscoderFormat.RGBA32 ], + engineFormat: [ EngineFormat.RGBAFormat, EngineFormat.RGBAFormat ], + engineType: [ EngineType.UnsignedByteType, EngineType.UnsignedByteType ], + priorityETC1S: 100, + priorityUASTC: 100, + needsPowerOfTwo: false, + }, + { + basisFormat: [ BasisFormat.UASTC_HDR ], + transcoderFormat: [ TranscoderFormat.RGBA_HALF ], + engineFormat: [ EngineFormat.RGBAFormat ], + engineType: [ EngineType.HalfFloatType ], + priorityHDR: 100, + needsPowerOfTwo: false, + } + ]; + + const OPTIONS = { + // TODO: For ETC1S we intentionally sort by _UASTC_ priority, preserving + // a historical accident shown to avoid performance pitfalls for Linux with + // Firefox & AMD GPU (RadeonSI). Further work needed. + // See https://github.com/mrdoob/three.js/pull/29730. + [ BasisFormat.ETC1S ]: FORMAT_OPTIONS + .filter( ( opt ) => opt.basisFormat.includes( BasisFormat.ETC1S ) ) + .sort( ( a, b ) => a.priorityUASTC - b.priorityUASTC ), + + [ BasisFormat.UASTC ]: FORMAT_OPTIONS + .filter( ( opt ) => opt.basisFormat.includes( BasisFormat.UASTC ) ) + .sort( ( a, b ) => a.priorityUASTC - b.priorityUASTC ), + + [ BasisFormat.UASTC_HDR ]: FORMAT_OPTIONS + .filter( ( opt ) => opt.basisFormat.includes( BasisFormat.UASTC_HDR ) ) + .sort( ( a, b ) => a.priorityHDR - b.priorityHDR ), + }; + + function getTranscoderFormat( basisFormat, width, height, hasAlpha ) { + + const options = OPTIONS[ basisFormat ]; + + for ( let i = 0; i < options.length; i ++ ) { + + const opt = options[ i ]; + + if ( opt.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; + + const transcoderFormat = opt.transcoderFormat[ hasAlpha ? 1 : 0 ]; + const engineFormat = opt.engineFormat[ hasAlpha ? 1 : 0 ]; + const engineType = opt.engineType[ 0 ]; + + return { transcoderFormat, engineFormat, engineType }; + + } + + throw new Error( 'THREE.KTX2Loader: Failed to identify transcoding target.' ); + + } + + function isPowerOfTwo( value ) { + + if ( value <= 2 ) return true; + + return ( value & ( value - 1 ) ) === 0 && value !== 0; + + } + + /** Concatenates N byte arrays. */ + function concat( arrays ) { + + if ( arrays.length === 1 ) return arrays[ 0 ]; + + 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; + + } + +}; + +// Parsing for non-Basis textures. These textures may have supercompression +// like Zstd, but they do not require transcoding. + +const UNCOMPRESSED_FORMATS = new Set( [ RGBAFormat, RGFormat, RedFormat ] ); + +const FORMAT_MAP = { + + [ VK_FORMAT_R32G32B32A32_SFLOAT ]: RGBAFormat, + [ VK_FORMAT_R16G16B16A16_SFLOAT ]: RGBAFormat, + [ VK_FORMAT_R8G8B8A8_UNORM ]: RGBAFormat, + [ VK_FORMAT_R8G8B8A8_SRGB ]: RGBAFormat, + + [ VK_FORMAT_R32G32_SFLOAT ]: RGFormat, + [ VK_FORMAT_R16G16_SFLOAT ]: RGFormat, + [ VK_FORMAT_R8G8_UNORM ]: RGFormat, + [ VK_FORMAT_R8G8_SRGB ]: RGFormat, + + [ VK_FORMAT_R32_SFLOAT ]: RedFormat, + [ VK_FORMAT_R16_SFLOAT ]: RedFormat, + [ VK_FORMAT_R8_SRGB ]: RedFormat, + [ VK_FORMAT_R8_UNORM ]: RedFormat, + + [ VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT ]: RGBA_ASTC_4x4_Format, + [ VK_FORMAT_ASTC_6x6_SRGB_BLOCK ]: RGBA_ASTC_6x6_Format, + [ VK_FORMAT_ASTC_6x6_UNORM_BLOCK ]: RGBA_ASTC_6x6_Format, + +}; + +const TYPE_MAP = { + + [ VK_FORMAT_R32G32B32A32_SFLOAT ]: FloatType, + [ VK_FORMAT_R16G16B16A16_SFLOAT ]: HalfFloatType, + [ VK_FORMAT_R8G8B8A8_UNORM ]: UnsignedByteType, + [ VK_FORMAT_R8G8B8A8_SRGB ]: UnsignedByteType, + + [ VK_FORMAT_R32G32_SFLOAT ]: FloatType, + [ VK_FORMAT_R16G16_SFLOAT ]: HalfFloatType, + [ VK_FORMAT_R8G8_UNORM ]: UnsignedByteType, + [ VK_FORMAT_R8G8_SRGB ]: UnsignedByteType, + + [ VK_FORMAT_R32_SFLOAT ]: FloatType, + [ VK_FORMAT_R16_SFLOAT ]: HalfFloatType, + [ VK_FORMAT_R8_SRGB ]: UnsignedByteType, + [ VK_FORMAT_R8_UNORM ]: UnsignedByteType, + + [ VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT ]: HalfFloatType, + [ VK_FORMAT_ASTC_6x6_SRGB_BLOCK ]: UnsignedByteType, + [ VK_FORMAT_ASTC_6x6_UNORM_BLOCK ]: UnsignedByteType, + +}; + +async function createRawTexture( container ) { + + const { vkFormat } = container; + + if ( FORMAT_MAP[ vkFormat ] === undefined ) { + + throw new Error( 'THREE.KTX2Loader: Unsupported vkFormat.' ); + + } + + // + + let zstd; + + if ( container.supercompressionScheme === KHR_SUPERCOMPRESSION_ZSTD ) { + + if ( ! _zstd ) { + + _zstd = new Promise( async ( resolve ) => { + + const zstd = new ZSTDDecoder(); + await zstd.init(); + resolve( zstd ); + + } ); + + } + + zstd = await _zstd; + + } + + // + + const mipmaps = []; + + + for ( let levelIndex = 0; levelIndex < container.levels.length; levelIndex ++ ) { + + const levelWidth = Math.max( 1, container.pixelWidth >> levelIndex ); + const levelHeight = Math.max( 1, container.pixelHeight >> levelIndex ); + const levelDepth = container.pixelDepth ? Math.max( 1, container.pixelDepth >> levelIndex ) : 0; + + const level = container.levels[ levelIndex ]; + + let levelData; + + if ( container.supercompressionScheme === KHR_SUPERCOMPRESSION_NONE ) { + + levelData = level.levelData; + + } else if ( container.supercompressionScheme === KHR_SUPERCOMPRESSION_ZSTD ) { + + levelData = zstd.decode( level.levelData, level.uncompressedByteLength ); + + } else { + + throw new Error( 'THREE.KTX2Loader: Unsupported supercompressionScheme.' ); + + } + + let data; + + if ( TYPE_MAP[ vkFormat ] === FloatType ) { + + data = new Float32Array( + + levelData.buffer, + levelData.byteOffset, + levelData.byteLength / Float32Array.BYTES_PER_ELEMENT + + ); + + } else if ( TYPE_MAP[ vkFormat ] === HalfFloatType ) { + + data = new Uint16Array( + + levelData.buffer, + levelData.byteOffset, + levelData.byteLength / Uint16Array.BYTES_PER_ELEMENT + + ); + + } else { + + data = levelData; + + } + + mipmaps.push( { + + data: data, + width: levelWidth, + height: levelHeight, + depth: levelDepth, + + } ); + + } + + let texture; + + if ( UNCOMPRESSED_FORMATS.has( FORMAT_MAP[ vkFormat ] ) ) { + + texture = container.pixelDepth === 0 + ? new DataTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight ) + : new Data3DTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight, container.pixelDepth ); + + } else { + + if ( container.pixelDepth > 0 ) throw new Error( 'THREE.KTX2Loader: Unsupported pixelDepth.' ); + + texture = new CompressedTexture( mipmaps, container.pixelWidth, container.pixelHeight ); + + texture.minFilter = mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter; + texture.magFilter = LinearFilter; + + } + + texture.mipmaps = mipmaps; + + texture.type = TYPE_MAP[ vkFormat ]; + texture.format = FORMAT_MAP[ vkFormat ]; + texture.colorSpace = parseColorSpace( container ); + texture.needsUpdate = true; + + // + + return Promise.resolve( texture ); + +} + +function parseColorSpace( container ) { + + const dfd = container.dataFormatDescriptor[ 0 ]; + + if ( dfd.colorPrimaries === KHR_DF_PRIMARIES_BT709 ) { + + return dfd.transferFunction === KHR_DF_TRANSFER_SRGB ? SRGBColorSpace : LinearSRGBColorSpace; + + } else if ( dfd.colorPrimaries === KHR_DF_PRIMARIES_DISPLAYP3 ) { + + return dfd.transferFunction === KHR_DF_TRANSFER_SRGB ? DisplayP3ColorSpace : LinearDisplayP3ColorSpace; + + } else if ( dfd.colorPrimaries === KHR_DF_PRIMARIES_UNSPECIFIED ) { + + return NoColorSpace; + + } else { + + console.warn( `THREE.KTX2Loader: Unsupported color primaries, "${ dfd.colorPrimaries }"` ); + return NoColorSpace; + + } + +} + +export { KTX2Loader }; diff --git a/js/lib/jsm/loaders/OBJLoader.js b/js/lib/jsm/loaders/OBJLoader.js new file mode 100644 index 0000000..8a76029 --- /dev/null +++ b/js/lib/jsm/loaders/OBJLoader.js @@ -0,0 +1,907 @@ +import { + BufferGeometry, + FileLoader, + Float32BufferAttribute, + Group, + LineBasicMaterial, + LineSegments, + Loader, + Material, + Mesh, + MeshPhongMaterial, + Points, + PointsMaterial, + Vector3, + Color, + SRGBColorSpace +} from '../../three.module.js'; + +// o object_name | g group_name +const _object_pattern = /^[og]\s*(.+)?/; +// mtllib file_reference +const _material_library_pattern = /^mtllib /; +// usemtl material_name +const _material_use_pattern = /^usemtl /; +// usemap map_name +const _map_use_pattern = /^usemap /; +const _face_vertex_data_separator_pattern = /\s+/; + +const _vA = new Vector3(); +const _vB = new Vector3(); +const _vC = new Vector3(); + +const _ab = new Vector3(); +const _cb = new Vector3(); + +const _color = new Color(); + +function ParserState() { + + const state = { + objects: [], + object: {}, + + vertices: [], + normals: [], + colors: [], + uvs: [], + + materials: {}, + materialLibraries: [], + + startObject: function ( name, fromDeclaration ) { + + // If the current object (initial from reset) is not from a g/o declaration in the parsed + // file. We need to use it for the first parsed g/o to keep things in sync. + if ( this.object && this.object.fromDeclaration === false ) { + + this.object.name = name; + this.object.fromDeclaration = ( fromDeclaration !== false ); + return; + + } + + const previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined ); + + if ( this.object && typeof this.object._finalize === 'function' ) { + + this.object._finalize( true ); + + } + + this.object = { + name: name || '', + fromDeclaration: ( fromDeclaration !== false ), + + geometry: { + vertices: [], + normals: [], + colors: [], + uvs: [], + hasUVIndices: false + }, + materials: [], + smooth: true, + + startMaterial: function ( name, libraries ) { + + const previous = this._finalize( false ); + + // New usemtl declaration overwrites an inherited material, except if faces were declared + // after the material, then it must be preserved for proper MultiMaterial continuation. + if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) { + + this.materials.splice( previous.index, 1 ); + + } + + const material = { + index: this.materials.length, + name: name || '', + mtllib: ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ), + smooth: ( previous !== undefined ? previous.smooth : this.smooth ), + groupStart: ( previous !== undefined ? previous.groupEnd : 0 ), + groupEnd: - 1, + groupCount: - 1, + inherited: false, + + clone: function ( index ) { + + const cloned = { + index: ( typeof index === 'number' ? index : this.index ), + name: this.name, + mtllib: this.mtllib, + smooth: this.smooth, + groupStart: 0, + groupEnd: - 1, + groupCount: - 1, + inherited: false + }; + cloned.clone = this.clone.bind( cloned ); + return cloned; + + } + }; + + this.materials.push( material ); + + return material; + + }, + + currentMaterial: function () { + + if ( this.materials.length > 0 ) { + + return this.materials[ this.materials.length - 1 ]; + + } + + return undefined; + + }, + + _finalize: function ( end ) { + + const lastMultiMaterial = this.currentMaterial(); + if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) { + + lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3; + lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart; + lastMultiMaterial.inherited = false; + + } + + // Ignore objects tail materials if no face declarations followed them before a new o/g started. + if ( end && this.materials.length > 1 ) { + + for ( let mi = this.materials.length - 1; mi >= 0; mi -- ) { + + if ( this.materials[ mi ].groupCount <= 0 ) { + + this.materials.splice( mi, 1 ); + + } + + } + + } + + // Guarantee at least one empty material, this makes the creation later more straight forward. + if ( end && this.materials.length === 0 ) { + + this.materials.push( { + name: '', + smooth: this.smooth + } ); + + } + + return lastMultiMaterial; + + } + }; + + // Inherit previous objects material. + // Spec tells us that a declared material must be set to all objects until a new material is declared. + // If a usemtl declaration is encountered while this new object is being parsed, it will + // overwrite the inherited material. Exception being that there was already face declarations + // to the inherited material, then it will be preserved for proper MultiMaterial continuation. + + if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) { + + const declared = previousMaterial.clone( 0 ); + declared.inherited = true; + this.object.materials.push( declared ); + + } + + this.objects.push( this.object ); + + }, + + finalize: function () { + + if ( this.object && typeof this.object._finalize === 'function' ) { + + this.object._finalize( true ); + + } + + }, + + parseVertexIndex: function ( value, len ) { + + const index = parseInt( value, 10 ); + return ( index >= 0 ? index - 1 : index + len / 3 ) * 3; + + }, + + parseNormalIndex: function ( value, len ) { + + const index = parseInt( value, 10 ); + return ( index >= 0 ? index - 1 : index + len / 3 ) * 3; + + }, + + parseUVIndex: function ( value, len ) { + + const index = parseInt( value, 10 ); + return ( index >= 0 ? index - 1 : index + len / 2 ) * 2; + + }, + + addVertex: function ( a, b, c ) { + + const src = this.vertices; + const dst = this.object.geometry.vertices; + + dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); + dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); + dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); + + }, + + addVertexPoint: function ( a ) { + + const src = this.vertices; + const dst = this.object.geometry.vertices; + + dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); + + }, + + addVertexLine: function ( a ) { + + const src = this.vertices; + const dst = this.object.geometry.vertices; + + dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); + + }, + + addNormal: function ( a, b, c ) { + + const src = this.normals; + const dst = this.object.geometry.normals; + + dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); + dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); + dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); + + }, + + addFaceNormal: function ( a, b, c ) { + + const src = this.vertices; + const dst = this.object.geometry.normals; + + _vA.fromArray( src, a ); + _vB.fromArray( src, b ); + _vC.fromArray( src, c ); + + _cb.subVectors( _vC, _vB ); + _ab.subVectors( _vA, _vB ); + _cb.cross( _ab ); + + _cb.normalize(); + + dst.push( _cb.x, _cb.y, _cb.z ); + dst.push( _cb.x, _cb.y, _cb.z ); + dst.push( _cb.x, _cb.y, _cb.z ); + + }, + + addColor: function ( a, b, c ) { + + const src = this.colors; + const dst = this.object.geometry.colors; + + if ( src[ a ] !== undefined ) dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] ); + if ( src[ b ] !== undefined ) dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] ); + if ( src[ c ] !== undefined ) dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] ); + + }, + + addUV: function ( a, b, c ) { + + const src = this.uvs; + const dst = this.object.geometry.uvs; + + dst.push( src[ a + 0 ], src[ a + 1 ] ); + dst.push( src[ b + 0 ], src[ b + 1 ] ); + dst.push( src[ c + 0 ], src[ c + 1 ] ); + + }, + + addDefaultUV: function () { + + const dst = this.object.geometry.uvs; + + dst.push( 0, 0 ); + dst.push( 0, 0 ); + dst.push( 0, 0 ); + + }, + + addUVLine: function ( a ) { + + const src = this.uvs; + const dst = this.object.geometry.uvs; + + dst.push( src[ a + 0 ], src[ a + 1 ] ); + + }, + + addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) { + + const vLen = this.vertices.length; + + let ia = this.parseVertexIndex( a, vLen ); + let ib = this.parseVertexIndex( b, vLen ); + let ic = this.parseVertexIndex( c, vLen ); + + this.addVertex( ia, ib, ic ); + this.addColor( ia, ib, ic ); + + // normals + + if ( na !== undefined && na !== '' ) { + + const nLen = this.normals.length; + + ia = this.parseNormalIndex( na, nLen ); + ib = this.parseNormalIndex( nb, nLen ); + ic = this.parseNormalIndex( nc, nLen ); + + this.addNormal( ia, ib, ic ); + + } else { + + this.addFaceNormal( ia, ib, ic ); + + } + + // uvs + + if ( ua !== undefined && ua !== '' ) { + + const uvLen = this.uvs.length; + + ia = this.parseUVIndex( ua, uvLen ); + ib = this.parseUVIndex( ub, uvLen ); + ic = this.parseUVIndex( uc, uvLen ); + + this.addUV( ia, ib, ic ); + + this.object.geometry.hasUVIndices = true; + + } else { + + // add placeholder values (for inconsistent face definitions) + + this.addDefaultUV(); + + } + + }, + + addPointGeometry: function ( vertices ) { + + this.object.geometry.type = 'Points'; + + const vLen = this.vertices.length; + + for ( let vi = 0, l = vertices.length; vi < l; vi ++ ) { + + const index = this.parseVertexIndex( vertices[ vi ], vLen ); + + this.addVertexPoint( index ); + this.addColor( index ); + + } + + }, + + addLineGeometry: function ( vertices, uvs ) { + + this.object.geometry.type = 'Line'; + + const vLen = this.vertices.length; + const uvLen = this.uvs.length; + + for ( let vi = 0, l = vertices.length; vi < l; vi ++ ) { + + this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) ); + + } + + for ( let uvi = 0, l = uvs.length; uvi < l; uvi ++ ) { + + this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) ); + + } + + } + + }; + + state.startObject( '', false ); + + return state; + +} + +// + +class OBJLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + this.materials = null; + + } + + load( url, onLoad, onProgress, onError ) { + + const scope = this; + + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( text ) { + + try { + + onLoad( scope.parse( text ) ); + + } catch ( e ) { + + if ( onError ) { + + onError( e ); + + } else { + + console.error( e ); + + } + + scope.manager.itemError( url ); + + } + + }, onProgress, onError ); + + } + + setMaterials( materials ) { + + this.materials = materials; + + return this; + + } + + parse( text ) { + + const state = new ParserState(); + + if ( text.indexOf( '\r\n' ) !== - 1 ) { + + // This is faster than String.split with regex that splits on both + text = text.replace( /\r\n/g, '\n' ); + + } + + if ( text.indexOf( '\\\n' ) !== - 1 ) { + + // join lines separated by a line continuation character (\) + text = text.replace( /\\\n/g, '' ); + + } + + const lines = text.split( '\n' ); + let result = []; + + for ( let i = 0, l = lines.length; i < l; i ++ ) { + + const line = lines[ i ].trimStart(); + + if ( line.length === 0 ) continue; + + const lineFirstChar = line.charAt( 0 ); + + // @todo invoke passed in handler if any + if ( lineFirstChar === '#' ) continue; // skip comments + + if ( lineFirstChar === 'v' ) { + + const data = line.split( _face_vertex_data_separator_pattern ); + + switch ( data[ 0 ] ) { + + case 'v': + state.vertices.push( + parseFloat( data[ 1 ] ), + parseFloat( data[ 2 ] ), + parseFloat( data[ 3 ] ) + ); + if ( data.length >= 7 ) { + + _color.setRGB( + parseFloat( data[ 4 ] ), + parseFloat( data[ 5 ] ), + parseFloat( data[ 6 ] ), + SRGBColorSpace + ); + + state.colors.push( _color.r, _color.g, _color.b ); + + } else { + + // if no colors are defined, add placeholders so color and vertex indices match + + state.colors.push( undefined, undefined, undefined ); + + } + + break; + case 'vn': + state.normals.push( + parseFloat( data[ 1 ] ), + parseFloat( data[ 2 ] ), + parseFloat( data[ 3 ] ) + ); + break; + case 'vt': + state.uvs.push( + parseFloat( data[ 1 ] ), + parseFloat( data[ 2 ] ) + ); + break; + + } + + } else if ( lineFirstChar === 'f' ) { + + const lineData = line.slice( 1 ).trim(); + const vertexData = lineData.split( _face_vertex_data_separator_pattern ); + const faceVertices = []; + + // Parse the face vertex data into an easy to work with format + + for ( let j = 0, jl = vertexData.length; j < jl; j ++ ) { + + const vertex = vertexData[ j ]; + + if ( vertex.length > 0 ) { + + const vertexParts = vertex.split( '/' ); + faceVertices.push( vertexParts ); + + } + + } + + // Draw an edge between the first vertex and all subsequent vertices to form an n-gon + + const v1 = faceVertices[ 0 ]; + + for ( let j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) { + + const v2 = faceVertices[ j ]; + const v3 = faceVertices[ j + 1 ]; + + state.addFace( + v1[ 0 ], v2[ 0 ], v3[ 0 ], + v1[ 1 ], v2[ 1 ], v3[ 1 ], + v1[ 2 ], v2[ 2 ], v3[ 2 ] + ); + + } + + } else if ( lineFirstChar === 'l' ) { + + const lineParts = line.substring( 1 ).trim().split( ' ' ); + let lineVertices = []; + const lineUVs = []; + + if ( line.indexOf( '/' ) === - 1 ) { + + lineVertices = lineParts; + + } else { + + for ( let li = 0, llen = lineParts.length; li < llen; li ++ ) { + + const parts = lineParts[ li ].split( '/' ); + + if ( parts[ 0 ] !== '' ) lineVertices.push( parts[ 0 ] ); + if ( parts[ 1 ] !== '' ) lineUVs.push( parts[ 1 ] ); + + } + + } + + state.addLineGeometry( lineVertices, lineUVs ); + + } else if ( lineFirstChar === 'p' ) { + + const lineData = line.slice( 1 ).trim(); + const pointData = lineData.split( ' ' ); + + state.addPointGeometry( pointData ); + + } else if ( ( result = _object_pattern.exec( line ) ) !== null ) { + + // o object_name + // or + // g group_name + + // WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869 + // let name = result[ 0 ].slice( 1 ).trim(); + const name = ( ' ' + result[ 0 ].slice( 1 ).trim() ).slice( 1 ); + + state.startObject( name ); + + } else if ( _material_use_pattern.test( line ) ) { + + // material + + state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries ); + + } else if ( _material_library_pattern.test( line ) ) { + + // mtl file + + state.materialLibraries.push( line.substring( 7 ).trim() ); + + } else if ( _map_use_pattern.test( line ) ) { + + // the line is parsed but ignored since the loader assumes textures are defined MTL files + // (according to https://www.okino.com/conv/imp_wave.htm, 'usemap' is the old-style Wavefront texture reference method) + + console.warn( 'THREE.OBJLoader: Rendering identifier "usemap" not supported. Textures must be defined in MTL files.' ); + + } else if ( lineFirstChar === 's' ) { + + result = line.split( ' ' ); + + // smooth shading + + // @todo Handle files that have varying smooth values for a set of faces inside one geometry, + // but does not define a usemtl for each face set. + // This should be detected and a dummy material created (later MultiMaterial and geometry groups). + // This requires some care to not create extra material on each smooth value for "normal" obj files. + // where explicit usemtl defines geometry groups. + // Example asset: examples/models/obj/cerberus/Cerberus.obj + + /* + * http://paulbourke.net/dataformats/obj/ + * + * From chapter "Grouping" Syntax explanation "s group_number": + * "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off. + * Polygonal elements use group numbers to put elements in different smoothing groups. For free-form + * surfaces, smoothing groups are either turned on or off; there is no difference between values greater + * than 0." + */ + if ( result.length > 1 ) { + + const value = result[ 1 ].trim().toLowerCase(); + state.object.smooth = ( value !== '0' && value !== 'off' ); + + } else { + + // ZBrush can produce "s" lines #11707 + state.object.smooth = true; + + } + + const material = state.object.currentMaterial(); + if ( material ) material.smooth = state.object.smooth; + + } else { + + // Handle null terminated files without exception + if ( line === '\0' ) continue; + + console.warn( 'THREE.OBJLoader: Unexpected line: "' + line + '"' ); + + } + + } + + state.finalize(); + + const container = new Group(); + container.materialLibraries = [].concat( state.materialLibraries ); + + const hasPrimitives = ! ( state.objects.length === 1 && state.objects[ 0 ].geometry.vertices.length === 0 ); + + if ( hasPrimitives === true ) { + + for ( let i = 0, l = state.objects.length; i < l; i ++ ) { + + const object = state.objects[ i ]; + const geometry = object.geometry; + const materials = object.materials; + const isLine = ( geometry.type === 'Line' ); + const isPoints = ( geometry.type === 'Points' ); + let hasVertexColors = false; + + // Skip o/g line declarations that did not follow with any faces + if ( geometry.vertices.length === 0 ) continue; + + const buffergeometry = new BufferGeometry(); + + buffergeometry.setAttribute( 'position', new Float32BufferAttribute( geometry.vertices, 3 ) ); + + if ( geometry.normals.length > 0 ) { + + buffergeometry.setAttribute( 'normal', new Float32BufferAttribute( geometry.normals, 3 ) ); + + } + + if ( geometry.colors.length > 0 ) { + + hasVertexColors = true; + buffergeometry.setAttribute( 'color', new Float32BufferAttribute( geometry.colors, 3 ) ); + + } + + if ( geometry.hasUVIndices === true ) { + + buffergeometry.setAttribute( 'uv', new Float32BufferAttribute( geometry.uvs, 2 ) ); + + } + + // Create materials + + const createdMaterials = []; + + for ( let mi = 0, miLen = materials.length; mi < miLen; mi ++ ) { + + const sourceMaterial = materials[ mi ]; + const materialHash = sourceMaterial.name + '_' + sourceMaterial.smooth + '_' + hasVertexColors; + let material = state.materials[ materialHash ]; + + if ( this.materials !== null ) { + + material = this.materials.create( sourceMaterial.name ); + + // mtl etc. loaders probably can't create line materials correctly, copy properties to a line material. + if ( isLine && material && ! ( material instanceof LineBasicMaterial ) ) { + + const materialLine = new LineBasicMaterial(); + Material.prototype.copy.call( materialLine, material ); + materialLine.color.copy( material.color ); + material = materialLine; + + } else if ( isPoints && material && ! ( material instanceof PointsMaterial ) ) { + + const materialPoints = new PointsMaterial( { size: 10, sizeAttenuation: false } ); + Material.prototype.copy.call( materialPoints, material ); + materialPoints.color.copy( material.color ); + materialPoints.map = material.map; + material = materialPoints; + + } + + } + + if ( material === undefined ) { + + if ( isLine ) { + + material = new LineBasicMaterial(); + + } else if ( isPoints ) { + + material = new PointsMaterial( { size: 1, sizeAttenuation: false } ); + + } else { + + material = new MeshPhongMaterial(); + + } + + material.name = sourceMaterial.name; + material.flatShading = sourceMaterial.smooth ? false : true; + material.vertexColors = hasVertexColors; + + state.materials[ materialHash ] = material; + + } + + createdMaterials.push( material ); + + } + + // Create mesh + + let mesh; + + if ( createdMaterials.length > 1 ) { + + for ( let mi = 0, miLen = materials.length; mi < miLen; mi ++ ) { + + const sourceMaterial = materials[ mi ]; + buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi ); + + } + + if ( isLine ) { + + mesh = new LineSegments( buffergeometry, createdMaterials ); + + } else if ( isPoints ) { + + mesh = new Points( buffergeometry, createdMaterials ); + + } else { + + mesh = new Mesh( buffergeometry, createdMaterials ); + + } + + } else { + + if ( isLine ) { + + mesh = new LineSegments( buffergeometry, createdMaterials[ 0 ] ); + + } else if ( isPoints ) { + + mesh = new Points( buffergeometry, createdMaterials[ 0 ] ); + + } else { + + mesh = new Mesh( buffergeometry, createdMaterials[ 0 ] ); + + } + + } + + mesh.name = object.name; + + container.add( mesh ); + + } + + } else { + + // if there is only the default parser state object with no geometry data, interpret data as point cloud + + if ( state.vertices.length > 0 ) { + + const material = new PointsMaterial( { size: 1, sizeAttenuation: false } ); + + const buffergeometry = new BufferGeometry(); + + buffergeometry.setAttribute( 'position', new Float32BufferAttribute( state.vertices, 3 ) ); + + if ( state.colors.length > 0 && state.colors[ 0 ] !== undefined ) { + + buffergeometry.setAttribute( 'color', new Float32BufferAttribute( state.colors, 3 ) ); + material.vertexColors = true; + + } + + const points = new Points( buffergeometry, material ); + container.add( points ); + + } + + } + + return container; + + } + +} + +export { OBJLoader }; diff --git a/js/lib/jsm/loaders/STLLoader.js b/js/lib/jsm/loaders/STLLoader.js new file mode 100644 index 0000000..f346571 --- /dev/null +++ b/js/lib/jsm/loaders/STLLoader.js @@ -0,0 +1,411 @@ +import { + BufferAttribute, + BufferGeometry, + Color, + FileLoader, + Float32BufferAttribute, + Loader, + Vector3, + SRGBColorSpace +} from '../../three.module.js'; + +/** + * Description: A THREE loader for STL ASCII files, as created by Solidworks and other CAD programs. + * + * Supports both binary and ASCII encoded files, with automatic detection of type. + * + * The loader returns a non-indexed buffer geometry. + * + * Limitations: + * Binary decoding supports "Magics" color format (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL). + * There is perhaps some question as to how valid it is to always assume little-endian-ness. + * ASCII decoding assumes file is UTF-8. + * + * Usage: + * const loader = new STLLoader(); + * loader.load( './models/stl/slotted_disk.stl', function ( geometry ) { + * scene.add( new THREE.Mesh( geometry ) ); + * }); + * + * For binary STLs geometry might contain colors for vertices. To use it: + * // use the same code to load STL as above + * if (geometry.hasColors) { + * material = new THREE.MeshPhongMaterial({ opacity: geometry.alpha, vertexColors: true }); + * } else { .... } + * const mesh = new THREE.Mesh( geometry, material ); + * + * For ASCII STLs containing multiple solids, each solid is assigned to a different group. + * Groups can be used to assign a different color by defining an array of materials with the same length of + * geometry.groups and passing it to the Mesh constructor: + * + * const mesh = new THREE.Mesh( geometry, material ); + * + * For example: + * + * const materials = []; + * const nGeometryGroups = geometry.groups.length; + * + * const colorMap = ...; // Some logic to index colors. + * + * for (let i = 0; i < nGeometryGroups; i++) { + * + * const material = new THREE.MeshPhongMaterial({ + * color: colorMap[i], + * wireframe: false + * }); + * + * } + * + * materials.push(material); + * const mesh = new THREE.Mesh(geometry, materials); + */ + + +class STLLoader extends Loader { + + constructor( manager ) { + + super( manager ); + + } + + load( url, onLoad, onProgress, onError ) { + + const scope = this; + + const loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setResponseType( 'arraybuffer' ); + loader.setRequestHeader( this.requestHeader ); + loader.setWithCredentials( this.withCredentials ); + + loader.load( url, function ( text ) { + + try { + + onLoad( scope.parse( text ) ); + + } catch ( e ) { + + if ( onError ) { + + onError( e ); + + } else { + + console.error( e ); + + } + + scope.manager.itemError( url ); + + } + + }, onProgress, onError ); + + } + + parse( data ) { + + function isBinary( data ) { + + const reader = new DataView( data ); + const face_size = ( 32 / 8 * 3 ) + ( ( 32 / 8 * 3 ) * 3 ) + ( 16 / 8 ); + const n_faces = reader.getUint32( 80, true ); + const expect = 80 + ( 32 / 8 ) + ( n_faces * face_size ); + + if ( expect === reader.byteLength ) { + + return true; + + } + + // An ASCII STL data must begin with 'solid ' as the first six bytes. + // However, ASCII STLs lacking the SPACE after the 'd' are known to be + // plentiful. So, check the first 5 bytes for 'solid'. + + // Several encodings, such as UTF-8, precede the text with up to 5 bytes: + // https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding + // Search for "solid" to start anywhere after those prefixes. + + // US-ASCII ordinal values for 's', 'o', 'l', 'i', 'd' + + const solid = [ 115, 111, 108, 105, 100 ]; + + for ( let off = 0; off < 5; off ++ ) { + + // If "solid" text is matched to the current offset, declare it to be an ASCII STL. + + if ( matchDataViewAt( solid, reader, off ) ) return false; + + } + + // Couldn't find "solid" text at the beginning; it is binary STL. + + return true; + + } + + function matchDataViewAt( query, reader, offset ) { + + // Check if each byte in query matches the corresponding byte from the current offset + + for ( let i = 0, il = query.length; i < il; i ++ ) { + + if ( query[ i ] !== reader.getUint8( offset + i ) ) return false; + + } + + return true; + + } + + function parseBinary( data ) { + + const reader = new DataView( data ); + const faces = reader.getUint32( 80, true ); + + let r, g, b, hasColors = false, colors; + let defaultR, defaultG, defaultB, alpha; + + // process STL header + // check for default color in header ("COLOR=rgba" sequence). + + for ( let index = 0; index < 80 - 10; index ++ ) { + + if ( ( reader.getUint32( index, false ) == 0x434F4C4F /*COLO*/ ) && + ( reader.getUint8( index + 4 ) == 0x52 /*'R'*/ ) && + ( reader.getUint8( index + 5 ) == 0x3D /*'='*/ ) ) { + + hasColors = true; + colors = new Float32Array( faces * 3 * 3 ); + + defaultR = reader.getUint8( index + 6 ) / 255; + defaultG = reader.getUint8( index + 7 ) / 255; + defaultB = reader.getUint8( index + 8 ) / 255; + alpha = reader.getUint8( index + 9 ) / 255; + + } + + } + + const dataOffset = 84; + const faceLength = 12 * 4 + 2; + + const geometry = new BufferGeometry(); + + const vertices = new Float32Array( faces * 3 * 3 ); + const normals = new Float32Array( faces * 3 * 3 ); + + const color = new Color(); + + for ( let face = 0; face < faces; face ++ ) { + + const start = dataOffset + face * faceLength; + const normalX = reader.getFloat32( start, true ); + const normalY = reader.getFloat32( start + 4, true ); + const normalZ = reader.getFloat32( start + 8, true ); + + if ( hasColors ) { + + const packedColor = reader.getUint16( start + 48, true ); + + if ( ( packedColor & 0x8000 ) === 0 ) { + + // facet has its own unique color + + r = ( packedColor & 0x1F ) / 31; + g = ( ( packedColor >> 5 ) & 0x1F ) / 31; + b = ( ( packedColor >> 10 ) & 0x1F ) / 31; + + } else { + + r = defaultR; + g = defaultG; + b = defaultB; + + } + + } + + for ( let i = 1; i <= 3; i ++ ) { + + const vertexstart = start + i * 12; + const componentIdx = ( face * 3 * 3 ) + ( ( i - 1 ) * 3 ); + + vertices[ componentIdx ] = reader.getFloat32( vertexstart, true ); + vertices[ componentIdx + 1 ] = reader.getFloat32( vertexstart + 4, true ); + vertices[ componentIdx + 2 ] = reader.getFloat32( vertexstart + 8, true ); + + normals[ componentIdx ] = normalX; + normals[ componentIdx + 1 ] = normalY; + normals[ componentIdx + 2 ] = normalZ; + + if ( hasColors ) { + + color.setRGB( r, g, b, SRGBColorSpace ); + + colors[ componentIdx ] = color.r; + colors[ componentIdx + 1 ] = color.g; + colors[ componentIdx + 2 ] = color.b; + + } + + } + + } + + geometry.setAttribute( 'position', new BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'normal', new BufferAttribute( normals, 3 ) ); + + if ( hasColors ) { + + geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) ); + geometry.hasColors = true; + geometry.alpha = alpha; + + } + + return geometry; + + } + + function parseASCII( data ) { + + const geometry = new BufferGeometry(); + const patternSolid = /solid([\s\S]*?)endsolid/g; + const patternFace = /facet([\s\S]*?)endfacet/g; + const patternName = /solid\s(.+)/; + let faceCounter = 0; + + const patternFloat = /[\s]+([+-]?(?:\d*)(?:\.\d*)?(?:[eE][+-]?\d+)?)/.source; + const patternVertex = new RegExp( 'vertex' + patternFloat + patternFloat + patternFloat, 'g' ); + const patternNormal = new RegExp( 'normal' + patternFloat + patternFloat + patternFloat, 'g' ); + + const vertices = []; + const normals = []; + const groupNames = []; + + const normal = new Vector3(); + + let result; + + let groupCount = 0; + let startVertex = 0; + let endVertex = 0; + + while ( ( result = patternSolid.exec( data ) ) !== null ) { + + startVertex = endVertex; + + const solid = result[ 0 ]; + + const name = ( result = patternName.exec( solid ) ) !== null ? result[ 1 ] : ''; + groupNames.push( name ); + + while ( ( result = patternFace.exec( solid ) ) !== null ) { + + let vertexCountPerFace = 0; + let normalCountPerFace = 0; + + const text = result[ 0 ]; + + while ( ( result = patternNormal.exec( text ) ) !== null ) { + + normal.x = parseFloat( result[ 1 ] ); + normal.y = parseFloat( result[ 2 ] ); + normal.z = parseFloat( result[ 3 ] ); + normalCountPerFace ++; + + } + + while ( ( result = patternVertex.exec( text ) ) !== null ) { + + vertices.push( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) ); + normals.push( normal.x, normal.y, normal.z ); + vertexCountPerFace ++; + endVertex ++; + + } + + // every face have to own ONE valid normal + + if ( normalCountPerFace !== 1 ) { + + console.error( 'THREE.STLLoader: Something isn\'t right with the normal of face number ' + faceCounter ); + + } + + // each face have to own THREE valid vertices + + if ( vertexCountPerFace !== 3 ) { + + console.error( 'THREE.STLLoader: Something isn\'t right with the vertices of face number ' + faceCounter ); + + } + + faceCounter ++; + + } + + const start = startVertex; + const count = endVertex - startVertex; + + geometry.userData.groupNames = groupNames; + + geometry.addGroup( start, count, groupCount ); + groupCount ++; + + } + + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + + return geometry; + + } + + function ensureString( buffer ) { + + if ( typeof buffer !== 'string' ) { + + return new TextDecoder().decode( buffer ); + + } + + return buffer; + + } + + function ensureBinary( buffer ) { + + if ( typeof buffer === 'string' ) { + + const array_buffer = new Uint8Array( buffer.length ); + for ( let i = 0; i < buffer.length; i ++ ) { + + array_buffer[ i ] = buffer.charCodeAt( i ) & 0xff; // implicitly assumes little-endian + + } + + return array_buffer.buffer || array_buffer; + + } else { + + return buffer; + + } + + } + + // start + + const binData = ensureBinary( data ); + + return isBinary( binData ) ? parseBinary( binData ) : parseASCII( ensureString( data ) ); + + } + +} + +export { STLLoader }; diff --git a/js/lib/jsm/math/ColorSpaces.js b/js/lib/jsm/math/ColorSpaces.js new file mode 100644 index 0000000..74511a1 --- /dev/null +++ b/js/lib/jsm/math/ColorSpaces.js @@ -0,0 +1,76 @@ +import { LinearTransfer, Matrix3, SRGBTransfer } from '../../three.module.js'; + +// Reference: http://www.russellcottrell.com/photo/matrixCalculator.htm + +const P3_PRIMARIES = [ 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 ]; +const P3_LUMINANCE_COEFFICIENTS = [ 0.2289, 0.6917, 0.0793 ]; +const REC2020_PRIMARIES = [ 0.708, 0.292, 0.170, 0.797, 0.131, 0.046 ]; +const REC2020_LUMINANCE_COEFFICIENTS = [ 0.2627, 0.6780, 0.0593 ]; +const D65 = [ 0.3127, 0.3290 ]; + +/****************************************************************************** + * Display P3 definitions + */ + +const LINEAR_DISPLAY_P3_TO_XYZ = /*@__PURE__*/ new Matrix3().set( + 0.4865709, 0.2656677, 0.1982173, + 0.2289746, 0.6917385, 0.0792869, + 0.0000000, 0.0451134, 1.0439444 +); + +const XYZ_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().set( + 2.4934969, - 0.9313836, - 0.4027108, + - 0.8294890, 1.7626641, 0.0236247, + 0.0358458, - 0.0761724, 0.9568845 +); + +export const DisplayP3ColorSpace = 'display-p3'; +export const LinearDisplayP3ColorSpace = 'display-p3-linear'; + +export const DisplayP3ColorSpaceImpl = { + primaries: P3_PRIMARIES, + whitePoint: D65, + transfer: SRGBTransfer, + toXYZ: LINEAR_DISPLAY_P3_TO_XYZ, + fromXYZ: XYZ_TO_LINEAR_DISPLAY_P3, + luminanceCoefficients: P3_LUMINANCE_COEFFICIENTS, + outputColorSpaceConfig: { drawingBufferColorSpace: DisplayP3ColorSpace } +}; + +export const LinearDisplayP3ColorSpaceImpl = { + primaries: P3_PRIMARIES, + whitePoint: D65, + transfer: LinearTransfer, + toXYZ: LINEAR_DISPLAY_P3_TO_XYZ, + fromXYZ: XYZ_TO_LINEAR_DISPLAY_P3, + luminanceCoefficients: P3_LUMINANCE_COEFFICIENTS, + workingColorSpaceConfig: { unpackColorSpace: DisplayP3ColorSpace }, + outputColorSpaceConfig: { drawingBufferColorSpace: DisplayP3ColorSpace } +}; + +/****************************************************************************** + * Rec. 2020 definitions + */ + +const LINEAR_REC2020_TO_XYZ = /*@__PURE__*/ new Matrix3().set( + 0.6369580, 0.1446169, 0.1688810, + 0.2627002, 0.6779981, 0.0593017, + 0.0000000, 0.0280727, 1.0609851 +); + +const XYZ_TO_LINEAR_REC2020 = /*@__PURE__*/ new Matrix3().set( + 1.7166512, - 0.3556708, - 0.2533663, + - 0.6666844, 1.6164812, 0.0157685, + 0.0176399, - 0.0427706, 0.9421031 +); + +export const LinearRec2020ColorSpace = 'rec2020-linear'; + +export const LinearRec2020ColorSpaceImpl = { + primaries: REC2020_PRIMARIES, + whitePoint: D65, + transfer: LinearTransfer, + toXYZ: LINEAR_REC2020_TO_XYZ, + fromXYZ: XYZ_TO_LINEAR_REC2020, + luminanceCoefficients: REC2020_LUMINANCE_COEFFICIENTS, +}; diff --git a/js/lib/jsm/utils/WorkerPool.js b/js/lib/jsm/utils/WorkerPool.js new file mode 100644 index 0000000..c8d1916 --- /dev/null +++ b/js/lib/jsm/utils/WorkerPool.js @@ -0,0 +1,102 @@ +/** + * @author Deepkolos / https://github.com/deepkolos + */ + +export class WorkerPool { + + constructor( pool = 4 ) { + + this.pool = pool; + this.queue = []; + this.workers = []; + this.workersResolve = []; + this.workerStatus = 0; + + } + + _initWorker( workerId ) { + + if ( ! this.workers[ workerId ] ) { + + const worker = this.workerCreator(); + worker.addEventListener( 'message', this._onMessage.bind( this, workerId ) ); + this.workers[ workerId ] = worker; + + } + + } + + _getIdleWorker() { + + for ( let i = 0; i < this.pool; i ++ ) + if ( ! ( this.workerStatus & ( 1 << i ) ) ) return i; + + return - 1; + + } + + _onMessage( workerId, msg ) { + + const resolve = this.workersResolve[ workerId ]; + resolve && resolve( msg ); + + if ( this.queue.length ) { + + const { resolve, msg, transfer } = this.queue.shift(); + this.workersResolve[ workerId ] = resolve; + this.workers[ workerId ].postMessage( msg, transfer ); + + } else { + + this.workerStatus ^= 1 << workerId; + + } + + } + + setWorkerCreator( workerCreator ) { + + this.workerCreator = workerCreator; + + } + + setWorkerLimit( pool ) { + + this.pool = pool; + + } + + postMessage( msg, transfer ) { + + return new Promise( ( resolve ) => { + + const workerId = this._getIdleWorker(); + + if ( workerId !== - 1 ) { + + this._initWorker( workerId ); + this.workerStatus |= 1 << workerId; + this.workersResolve[ workerId ] = resolve; + this.workers[ workerId ].postMessage( msg, transfer ); + + } else { + + this.queue.push( { resolve, msg, transfer } ); + + } + + } ); + + } + + dispose() { + + this.workers.forEach( ( worker ) => worker.terminate() ); + this.workersResolve.length = 0; + this.workers.length = 0; + this.queue.length = 0; + this.workerStatus = 0; + + } + +} diff --git a/js/three_view.js b/js/three_view.js index e391c00..e3e18bf 100644 --- a/js/three_view.js +++ b/js/three_view.js @@ -229,7 +229,7 @@ app.registerExtension({ if (threeCanvasId !== -1 && w?.widgets_values[threeCanvasId]) { // Get widget threeCanvas by Index - const threeCnavasWidget = this.widgets[threeCanvasId].threeCanvas + const threeCanvasWidget = this.widgets[threeCanvasId].threeCanvas // Get value size and options const {size: sizeData, camera: cameraData, currentModel} = w.widgets_values[threeCanvasId]; @@ -238,7 +238,7 @@ app.registerExtension({ if(sizeData){ const { w: width, h: height } = sizeData; if(width && height){ - threeCnavasWidget.setCanvasSize(width, height); + threeCanvasWidget.setCanvasSize(width, height); this.title = `${this.type} [${width}x${height}]`; } } @@ -258,17 +258,17 @@ app.registerExtension({ urlData = new URL(currentModel, import.meta.url).href } - await threeCnavasWidget.loaderGltf.load(urlData, ( glb ) => { - threeCnavasWidget.addModel( glb ); + await threeCanvasWidget.getLoader('glb').load(urlData, ( glb ) => { + threeCanvasWidget.addModel( glb ); // Load camera data - if( cameraData ) threeCnavasWidget.loadCameraState( cameraData ) + if( cameraData ) threeCanvasWidget.loadCameraState( cameraData ) }, ( data ) => {/* console.log( `Loaded data: ${data.loaded}/${data.total}` */}, ( err ) => { console.log( err ); - threeCnavasWidget.addHeadTest(); + threeCanvasWidget.addHeadTest(); }) }