{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To do:\n",
    "\n",
    "- Parametrize gen_twisted_boundary over boundaries and\n",
    "do my nested spiral\n",
    "- Rewrite ram_horn in terms of newer abstractions\n",
    "- Encode the notions of \"generator which transforms an\n",
    "existing list of boundaries\", \"generator which transforms\n",
    "another generator\"\n",
    "- Work directly with lists of boundaries. The only thing\n",
    "I ever do with them is apply transforms to all of them, or\n",
    "join adjacent ones with corresponding elements.\n",
    "- Why do I get the weird zig-zag pattern on the triangles,\n",
    "despite larger numbers of them? Is it something in how I\n",
    "twist the frames?\n",
    "  - How can I compute the *torsion* on a quad? I think it\n",
    "    comes down to this: torsion applied across the quad I'm\n",
    "    triangulating leading to neither diagonal being a\n",
    "    particularly good choice.  Subdividing the boundary seems\n",
    "    to help, but other triangulation methods (e.g. turning a\n",
    "    quad to 4 triangles by adding the centroid) could be good\n",
    "    too.\n",
    "  - Facets/edges are just oriented the wrong way...\n",
    "- I need an actual example of branching/forking. If I simply\n",
    "split a boundary into sub-boundaries per the rules I already\n",
    "have in my notes, then this still lets me split any way I want\n",
    "to without having to worry about joining N boundaries instead\n",
    "of 2, doesn't it?\n",
    "\n",
    "Other notes:\n",
    "- Picking at random the diagonal on the quad to triangulate with\n",
    "  does seem to turn 'error' just to noise, and in its own way this\n",
    "  is preferable. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import stl.mesh\n",
    "import numpy\n",
    "import trimesh\n",
    "import random\n",
    "\n",
    "import meshutil\n",
    "import examples"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "#mesh = examples.ram_horn()\n",
    "#mesh = examples.twist()\n",
    "#mesh = examples.twist_nonlinear()\n",
    "#mesh = examples.twist_from_gen()\n",
    "mesh = examples.twisty_torus(1000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# for me to be able to nest this, gen_twisted_boundary has to\n",
    "# be parametrized over some other boundary (the way )\n",
    "#gen = examples.gen_inc_y(examples.gen_twisted_boundary())\n",
    "#mesh = gen2mesh(gen, 100, True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Work around some annoying-ass trimesh/threejs bug:\n",
    "wtf = meshutil.Transform().scale(0.1).translate(20,0,0)\n",
    "center = meshutil.Transform().translate(-0.5, -0.5, -0.5)\n",
    "base = meshutil.cube(open_xz=False).transform(center)\n",
    "base = base.transform(wtf)\n",
    "mesh_out = mesh\n",
    "# to enable:\n",
    "mesh_out = mesh_out.concat(base)\n",
    "\n",
    "mesh_fname = \"twist_wtf.stl\"\n",
    "mesh_out.to_stl_mesh().save(mesh_fname)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "face_normals didn't match triangles, ignoring!\n",
      "/home/hodapp/.local/lib/python3.6/site-packages/IPython/core/display.py:694: UserWarning: Consider using IPython.display.IFrame instead\n",
      "  warnings.warn(\"Consider using IPython.display.IFrame instead\")\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<iframe srcdoc=\"<!DOCTYPE html>\n",
       "<html lang=&quot;en&quot;>\n",
       "  <head>\n",
       "    <title>trimesh: threejs viewer</title>\n",
       "    <meta charset=&quot;utf-8&quot;>\n",
       "    <meta name=&quot;viewport&quot; content=&quot;width=device-width, \n",
       "\t\t   user-scalable=no, \n",
       "\t\t   minimum-scale=1.0, \n",
       "\t\t   maximum-scale=1.0&quot;>\n",
       "    <style>\n",
       "      body {\n",
       "      margin: 0px;\n",
       "      overflow: hidden;\n",
       "      }\n",
       "    </style>\n",
       "  </head>\n",
       "  <body>\n",
       "    <div id=&quot;container&quot;></div>\n",
       "    <script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/three.js/106/three.min.js&quot;></script>\n",
       "    <script>THREE.TrackballControls=function(object,domElement){var _this=this;var STATE={NONE:-1,ROTATE:0,ZOOM:1,PAN:2,TOUCH_ROTATE:3,TOUCH_ZOOM_PAN:4};this.object=object;this.domElement=(domElement!==undefined)?domElement:document;this.enabled=true;this.screen={left:0,top:0,width:0,height:0};this.rotateSpeed=1.0;this.zoomSpeed=1.2;this.panSpeed=0.3;this.noRotate=false;this.noZoom=false;this.noPan=false;this.staticMoving=false;this.dynamicDampingFactor=0.2;this.minDistance=0;this.maxDistance=Infinity;this.keys=[65 ,83 ,68 ];this.target=new THREE.Vector3();var EPS=0.000001;var lastPosition=new THREE.Vector3();var _state=STATE.NONE,_prevState=STATE.NONE,_eye=new THREE.Vector3(),_movePrev=new THREE.Vector2(),_moveCurr=new THREE.Vector2(),_lastAxis=new THREE.Vector3(),_lastAngle=0,_zoomStart=new THREE.Vector2(),_zoomEnd=new THREE.Vector2(),_touchZoomDistanceStart=0,_touchZoomDistanceEnd=0,_panStart=new THREE.Vector2(),_panEnd=new THREE.Vector2();this.target0=this.target.clone();this.position0=this.object.position.clone();this.up0=this.object.up.clone();var changeEvent={type:'change'};var startEvent={type:'start'};var endEvent={type:'end'};this.handleResize=function(){if(this.domElement===document){this.screen.left=0;this.screen.top=0;this.screen.width=window.innerWidth;this.screen.height=window.innerHeight;}else{var box=this.domElement.getBoundingClientRect();var d=this.domElement.ownerDocument.documentElement;this.screen.left=box.left+window.pageXOffset-d.clientLeft;this.screen.top=box.top+window.pageYOffset-d.clientTop;this.screen.width=box.width;this.screen.height=box.height;}};var getMouseOnScreen=(function(){var vector=new THREE.Vector2();return function getMouseOnScreen(pageX,pageY){vector.set((pageX-_this.screen.left)/_this.screen.width,(pageY-_this.screen.top)/_this.screen.height);return vector;};}());var getMouseOnCircle=(function(){var vector=new THREE.Vector2();return function getMouseOnCircle(pageX,pageY){vector.set(((pageX-_this.screen.width*0.5-_this.screen.left)/(_this.screen.width*0.5)),((_this.screen.height+2*(_this.screen.top-pageY))/_this.screen.width));return vector;};}());this.rotateCamera=(function(){var axis=new THREE.Vector3(),quaternion=new THREE.Quaternion(),eyeDirection=new THREE.Vector3(),objectUpDirection=new THREE.Vector3(),objectSidewaysDirection=new THREE.Vector3(),moveDirection=new THREE.Vector3(),angle;return function rotateCamera(){moveDirection.set(_moveCurr.x-_movePrev.x,_moveCurr.y-_movePrev.y,0);angle=moveDirection.length();if(angle){_eye.copy(_this.object.position).sub(_this.target);eyeDirection.copy(_eye).normalize();objectUpDirection.copy(_this.object.up).normalize();objectSidewaysDirection.crossVectors(objectUpDirection,eyeDirection).normalize();objectUpDirection.setLength(_moveCurr.y-_movePrev.y);objectSidewaysDirection.setLength(_moveCurr.x-_movePrev.x);moveDirection.copy(objectUpDirection.add(objectSidewaysDirection));axis.crossVectors(moveDirection,_eye).normalize();angle*=_this.rotateSpeed;quaternion.setFromAxisAngle(axis,angle);_eye.applyQuaternion(quaternion);_this.object.up.applyQuaternion(quaternion);_lastAxis.copy(axis);_lastAngle=angle;}else if(!_this.staticMoving&&_lastAngle){_lastAngle*=Math.sqrt(1.0-_this.dynamicDampingFactor);_eye.copy(_this.object.position).sub(_this.target);quaternion.setFromAxisAngle(_lastAxis,_lastAngle);_eye.applyQuaternion(quaternion);_this.object.up.applyQuaternion(quaternion);}\n",
       "_movePrev.copy(_moveCurr);};}());this.zoomCamera=function(){var factor;if(_state===STATE.TOUCH_ZOOM_PAN){factor=_touchZoomDistanceStart/_touchZoomDistanceEnd;_touchZoomDistanceStart=_touchZoomDistanceEnd;_eye.multiplyScalar(factor);}else{factor=1.0+(_zoomEnd.y-_zoomStart.y)*_this.zoomSpeed;if(factor!==1.0&&factor>0.0){_eye.multiplyScalar(factor);}\n",
       "if(_this.staticMoving){_zoomStart.copy(_zoomEnd);}else{_zoomStart.y+=(_zoomEnd.y-_zoomStart.y)*this.dynamicDampingFactor;}}};this.panCamera=(function(){var mouseChange=new THREE.Vector2(),objectUp=new THREE.Vector3(),pan=new THREE.Vector3();return function panCamera(){mouseChange.copy(_panEnd).sub(_panStart);if(mouseChange.lengthSq()){mouseChange.multiplyScalar(_eye.length()*_this.panSpeed);pan.copy(_eye).cross(_this.object.up).setLength(mouseChange.x);pan.add(objectUp.copy(_this.object.up).setLength(mouseChange.y));_this.object.position.add(pan);_this.target.add(pan);if(_this.staticMoving){_panStart.copy(_panEnd);}else{_panStart.add(mouseChange.subVectors(_panEnd,_panStart).multiplyScalar(_this.dynamicDampingFactor));}}};}());this.checkDistances=function(){if(!_this.noZoom||!_this.noPan){if(_eye.lengthSq()>_this.maxDistance*_this.maxDistance){_this.object.position.addVectors(_this.target,_eye.setLength(_this.maxDistance));_zoomStart.copy(_zoomEnd);}\n",
       "if(_eye.lengthSq()<_this.minDistance*_this.minDistance){_this.object.position.addVectors(_this.target,_eye.setLength(_this.minDistance));_zoomStart.copy(_zoomEnd);}}};this.update=function(){_eye.subVectors(_this.object.position,_this.target);if(!_this.noRotate){_this.rotateCamera();}\n",
       "if(!_this.noZoom){_this.zoomCamera();}\n",
       "if(!_this.noPan){_this.panCamera();}\n",
       "_this.object.position.addVectors(_this.target,_eye);_this.checkDistances();_this.object.lookAt(_this.target);if(lastPosition.distanceToSquared(_this.object.position)>EPS){_this.dispatchEvent(changeEvent);lastPosition.copy(_this.object.position);}};this.reset=function(){_state=STATE.NONE;_prevState=STATE.NONE;_this.target.copy(_this.target0);_this.object.position.copy(_this.position0);_this.object.up.copy(_this.up0);_eye.subVectors(_this.object.position,_this.target);_this.object.lookAt(_this.target);_this.dispatchEvent(changeEvent);lastPosition.copy(_this.object.position);};function keydown(event){if(_this.enabled===false)return;window.removeEventListener('keydown',keydown);_prevState=_state;if(_state!==STATE.NONE){return;}else if(event.keyCode===_this.keys[STATE.ROTATE]&&!_this.noRotate){_state=STATE.ROTATE;}else if(event.keyCode===_this.keys[STATE.ZOOM]&&!_this.noZoom){_state=STATE.ZOOM;}else if(event.keyCode===_this.keys[STATE.PAN]&&!_this.noPan){_state=STATE.PAN;}}\n",
       "function keyup(event){if(_this.enabled===false)return;_state=_prevState;window.addEventListener('keydown',keydown,false);}\n",
       "function mousedown(event){if(_this.enabled===false)return;event.preventDefault();event.stopPropagation();if(_state===STATE.NONE){_state=event.button;}\n",
       "if(_state===STATE.ROTATE&&!_this.noRotate){_moveCurr.copy(getMouseOnCircle(event.pageX,event.pageY));_movePrev.copy(_moveCurr);}else if(_state===STATE.ZOOM&&!_this.noZoom){_zoomStart.copy(getMouseOnScreen(event.pageX,event.pageY));_zoomEnd.copy(_zoomStart);}else if(_state===STATE.PAN&&!_this.noPan){_panStart.copy(getMouseOnScreen(event.pageX,event.pageY));_panEnd.copy(_panStart);}\n",
       "document.addEventListener('mousemove',mousemove,false);document.addEventListener('mouseup',mouseup,false);_this.dispatchEvent(startEvent);}\n",
       "function mousemove(event){if(_this.enabled===false)return;event.preventDefault();event.stopPropagation();if(_state===STATE.ROTATE&&!_this.noRotate){_movePrev.copy(_moveCurr);_moveCurr.copy(getMouseOnCircle(event.pageX,event.pageY));}else if(_state===STATE.ZOOM&&!_this.noZoom){_zoomEnd.copy(getMouseOnScreen(event.pageX,event.pageY));}else if(_state===STATE.PAN&&!_this.noPan){_panEnd.copy(getMouseOnScreen(event.pageX,event.pageY));}}\n",
       "function mouseup(event){if(_this.enabled===false)return;event.preventDefault();event.stopPropagation();_state=STATE.NONE;document.removeEventListener('mousemove',mousemove);document.removeEventListener('mouseup',mouseup);_this.dispatchEvent(endEvent);}\n",
       "function mousewheel(event){if(_this.enabled===false)return;if(_this.noZoom===true)return;event.preventDefault();event.stopPropagation();switch(event.deltaMode){case 2:_zoomStart.y-=event.deltaY*0.025;break;case 1:_zoomStart.y-=event.deltaY*0.01;break;default:_zoomStart.y-=event.deltaY*0.00025;break;}\n",
       "_this.dispatchEvent(startEvent);_this.dispatchEvent(endEvent);}\n",
       "function touchstart(event){if(_this.enabled===false)return;event.preventDefault();switch(event.touches.length){case 1:_state=STATE.TOUCH_ROTATE;_moveCurr.copy(getMouseOnCircle(event.touches[0].pageX,event.touches[0].pageY));_movePrev.copy(_moveCurr);break;default:_state=STATE.TOUCH_ZOOM_PAN;var dx=event.touches[0].pageX-event.touches[1].pageX;var dy=event.touches[0].pageY-event.touches[1].pageY;_touchZoomDistanceEnd=_touchZoomDistanceStart=Math.sqrt(dx*dx+dy*dy);var x=(event.touches[0].pageX+event.touches[1].pageX)/2;var y=(event.touches[0].pageY+event.touches[1].pageY)/2;_panStart.copy(getMouseOnScreen(x,y));_panEnd.copy(_panStart);break;}\n",
       "_this.dispatchEvent(startEvent);}\n",
       "function touchmove(event){if(_this.enabled===false)return;event.preventDefault();event.stopPropagation();switch(event.touches.length){case 1:_movePrev.copy(_moveCurr);_moveCurr.copy(getMouseOnCircle(event.touches[0].pageX,event.touches[0].pageY));break;default:var dx=event.touches[0].pageX-event.touches[1].pageX;var dy=event.touches[0].pageY-event.touches[1].pageY;_touchZoomDistanceEnd=Math.sqrt(dx*dx+dy*dy);var x=(event.touches[0].pageX+event.touches[1].pageX)/2;var y=(event.touches[0].pageY+event.touches[1].pageY)/2;_panEnd.copy(getMouseOnScreen(x,y));break;}}\n",
       "function touchend(event){if(_this.enabled===false)return;switch(event.touches.length){case 0:_state=STATE.NONE;break;case 1:_state=STATE.TOUCH_ROTATE;_moveCurr.copy(getMouseOnCircle(event.touches[0].pageX,event.touches[0].pageY));_movePrev.copy(_moveCurr);break;}\n",
       "_this.dispatchEvent(endEvent);}\n",
       "function contextmenu(event){if(_this.enabled===false)return;event.preventDefault();}\n",
       "this.dispose=function(){this.domElement.removeEventListener('contextmenu',contextmenu,false);this.domElement.removeEventListener('mousedown',mousedown,false);this.domElement.removeEventListener('wheel',mousewheel,false);this.domElement.removeEventListener('touchstart',touchstart,false);this.domElement.removeEventListener('touchend',touchend,false);this.domElement.removeEventListener('touchmove',touchmove,false);document.removeEventListener('mousemove',mousemove,false);document.removeEventListener('mouseup',mouseup,false);window.removeEventListener('keydown',keydown,false);window.removeEventListener('keyup',keyup,false);};this.domElement.addEventListener('contextmenu',contextmenu,false);this.domElement.addEventListener('mousedown',mousedown,false);this.domElement.addEventListener('wheel',mousewheel,false);this.domElement.addEventListener('touchstart',touchstart,false);this.domElement.addEventListener('touchend',touchend,false);this.domElement.addEventListener('touchmove',touchmove,false);window.addEventListener('keydown',keydown,false);window.addEventListener('keyup',keyup,false);this.handleResize();this.update();};THREE.TrackballControls.prototype=Object.create(THREE.EventDispatcher.prototype);THREE.TrackballControls.prototype.constructor=THREE.TrackballControls;THREE.GLTFLoader=(function(){function GLTFLoader(manager){this.manager=(manager!==undefined)?manager:THREE.DefaultLoadingManager;this.dracoLoader=null;this.ddsLoader=null;}\n",
       "GLTFLoader.prototype={constructor:GLTFLoader,crossOrigin:'anonymous',load:function(url,onLoad,onProgress,onError){var scope=this;var resourcePath;if(this.resourcePath!==undefined){resourcePath=this.resourcePath;}else if(this.path!==undefined){resourcePath=this.path;}else{resourcePath=THREE.LoaderUtils.extractUrlBase(url);}\n",
       "scope.manager.itemStart(url);var _onError=function(e){if(onError){onError(e);}else{console.error(e);}\n",
       "scope.manager.itemError(url);scope.manager.itemEnd(url);};var loader=new THREE.FileLoader(scope.manager);loader.setPath(this.path);loader.setResponseType('arraybuffer');if(scope.crossOrigin==='use-credentials'){loader.setWithCredentials(true);}\n",
       "loader.load(url,function(data){try{scope.parse(data,resourcePath,function(gltf){onLoad(gltf);scope.manager.itemEnd(url);},_onError);}catch(e){_onError(e);}},onProgress,_onError);},setCrossOrigin:function(value){this.crossOrigin=value;return this;},setPath:function(value){this.path=value;return this;},setResourcePath:function(value){this.resourcePath=value;return this;},setDRACOLoader:function(dracoLoader){this.dracoLoader=dracoLoader;return this;},setDDSLoader:function(ddsLoader){this.ddsLoader=ddsLoader;return this;},parse:function(data,path,onLoad,onError){var content;var extensions={};if(typeof data==='string'){content=data;}else{var magic=THREE.LoaderUtils.decodeText(new Uint8Array(data,0,4));if(magic===BINARY_EXTENSION_HEADER_MAGIC){try{extensions[EXTENSIONS.KHR_BINARY_GLTF]=new GLTFBinaryExtension(data);}catch(error){if(onError)onError(error);return;}\n",
       "content=extensions[EXTENSIONS.KHR_BINARY_GLTF].content;}else{content=THREE.LoaderUtils.decodeText(new Uint8Array(data));}}\n",
       "var json=JSON.parse(content);if(json.asset===undefined||json.asset.version[0]<2){if(onError)onError(new Error('THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported. Use LegacyGLTFLoader instead.'));return;}\n",
       "if(json.extensionsUsed){for(var i=0;i<json.extensionsUsed.length;++i){var extensionName=json.extensionsUsed[i];var extensionsRequired=json.extensionsRequired||[];switch(extensionName){case EXTENSIONS.KHR_LIGHTS_PUNCTUAL:extensions[extensionName]=new GLTFLightsExtension(json);break;case EXTENSIONS.KHR_MATERIALS_UNLIT:extensions[extensionName]=new GLTFMaterialsUnlitExtension();break;case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:extensions[extensionName]=new GLTFMaterialsPbrSpecularGlossinessExtension();break;case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:extensions[extensionName]=new GLTFDracoMeshCompressionExtension(json,this.dracoLoader);break;case EXTENSIONS.MSFT_TEXTURE_DDS:extensions[EXTENSIONS.MSFT_TEXTURE_DDS]=new GLTFTextureDDSExtension(this.ddsLoader);break;case EXTENSIONS.KHR_TEXTURE_TRANSFORM:extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM]=new GLTFTextureTransformExtension();break;default:if(extensionsRequired.indexOf(extensionName)>=0){console.warn('THREE.GLTFLoader: Unknown extension &quot;'+extensionName+'&quot;.');}}}}\n",
       "var parser=new GLTFParser(json,extensions,{path:path||this.resourcePath||'',crossOrigin:this.crossOrigin,manager:this.manager});parser.parse(onLoad,onError);}};function GLTFRegistry(){var objects={};return{get:function(key){return objects[key];},add:function(key,object){objects[key]=object;},remove:function(key){delete objects[key];},removeAll:function(){objects={};}};}\n",
       "var EXTENSIONS={KHR_BINARY_GLTF:'KHR_binary_glTF',KHR_DRACO_MESH_COMPRESSION:'KHR_draco_mesh_compression',KHR_LIGHTS_PUNCTUAL:'KHR_lights_punctual',KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:'KHR_materials_pbrSpecularGlossiness',KHR_MATERIALS_UNLIT:'KHR_materials_unlit',KHR_TEXTURE_TRANSFORM:'KHR_texture_transform',MSFT_TEXTURE_DDS:'MSFT_texture_dds'};function GLTFTextureDDSExtension(ddsLoader){if(!ddsLoader){throw new Error('THREE.GLTFLoader: Attempting to load .dds texture without importing THREE.DDSLoader');}\n",
       "this.name=EXTENSIONS.MSFT_TEXTURE_DDS;this.ddsLoader=ddsLoader;}\n",
       "function GLTFLightsExtension(json){this.name=EXTENSIONS.KHR_LIGHTS_PUNCTUAL;var extension=(json.extensions&&json.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL])||{};this.lightDefs=extension.lights||[];}\n",
       "GLTFLightsExtension.prototype.loadLight=function(lightIndex){var lightDef=this.lightDefs[lightIndex];var lightNode;var color=new THREE.Color(0xffffff);if(lightDef.color!==undefined)color.fromArray(lightDef.color);var range=lightDef.range!==undefined?lightDef.range:0;switch(lightDef.type){case'directional':lightNode=new THREE.DirectionalLight(color);lightNode.target.position.set(0,0,-1);lightNode.add(lightNode.target);break;case'point':lightNode=new THREE.PointLight(color);lightNode.distance=range;break;case'spot':lightNode=new THREE.SpotLight(color);lightNode.distance=range;lightDef.spot=lightDef.spot||{};lightDef.spot.innerConeAngle=lightDef.spot.innerConeAngle!==undefined?lightDef.spot.innerConeAngle:0;lightDef.spot.outerConeAngle=lightDef.spot.outerConeAngle!==undefined?lightDef.spot.outerConeAngle:Math.PI/4.0;lightNode.angle=lightDef.spot.outerConeAngle;lightNode.penumbra=1.0-lightDef.spot.innerConeAngle/lightDef.spot.outerConeAngle;lightNode.target.position.set(0,0,-1);lightNode.add(lightNode.target);break;default:throw new Error('THREE.GLTFLoader: Unexpected light type, &quot;'+lightDef.type+'&quot;.');}\n",
       "lightNode.position.set(0,0,0);lightNode.decay=2;if(lightDef.intensity!==undefined)lightNode.intensity=lightDef.intensity;lightNode.name=lightDef.name||('light_'+lightIndex);return Promise.resolve(lightNode);};function GLTFMaterialsUnlitExtension(){this.name=EXTENSIONS.KHR_MATERIALS_UNLIT;}\n",
       "GLTFMaterialsUnlitExtension.prototype.getMaterialType=function(){return THREE.MeshBasicMaterial;};GLTFMaterialsUnlitExtension.prototype.extendParams=function(materialParams,materialDef,parser){var pending=[];materialParams.color=new THREE.Color(1.0,1.0,1.0);materialParams.opacity=1.0;var metallicRoughness=materialDef.pbrMetallicRoughness;if(metallicRoughness){if(Array.isArray(metallicRoughness.baseColorFactor)){var array=metallicRoughness.baseColorFactor;materialParams.color.fromArray(array);materialParams.opacity=array[3];}\n",
       "if(metallicRoughness.baseColorTexture!==undefined){pending.push(parser.assignTexture(materialParams,'map',metallicRoughness.baseColorTexture));}}\n",
       "return Promise.all(pending);};var BINARY_EXTENSION_HEADER_MAGIC='glTF';var BINARY_EXTENSION_HEADER_LENGTH=12;var BINARY_EXTENSION_CHUNK_TYPES={JSON:0x4E4F534A,BIN:0x004E4942};function GLTFBinaryExtension(data){this.name=EXTENSIONS.KHR_BINARY_GLTF;this.content=null;this.body=null;var headerView=new DataView(data,0,BINARY_EXTENSION_HEADER_LENGTH);this.header={magic:THREE.LoaderUtils.decodeText(new Uint8Array(data.slice(0,4))),version:headerView.getUint32(4,true),length:headerView.getUint32(8,true)};if(this.header.magic!==BINARY_EXTENSION_HEADER_MAGIC){throw new Error('THREE.GLTFLoader: Unsupported glTF-Binary header.');}else if(this.header.version<2.0){throw new Error('THREE.GLTFLoader: Legacy binary file detected. Use LegacyGLTFLoader instead.');}\n",
       "var chunkView=new DataView(data,BINARY_EXTENSION_HEADER_LENGTH);var chunkIndex=0;while(chunkIndex<chunkView.byteLength){var chunkLength=chunkView.getUint32(chunkIndex,true);chunkIndex+=4;var chunkType=chunkView.getUint32(chunkIndex,true);chunkIndex+=4;if(chunkType===BINARY_EXTENSION_CHUNK_TYPES.JSON){var contentArray=new Uint8Array(data,BINARY_EXTENSION_HEADER_LENGTH+chunkIndex,chunkLength);this.content=THREE.LoaderUtils.decodeText(contentArray);}else if(chunkType===BINARY_EXTENSION_CHUNK_TYPES.BIN){var byteOffset=BINARY_EXTENSION_HEADER_LENGTH+chunkIndex;this.body=data.slice(byteOffset,byteOffset+chunkLength);}\n",
       "chunkIndex+=chunkLength;}\n",
       "if(this.content===null){throw new Error('THREE.GLTFLoader: JSON content not found.');}}\n",
       "function GLTFDracoMeshCompressionExtension(json,dracoLoader){if(!dracoLoader){throw new Error('THREE.GLTFLoader: No DRACOLoader instance provided.');}\n",
       "this.name=EXTENSIONS.KHR_DRACO_MESH_COMPRESSION;this.json=json;this.dracoLoader=dracoLoader;}\n",
       "GLTFDracoMeshCompressionExtension.prototype.decodePrimitive=function(primitive,parser){var json=this.json;var dracoLoader=this.dracoLoader;var bufferViewIndex=primitive.extensions[this.name].bufferView;var gltfAttributeMap=primitive.extensions[this.name].attributes;var threeAttributeMap={};var attributeNormalizedMap={};var attributeTypeMap={};for(var attributeName in gltfAttributeMap){var threeAttributeName=ATTRIBUTES[attributeName]||attributeName.toLowerCase();threeAttributeMap[threeAttributeName]=gltfAttributeMap[attributeName];}\n",
       "for(attributeName in primitive.attributes){var threeAttributeName=ATTRIBUTES[attributeName]||attributeName.toLowerCase();if(gltfAttributeMap[attributeName]!==undefined){var accessorDef=json.accessors[primitive.attributes[attributeName]];var componentType=WEBGL_COMPONENT_TYPES[accessorDef.componentType];attributeTypeMap[threeAttributeName]=componentType;attributeNormalizedMap[threeAttributeName]=accessorDef.normalized===true;}}\n",
       "return parser.getDependency('bufferView',bufferViewIndex).then(function(bufferView){return new Promise(function(resolve){dracoLoader.decodeDracoFile(bufferView,function(geometry){for(var attributeName in geometry.attributes){var attribute=geometry.attributes[attributeName];var normalized=attributeNormalizedMap[attributeName];if(normalized!==undefined)attribute.normalized=normalized;}\n",
       "resolve(geometry);},threeAttributeMap,attributeTypeMap);});});};function GLTFTextureTransformExtension(){this.name=EXTENSIONS.KHR_TEXTURE_TRANSFORM;}\n",
       "GLTFTextureTransformExtension.prototype.extendTexture=function(texture,transform){texture=texture.clone();if(transform.offset!==undefined){texture.offset.fromArray(transform.offset);}\n",
       "if(transform.rotation!==undefined){texture.rotation=transform.rotation;}\n",
       "if(transform.scale!==undefined){texture.repeat.fromArray(transform.scale);}\n",
       "if(transform.texCoord!==undefined){console.warn('THREE.GLTFLoader: Custom UV sets in &quot;'+this.name+'&quot; extension not yet supported.');}\n",
       "texture.needsUpdate=true;return texture;};function GLTFMaterialsPbrSpecularGlossinessExtension(){return{name:EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS,specularGlossinessParams:['color','map','lightMap','lightMapIntensity','aoMap','aoMapIntensity','emissive','emissiveIntensity','emissiveMap','bumpMap','bumpScale','normalMap','displacementMap','displacementScale','displacementBias','specularMap','specular','glossinessMap','glossiness','alphaMap','envMap','envMapIntensity','refractionRatio',],getMaterialType:function(){return THREE.ShaderMaterial;},extendParams:function(materialParams,materialDef,parser){var pbrSpecularGlossiness=materialDef.extensions[this.name];var shader=THREE.ShaderLib['standard'];var uniforms=THREE.UniformsUtils.clone(shader.uniforms);var specularMapParsFragmentChunk=['#ifdef USE_SPECULARMAP','\tuniform sampler2D specularMap;','#endif'].join('\\n');var glossinessMapParsFragmentChunk=['#ifdef USE_GLOSSINESSMAP','\tuniform sampler2D glossinessMap;','#endif'].join('\\n');var specularMapFragmentChunk=['vec3 specularFactor = specular;','#ifdef USE_SPECULARMAP','\tvec4 texelSpecular = texture2D( specularMap, vUv );','\ttexelSpecular = sRGBToLinear( texelSpecular );','\t// reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture','\tspecularFactor *= texelSpecular.rgb;','#endif'].join('\\n');var glossinessMapFragmentChunk=['float glossinessFactor = glossiness;','#ifdef USE_GLOSSINESSMAP','\tvec4 texelGlossiness = texture2D( glossinessMap, vUv );','\t// reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture','\tglossinessFactor *= texelGlossiness.a;','#endif'].join('\\n');var lightPhysicalFragmentChunk=['PhysicalMaterial material;','material.diffuseColor = diffuseColor.rgb;','material.specularRoughness = clamp( 1.0 - glossinessFactor, 0.04, 1.0 );','material.specularColor = specularFactor.rgb;',].join('\\n');var fragmentShader=shader.fragmentShader.replace('uniform float roughness;','uniform vec3 specular;').replace('uniform float metalness;','uniform float glossiness;').replace('#include <roughnessmap_pars_fragment>',specularMapParsFragmentChunk).replace('#include <metalnessmap_pars_fragment>',glossinessMapParsFragmentChunk).replace('#include <roughnessmap_fragment>',specularMapFragmentChunk).replace('#include <metalnessmap_fragment>',glossinessMapFragmentChunk).replace('#include <lights_physical_fragment>',lightPhysicalFragmentChunk);delete uniforms.roughness;delete uniforms.metalness;delete uniforms.roughnessMap;delete uniforms.metalnessMap;uniforms.specular={value:new THREE.Color().setHex(0x111111)};uniforms.glossiness={value:0.5};uniforms.specularMap={value:null};uniforms.glossinessMap={value:null};materialParams.vertexShader=shader.vertexShader;materialParams.fragmentShader=fragmentShader;materialParams.uniforms=uniforms;materialParams.defines={'STANDARD':''};materialParams.color=new THREE.Color(1.0,1.0,1.0);materialParams.opacity=1.0;var pending=[];if(Array.isArray(pbrSpecularGlossiness.diffuseFactor)){var array=pbrSpecularGlossiness.diffuseFactor;materialParams.color.fromArray(array);materialParams.opacity=array[3];}\n",
       "if(pbrSpecularGlossiness.diffuseTexture!==undefined){pending.push(parser.assignTexture(materialParams,'map',pbrSpecularGlossiness.diffuseTexture));}\n",
       "materialParams.emissive=new THREE.Color(0.0,0.0,0.0);materialParams.glossiness=pbrSpecularGlossiness.glossinessFactor!==undefined?pbrSpecularGlossiness.glossinessFactor:1.0;materialParams.specular=new THREE.Color(1.0,1.0,1.0);if(Array.isArray(pbrSpecularGlossiness.specularFactor)){materialParams.specular.fromArray(pbrSpecularGlossiness.specularFactor);}\n",
       "if(pbrSpecularGlossiness.specularGlossinessTexture!==undefined){var specGlossMapDef=pbrSpecularGlossiness.specularGlossinessTexture;pending.push(parser.assignTexture(materialParams,'glossinessMap',specGlossMapDef));pending.push(parser.assignTexture(materialParams,'specularMap',specGlossMapDef));}\n",
       "return Promise.all(pending);},createMaterial:function(params){var material=new THREE.ShaderMaterial({defines:params.defines,vertexShader:params.vertexShader,fragmentShader:params.fragmentShader,uniforms:params.uniforms,fog:true,lights:true,opacity:params.opacity,transparent:params.transparent});material.isGLTFSpecularGlossinessMaterial=true;material.color=params.color;material.map=params.map===undefined?null:params.map;material.lightMap=null;material.lightMapIntensity=1.0;material.aoMap=params.aoMap===undefined?null:params.aoMap;material.aoMapIntensity=1.0;material.emissive=params.emissive;material.emissiveIntensity=1.0;material.emissiveMap=params.emissiveMap===undefined?null:params.emissiveMap;material.bumpMap=params.bumpMap===undefined?null:params.bumpMap;material.bumpScale=1;material.normalMap=params.normalMap===undefined?null:params.normalMap;if(params.normalScale)material.normalScale=params.normalScale;material.displacementMap=null;material.displacementScale=1;material.displacementBias=0;material.specularMap=params.specularMap===undefined?null:params.specularMap;material.specular=params.specular;material.glossinessMap=params.glossinessMap===undefined?null:params.glossinessMap;material.glossiness=params.glossiness;material.alphaMap=null;material.envMap=params.envMap===undefined?null:params.envMap;material.envMapIntensity=1.0;material.refractionRatio=0.98;material.extensions.derivatives=true;return material;},cloneMaterial:function(source){var target=source.clone();target.isGLTFSpecularGlossinessMaterial=true;var params=this.specularGlossinessParams;for(var i=0,il=params.length;i<il;i++){var value=source[params[i]];target[params[i]]=(value&&value.isColor)?value.clone():value;}\n",
       "return target;},refreshUniforms:function(renderer,scene,camera,geometry,material){if(material.isGLTFSpecularGlossinessMaterial!==true){return;}\n",
       "var uniforms=material.uniforms;var defines=material.defines;uniforms.opacity.value=material.opacity;uniforms.diffuse.value.copy(material.color);uniforms.emissive.value.copy(material.emissive).multiplyScalar(material.emissiveIntensity);uniforms.map.value=material.map;uniforms.specularMap.value=material.specularMap;uniforms.alphaMap.value=material.alphaMap;uniforms.lightMap.value=material.lightMap;uniforms.lightMapIntensity.value=material.lightMapIntensity;uniforms.aoMap.value=material.aoMap;uniforms.aoMapIntensity.value=material.aoMapIntensity;var uvScaleMap;if(material.map){uvScaleMap=material.map;}else if(material.specularMap){uvScaleMap=material.specularMap;}else if(material.displacementMap){uvScaleMap=material.displacementMap;}else if(material.normalMap){uvScaleMap=material.normalMap;}else if(material.bumpMap){uvScaleMap=material.bumpMap;}else if(material.glossinessMap){uvScaleMap=material.glossinessMap;}else if(material.alphaMap){uvScaleMap=material.alphaMap;}else if(material.emissiveMap){uvScaleMap=material.emissiveMap;}\n",
       "if(uvScaleMap!==undefined){if(uvScaleMap.isWebGLRenderTarget){uvScaleMap=uvScaleMap.texture;}\n",
       "if(uvScaleMap.matrixAutoUpdate===true){uvScaleMap.updateMatrix();}\n",
       "uniforms.uvTransform.value.copy(uvScaleMap.matrix);}\n",
       "if(material.envMap){uniforms.envMap.value=material.envMap;uniforms.envMapIntensity.value=material.envMapIntensity;uniforms.flipEnvMap.value=material.envMap.isCubeTexture?-1:1;uniforms.reflectivity.value=material.reflectivity;uniforms.refractionRatio.value=material.refractionRatio;uniforms.maxMipLevel.value=renderer.properties.get(material.envMap).__maxMipLevel;}\n",
       "uniforms.specular.value.copy(material.specular);uniforms.glossiness.value=material.glossiness;uniforms.glossinessMap.value=material.glossinessMap;uniforms.emissiveMap.value=material.emissiveMap;uniforms.bumpMap.value=material.bumpMap;uniforms.normalMap.value=material.normalMap;uniforms.displacementMap.value=material.displacementMap;uniforms.displacementScale.value=material.displacementScale;uniforms.displacementBias.value=material.displacementBias;if(uniforms.glossinessMap.value!==null&&defines.USE_GLOSSINESSMAP===undefined){defines.USE_GLOSSINESSMAP='';defines.USE_ROUGHNESSMAP='';}\n",
       "if(uniforms.glossinessMap.value===null&&defines.USE_GLOSSINESSMAP!==undefined){delete defines.USE_GLOSSINESSMAP;delete defines.USE_ROUGHNESSMAP;}}};}\n",
       "function GLTFCubicSplineInterpolant(parameterPositions,sampleValues,sampleSize,resultBuffer){THREE.Interpolant.call(this,parameterPositions,sampleValues,sampleSize,resultBuffer);}\n",
       "GLTFCubicSplineInterpolant.prototype=Object.create(THREE.Interpolant.prototype);GLTFCubicSplineInterpolant.prototype.constructor=GLTFCubicSplineInterpolant;GLTFCubicSplineInterpolant.prototype.copySampleValue_=function(index){var result=this.resultBuffer,values=this.sampleValues,valueSize=this.valueSize,offset=index*valueSize*3+valueSize;for(var i=0;i!==valueSize;i++){result[i]=values[offset+i];}\n",
       "return result;};GLTFCubicSplineInterpolant.prototype.beforeStart_=GLTFCubicSplineInterpolant.prototype.copySampleValue_;GLTFCubicSplineInterpolant.prototype.afterEnd_=GLTFCubicSplineInterpolant.prototype.copySampleValue_;GLTFCubicSplineInterpolant.prototype.interpolate_=function(i1,t0,t,t1){var result=this.resultBuffer;var values=this.sampleValues;var stride=this.valueSize;var stride2=stride*2;var stride3=stride*3;var td=t1-t0;var p=(t-t0)/td;var pp=p*p;var ppp=pp*p;var offset1=i1*stride3;var offset0=offset1-stride3;var s2=-2*ppp+3*pp;var s3=ppp-pp;var s0=1-s2;var s1=s3-pp+p;for(var i=0;i!==stride;i++){var p0=values[offset0+i+stride];var m0=values[offset0+i+stride2]*td;var p1=values[offset1+i+stride];var m1=values[offset1+i]*td;result[i]=s0*p0+s1*m0+s2*p1+s3*m1;}\n",
       "return result;};var WEBGL_CONSTANTS={FLOAT:5126,FLOAT_MAT3:35675,FLOAT_MAT4:35676,FLOAT_VEC2:35664,FLOAT_VEC3:35665,FLOAT_VEC4:35666,LINEAR:9729,REPEAT:10497,SAMPLER_2D:35678,POINTS:0,LINES:1,LINE_LOOP:2,LINE_STRIP:3,TRIANGLES:4,TRIANGLE_STRIP:5,TRIANGLE_FAN:6,UNSIGNED_BYTE:5121,UNSIGNED_SHORT:5123};var WEBGL_COMPONENT_TYPES={5120:Int8Array,5121:Uint8Array,5122:Int16Array,5123:Uint16Array,5125:Uint32Array,5126:Float32Array};var WEBGL_FILTERS={9728:THREE.NearestFilter,9729:THREE.LinearFilter,9984:THREE.NearestMipMapNearestFilter,9985:THREE.LinearMipMapNearestFilter,9986:THREE.NearestMipMapLinearFilter,9987:THREE.LinearMipMapLinearFilter};var WEBGL_WRAPPINGS={33071:THREE.ClampToEdgeWrapping,33648:THREE.MirroredRepeatWrapping,10497:THREE.RepeatWrapping};var WEBGL_TYPE_SIZES={'SCALAR':1,'VEC2':2,'VEC3':3,'VEC4':4,'MAT2':4,'MAT3':9,'MAT4':16};var ATTRIBUTES={POSITION:'position',NORMAL:'normal',TANGENT:'tangent',TEXCOORD_0:'uv',TEXCOORD_1:'uv2',COLOR_0:'color',WEIGHTS_0:'skinWeight',JOINTS_0:'skinIndex',};var PATH_PROPERTIES={scale:'scale',translation:'position',rotation:'quaternion',weights:'morphTargetInfluences'};var INTERPOLATION={CUBICSPLINE:undefined,LINEAR:THREE.InterpolateLinear,STEP:THREE.InterpolateDiscrete};var ALPHA_MODES={OPAQUE:'OPAQUE',MASK:'MASK',BLEND:'BLEND'};var MIME_TYPE_FORMATS={'image/png':THREE.RGBAFormat,'image/jpeg':THREE.RGBFormat};function resolveURL(url,path){if(typeof url!=='string'||url==='')return'';if(/^(https?:)?\\/\\//i.test(url))return url;if(/^data:.*,.*$/i.test(url))return url;if(/^blob:.*$/i.test(url))return url;return path+url;}\n",
       "var defaultMaterial;function createDefaultMaterial(){defaultMaterial=defaultMaterial||new THREE.MeshStandardMaterial({color:0xFFFFFF,emissive:0x000000,metalness:1,roughness:1,transparent:false,depthTest:true,side:THREE.FrontSide});return defaultMaterial;}\n",
       "function addUnknownExtensionsToUserData(knownExtensions,object,objectDef){for(var name in objectDef.extensions){if(knownExtensions[name]===undefined){object.userData.gltfExtensions=object.userData.gltfExtensions||{};object.userData.gltfExtensions[name]=objectDef.extensions[name];}}}\n",
       "function assignExtrasToUserData(object,gltfDef){if(gltfDef.extras!==undefined){if(typeof gltfDef.extras==='object'){Object.assign(object.userData,gltfDef.extras);}else{console.warn('THREE.GLTFLoader: Ignoring primitive type .extras, '+gltfDef.extras);}}}\n",
       "function addMorphTargets(geometry,targets,parser){var hasMorphPosition=false;var hasMorphNormal=false;for(var i=0,il=targets.length;i<il;i++){var target=targets[i];if(target.POSITION!==undefined)hasMorphPosition=true;if(target.NORMAL!==undefined)hasMorphNormal=true;if(hasMorphPosition&&hasMorphNormal)break;}\n",
       "if(!hasMorphPosition&&!hasMorphNormal)return Promise.resolve(geometry);var pendingPositionAccessors=[];var pendingNormalAccessors=[];for(var i=0,il=targets.length;i<il;i++){var target=targets[i];if(hasMorphPosition){var pendingAccessor=target.POSITION!==undefined?parser.getDependency('accessor',target.POSITION):geometry.attributes.position;pendingPositionAccessors.push(pendingAccessor);}\n",
       "if(hasMorphNormal){var pendingAccessor=target.NORMAL!==undefined?parser.getDependency('accessor',target.NORMAL):geometry.attributes.normal;pendingNormalAccessors.push(pendingAccessor);}}\n",
       "return Promise.all([Promise.all(pendingPositionAccessors),Promise.all(pendingNormalAccessors)]).then(function(accessors){var morphPositions=accessors[0];var morphNormals=accessors[1];for(var i=0,il=morphPositions.length;i<il;i++){if(geometry.attributes.position===morphPositions[i])continue;morphPositions[i]=cloneBufferAttribute(morphPositions[i]);}\n",
       "for(var i=0,il=morphNormals.length;i<il;i++){if(geometry.attributes.normal===morphNormals[i])continue;morphNormals[i]=cloneBufferAttribute(morphNormals[i]);}\n",
       "for(var i=0,il=targets.length;i<il;i++){var target=targets[i];var attributeName='morphTarget'+i;if(hasMorphPosition){if(target.POSITION!==undefined){var positionAttribute=morphPositions[i];positionAttribute.name=attributeName;var position=geometry.attributes.position;for(var j=0,jl=positionAttribute.count;j<jl;j++){positionAttribute.setXYZ(j,positionAttribute.getX(j)+position.getX(j),positionAttribute.getY(j)+position.getY(j),positionAttribute.getZ(j)+position.getZ(j));}}}\n",
       "if(hasMorphNormal){if(target.NORMAL!==undefined){var normalAttribute=morphNormals[i];normalAttribute.name=attributeName;var normal=geometry.attributes.normal;for(var j=0,jl=normalAttribute.count;j<jl;j++){normalAttribute.setXYZ(j,normalAttribute.getX(j)+normal.getX(j),normalAttribute.getY(j)+normal.getY(j),normalAttribute.getZ(j)+normal.getZ(j));}}}}\n",
       "if(hasMorphPosition)geometry.morphAttributes.position=morphPositions;if(hasMorphNormal)geometry.morphAttributes.normal=morphNormals;return geometry;});}\n",
       "function updateMorphTargets(mesh,meshDef){mesh.updateMorphTargets();if(meshDef.weights!==undefined){for(var i=0,il=meshDef.weights.length;i<il;i++){mesh.morphTargetInfluences[i]=meshDef.weights[i];}}\n",
       "if(meshDef.extras&&Array.isArray(meshDef.extras.targetNames)){var targetNames=meshDef.extras.targetNames;if(mesh.morphTargetInfluences.length===targetNames.length){mesh.morphTargetDictionary={};for(var i=0,il=targetNames.length;i<il;i++){mesh.morphTargetDictionary[targetNames[i]]=i;}}else{console.warn('THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.');}}}\n",
       "function createPrimitiveKey(primitiveDef){var dracoExtension=primitiveDef.extensions&&primitiveDef.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION];var geometryKey;if(dracoExtension){geometryKey='draco:'+dracoExtension.bufferView\n",
       "+':'+dracoExtension.indices\n",
       "+':'+createAttributesKey(dracoExtension.attributes);}else{geometryKey=primitiveDef.indices+':'+createAttributesKey(primitiveDef.attributes)+':'+primitiveDef.mode;}\n",
       "return geometryKey;}\n",
       "function createAttributesKey(attributes){var attributesKey='';var keys=Object.keys(attributes).sort();for(var i=0,il=keys.length;i<il;i++){attributesKey+=keys[i]+':'+attributes[keys[i]]+';';}\n",
       "return attributesKey;}\n",
       "function cloneBufferAttribute(attribute){if(attribute.isInterleavedBufferAttribute){var count=attribute.count;var itemSize=attribute.itemSize;var array=attribute.array.slice(0,count*itemSize);for(var i=0,j=0;i<count;++i){array[j++]=attribute.getX(i);if(itemSize>=2)array[j++]=attribute.getY(i);if(itemSize>=3)array[j++]=attribute.getZ(i);if(itemSize>=4)array[j++]=attribute.getW(i);}\n",
       "return new THREE.BufferAttribute(array,itemSize,attribute.normalized);}\n",
       "return attribute.clone();}\n",
       "function GLTFParser(json,extensions,options){this.json=json||{};this.extensions=extensions||{};this.options=options||{};this.cache=new GLTFRegistry();this.primitiveCache={};this.textureLoader=new THREE.TextureLoader(this.options.manager);this.textureLoader.setCrossOrigin(this.options.crossOrigin);this.fileLoader=new THREE.FileLoader(this.options.manager);this.fileLoader.setResponseType('arraybuffer');if(this.options.crossOrigin==='use-credentials'){this.fileLoader.setWithCredentials(true);}}\n",
       "GLTFParser.prototype.parse=function(onLoad,onError){var parser=this;var json=this.json;var extensions=this.extensions;this.cache.removeAll();this.markDefs();Promise.all([this.getDependencies('scene'),this.getDependencies('animation'),this.getDependencies('camera'),]).then(function(dependencies){var result={scene:dependencies[0][json.scene||0],scenes:dependencies[0],animations:dependencies[1],cameras:dependencies[2],asset:json.asset,parser:parser,userData:{}};addUnknownExtensionsToUserData(extensions,result,json);assignExtrasToUserData(result,json);onLoad(result);}).catch(onError);};GLTFParser.prototype.markDefs=function(){var nodeDefs=this.json.nodes||[];var skinDefs=this.json.skins||[];var meshDefs=this.json.meshes||[];var meshReferences={};var meshUses={};for(var skinIndex=0,skinLength=skinDefs.length;skinIndex<skinLength;skinIndex++){var joints=skinDefs[skinIndex].joints;for(var i=0,il=joints.length;i<il;i++){nodeDefs[joints[i]].isBone=true;}}\n",
       "for(var nodeIndex=0,nodeLength=nodeDefs.length;nodeIndex<nodeLength;nodeIndex++){var nodeDef=nodeDefs[nodeIndex];if(nodeDef.mesh!==undefined){if(meshReferences[nodeDef.mesh]===undefined){meshReferences[nodeDef.mesh]=meshUses[nodeDef.mesh]=0;}\n",
       "meshReferences[nodeDef.mesh]++;if(nodeDef.skin!==undefined){meshDefs[nodeDef.mesh].isSkinnedMesh=true;}}}\n",
       "this.json.meshReferences=meshReferences;this.json.meshUses=meshUses;};GLTFParser.prototype.getDependency=function(type,index){var cacheKey=type+':'+index;var dependency=this.cache.get(cacheKey);if(!dependency){switch(type){case'scene':dependency=this.loadScene(index);break;case'node':dependency=this.loadNode(index);break;case'mesh':dependency=this.loadMesh(index);break;case'accessor':dependency=this.loadAccessor(index);break;case'bufferView':dependency=this.loadBufferView(index);break;case'buffer':dependency=this.loadBuffer(index);break;case'material':dependency=this.loadMaterial(index);break;case'texture':dependency=this.loadTexture(index);break;case'skin':dependency=this.loadSkin(index);break;case'animation':dependency=this.loadAnimation(index);break;case'camera':dependency=this.loadCamera(index);break;case'light':dependency=this.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].loadLight(index);break;default:throw new Error('Unknown type: '+type);}\n",
       "this.cache.add(cacheKey,dependency);}\n",
       "return dependency;};GLTFParser.prototype.getDependencies=function(type){var dependencies=this.cache.get(type);if(!dependencies){var parser=this;var defs=this.json[type+(type==='mesh'?'es':'s')]||[];dependencies=Promise.all(defs.map(function(def,index){return parser.getDependency(type,index);}));this.cache.add(type,dependencies);}\n",
       "return dependencies;};GLTFParser.prototype.loadBuffer=function(bufferIndex){var bufferDef=this.json.buffers[bufferIndex];var loader=this.fileLoader;if(bufferDef.type&&bufferDef.type!=='arraybuffer'){throw new Error('THREE.GLTFLoader: '+bufferDef.type+' buffer type is not supported.');}\n",
       "if(bufferDef.uri===undefined&&bufferIndex===0){return Promise.resolve(this.extensions[EXTENSIONS.KHR_BINARY_GLTF].body);}\n",
       "var options=this.options;return new Promise(function(resolve,reject){loader.load(resolveURL(bufferDef.uri,options.path),resolve,undefined,function(){reject(new Error('THREE.GLTFLoader: Failed to load buffer &quot;'+bufferDef.uri+'&quot;.'));});});};GLTFParser.prototype.loadBufferView=function(bufferViewIndex){var bufferViewDef=this.json.bufferViews[bufferViewIndex];return this.getDependency('buffer',bufferViewDef.buffer).then(function(buffer){var byteLength=bufferViewDef.byteLength||0;var byteOffset=bufferViewDef.byteOffset||0;return buffer.slice(byteOffset,byteOffset+byteLength);});};GLTFParser.prototype.loadAccessor=function(accessorIndex){var parser=this;var json=this.json;var accessorDef=this.json.accessors[accessorIndex];if(accessorDef.bufferView===undefined&&accessorDef.sparse===undefined){return Promise.resolve(null);}\n",
       "var pendingBufferViews=[];if(accessorDef.bufferView!==undefined){pendingBufferViews.push(this.getDependency('bufferView',accessorDef.bufferView));}else{pendingBufferViews.push(null);}\n",
       "if(accessorDef.sparse!==undefined){pendingBufferViews.push(this.getDependency('bufferView',accessorDef.sparse.indices.bufferView));pendingBufferViews.push(this.getDependency('bufferView',accessorDef.sparse.values.bufferView));}\n",
       "return Promise.all(pendingBufferViews).then(function(bufferViews){var bufferView=bufferViews[0];var itemSize=WEBGL_TYPE_SIZES[accessorDef.type];var TypedArray=WEBGL_COMPONENT_TYPES[accessorDef.componentType];var elementBytes=TypedArray.BYTES_PER_ELEMENT;var itemBytes=elementBytes*itemSize;var byteOffset=accessorDef.byteOffset||0;var byteStride=accessorDef.bufferView!==undefined?json.bufferViews[accessorDef.bufferView].byteStride:undefined;var normalized=accessorDef.normalized===true;var array,bufferAttribute;if(byteStride&&byteStride!==itemBytes){var ibCacheKey='InterleavedBuffer:'+accessorDef.bufferView+':'+accessorDef.componentType;var ib=parser.cache.get(ibCacheKey);if(!ib){array=new TypedArray(bufferView);ib=new THREE.InterleavedBuffer(array,byteStride/elementBytes);parser.cache.add(ibCacheKey,ib);}\n",
       "bufferAttribute=new THREE.InterleavedBufferAttribute(ib,itemSize,byteOffset/elementBytes,normalized);}else{if(bufferView===null){array=new TypedArray(accessorDef.count*itemSize);}else{array=new TypedArray(bufferView,byteOffset,accessorDef.count*itemSize);}\n",
       "bufferAttribute=new THREE.BufferAttribute(array,itemSize,normalized);}\n",
       "if(accessorDef.sparse!==undefined){var itemSizeIndices=WEBGL_TYPE_SIZES.SCALAR;var TypedArrayIndices=WEBGL_COMPONENT_TYPES[accessorDef.sparse.indices.componentType];var byteOffsetIndices=accessorDef.sparse.indices.byteOffset||0;var byteOffsetValues=accessorDef.sparse.values.byteOffset||0;var sparseIndices=new TypedArrayIndices(bufferViews[1],byteOffsetIndices,accessorDef.sparse.count*itemSizeIndices);var sparseValues=new TypedArray(bufferViews[2],byteOffsetValues,accessorDef.sparse.count*itemSize);if(bufferView!==null){bufferAttribute.setArray(bufferAttribute.array.slice());}\n",
       "for(var i=0,il=sparseIndices.length;i<il;i++){var index=sparseIndices[i];bufferAttribute.setX(index,sparseValues[i*itemSize]);if(itemSize>=2)bufferAttribute.setY(index,sparseValues[i*itemSize+1]);if(itemSize>=3)bufferAttribute.setZ(index,sparseValues[i*itemSize+2]);if(itemSize>=4)bufferAttribute.setW(index,sparseValues[i*itemSize+3]);if(itemSize>=5)throw new Error('THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.');}}\n",
       "return bufferAttribute;});};GLTFParser.prototype.loadTexture=function(textureIndex){var parser=this;var json=this.json;var options=this.options;var textureLoader=this.textureLoader;var URL=window.URL||window.webkitURL;var textureDef=json.textures[textureIndex];var textureExtensions=textureDef.extensions||{};var source;if(textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS]){source=json.images[textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS].source];}else{source=json.images[textureDef.source];}\n",
       "var sourceURI=source.uri;var isObjectURL=false;if(source.bufferView!==undefined){sourceURI=parser.getDependency('bufferView',source.bufferView).then(function(bufferView){isObjectURL=true;var blob=new Blob([bufferView],{type:source.mimeType});sourceURI=URL.createObjectURL(blob);return sourceURI;});}\n",
       "return Promise.resolve(sourceURI).then(function(sourceURI){var loader=THREE.Loader.Handlers.get(sourceURI);if(!loader){loader=textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS]?parser.extensions[EXTENSIONS.MSFT_TEXTURE_DDS].ddsLoader:textureLoader;}\n",
       "return new Promise(function(resolve,reject){loader.load(resolveURL(sourceURI,options.path),resolve,undefined,reject);});}).then(function(texture){if(isObjectURL===true){URL.revokeObjectURL(sourceURI);}\n",
       "texture.flipY=false;if(textureDef.name!==undefined)texture.name=textureDef.name;if(source.mimeType in MIME_TYPE_FORMATS){texture.format=MIME_TYPE_FORMATS[source.mimeType];}\n",
       "var samplers=json.samplers||{};var sampler=samplers[textureDef.sampler]||{};texture.magFilter=WEBGL_FILTERS[sampler.magFilter]||THREE.LinearFilter;texture.minFilter=WEBGL_FILTERS[sampler.minFilter]||THREE.LinearMipMapLinearFilter;texture.wrapS=WEBGL_WRAPPINGS[sampler.wrapS]||THREE.RepeatWrapping;texture.wrapT=WEBGL_WRAPPINGS[sampler.wrapT]||THREE.RepeatWrapping;return texture;});};GLTFParser.prototype.assignTexture=function(materialParams,mapName,mapDef){var parser=this;return this.getDependency('texture',mapDef.index).then(function(texture){if(!texture.isCompressedTexture){switch(mapName){case'aoMap':case'emissiveMap':case'metalnessMap':case'normalMap':case'roughnessMap':texture.format=THREE.RGBFormat;break;}}\n",
       "if(parser.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM]){var transform=mapDef.extensions!==undefined?mapDef.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM]:undefined;if(transform){texture=parser.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM].extendTexture(texture,transform);}}\n",
       "materialParams[mapName]=texture;});};GLTFParser.prototype.assignFinalMaterial=function(mesh){var geometry=mesh.geometry;var material=mesh.material;var extensions=this.extensions;var useVertexTangents=geometry.attributes.tangent!==undefined;var useVertexColors=geometry.attributes.color!==undefined;var useFlatShading=geometry.attributes.normal===undefined;var useSkinning=mesh.isSkinnedMesh===true;var useMorphTargets=Object.keys(geometry.morphAttributes).length>0;var useMorphNormals=useMorphTargets&&geometry.morphAttributes.normal!==undefined;if(mesh.isPoints){var cacheKey='PointsMaterial:'+material.uuid;var pointsMaterial=this.cache.get(cacheKey);if(!pointsMaterial){pointsMaterial=new THREE.PointsMaterial();THREE.Material.prototype.copy.call(pointsMaterial,material);pointsMaterial.color.copy(material.color);pointsMaterial.map=material.map;pointsMaterial.lights=false;this.cache.add(cacheKey,pointsMaterial);}\n",
       "material=pointsMaterial;}else if(mesh.isLine){var cacheKey='LineBasicMaterial:'+material.uuid;var lineMaterial=this.cache.get(cacheKey);if(!lineMaterial){lineMaterial=new THREE.LineBasicMaterial();THREE.Material.prototype.copy.call(lineMaterial,material);lineMaterial.color.copy(material.color);lineMaterial.lights=false;this.cache.add(cacheKey,lineMaterial);}\n",
       "material=lineMaterial;}\n",
       "if(useVertexTangents||useVertexColors||useFlatShading||useSkinning||useMorphTargets){var cacheKey='ClonedMaterial:'+material.uuid+':';if(material.isGLTFSpecularGlossinessMaterial)cacheKey+='specular-glossiness:';if(useSkinning)cacheKey+='skinning:';if(useVertexTangents)cacheKey+='vertex-tangents:';if(useVertexColors)cacheKey+='vertex-colors:';if(useFlatShading)cacheKey+='flat-shading:';if(useMorphTargets)cacheKey+='morph-targets:';if(useMorphNormals)cacheKey+='morph-normals:';var cachedMaterial=this.cache.get(cacheKey);if(!cachedMaterial){cachedMaterial=material.isGLTFSpecularGlossinessMaterial?extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].cloneMaterial(material):material.clone();if(useSkinning)cachedMaterial.skinning=true;if(useVertexTangents)cachedMaterial.vertexTangents=true;if(useVertexColors)cachedMaterial.vertexColors=THREE.VertexColors;if(useFlatShading)cachedMaterial.flatShading=true;if(useMorphTargets)cachedMaterial.morphTargets=true;if(useMorphNormals)cachedMaterial.morphNormals=true;this.cache.add(cacheKey,cachedMaterial);}\n",
       "material=cachedMaterial;}\n",
       "if(material.aoMap&&geometry.attributes.uv2===undefined&&geometry.attributes.uv!==undefined){console.log('THREE.GLTFLoader: Duplicating UVs to support aoMap.');geometry.addAttribute('uv2',new THREE.BufferAttribute(geometry.attributes.uv.array,2));}\n",
       "if(material.isGLTFSpecularGlossinessMaterial){mesh.onBeforeRender=extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].refreshUniforms;}\n",
       "mesh.material=material;};GLTFParser.prototype.loadMaterial=function(materialIndex){var parser=this;var json=this.json;var extensions=this.extensions;var materialDef=json.materials[materialIndex];var materialType;var materialParams={};var materialExtensions=materialDef.extensions||{};var pending=[];if(materialExtensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS]){var sgExtension=extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS];materialType=sgExtension.getMaterialType();pending.push(sgExtension.extendParams(materialParams,materialDef,parser));}else if(materialExtensions[EXTENSIONS.KHR_MATERIALS_UNLIT]){var kmuExtension=extensions[EXTENSIONS.KHR_MATERIALS_UNLIT];materialType=kmuExtension.getMaterialType();pending.push(kmuExtension.extendParams(materialParams,materialDef,parser));}else{materialType=THREE.MeshStandardMaterial;var metallicRoughness=materialDef.pbrMetallicRoughness||{};materialParams.color=new THREE.Color(1.0,1.0,1.0);materialParams.opacity=1.0;if(Array.isArray(metallicRoughness.baseColorFactor)){var array=metallicRoughness.baseColorFactor;materialParams.color.fromArray(array);materialParams.opacity=array[3];}\n",
       "if(metallicRoughness.baseColorTexture!==undefined){pending.push(parser.assignTexture(materialParams,'map',metallicRoughness.baseColorTexture));}\n",
       "materialParams.metalness=metallicRoughness.metallicFactor!==undefined?metallicRoughness.metallicFactor:1.0;materialParams.roughness=metallicRoughness.roughnessFactor!==undefined?metallicRoughness.roughnessFactor:1.0;if(metallicRoughness.metallicRoughnessTexture!==undefined){pending.push(parser.assignTexture(materialParams,'metalnessMap',metallicRoughness.metallicRoughnessTexture));pending.push(parser.assignTexture(materialParams,'roughnessMap',metallicRoughness.metallicRoughnessTexture));}}\n",
       "if(materialDef.doubleSided===true){materialParams.side=THREE.DoubleSide;}\n",
       "var alphaMode=materialDef.alphaMode||ALPHA_MODES.OPAQUE;if(alphaMode===ALPHA_MODES.BLEND){materialParams.transparent=true;}else{materialParams.transparent=false;if(alphaMode===ALPHA_MODES.MASK){materialParams.alphaTest=materialDef.alphaCutoff!==undefined?materialDef.alphaCutoff:0.5;}}\n",
       "if(materialDef.normalTexture!==undefined&&materialType!==THREE.MeshBasicMaterial){pending.push(parser.assignTexture(materialParams,'normalMap',materialDef.normalTexture));materialParams.normalScale=new THREE.Vector2(1,1);if(materialDef.normalTexture.scale!==undefined){materialParams.normalScale.set(materialDef.normalTexture.scale,materialDef.normalTexture.scale);}}\n",
       "if(materialDef.occlusionTexture!==undefined&&materialType!==THREE.MeshBasicMaterial){pending.push(parser.assignTexture(materialParams,'aoMap',materialDef.occlusionTexture));if(materialDef.occlusionTexture.strength!==undefined){materialParams.aoMapIntensity=materialDef.occlusionTexture.strength;}}\n",
       "if(materialDef.emissiveFactor!==undefined&&materialType!==THREE.MeshBasicMaterial){materialParams.emissive=new THREE.Color().fromArray(materialDef.emissiveFactor);}\n",
       "if(materialDef.emissiveTexture!==undefined&&materialType!==THREE.MeshBasicMaterial){pending.push(parser.assignTexture(materialParams,'emissiveMap',materialDef.emissiveTexture));}\n",
       "return Promise.all(pending).then(function(){var material;if(materialType===THREE.ShaderMaterial){material=extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].createMaterial(materialParams);}else{material=new materialType(materialParams);}\n",
       "if(materialDef.name!==undefined)material.name=materialDef.name;if(material.map)material.map.encoding=THREE.sRGBEncoding;if(material.emissiveMap)material.emissiveMap.encoding=THREE.sRGBEncoding;if(material.specularMap)material.specularMap.encoding=THREE.sRGBEncoding;assignExtrasToUserData(material,materialDef);if(materialDef.extensions)addUnknownExtensionsToUserData(extensions,material,materialDef);return material;});};function addPrimitiveAttributes(geometry,primitiveDef,parser){var attributes=primitiveDef.attributes;var pending=[];function assignAttributeAccessor(accessorIndex,attributeName){return parser.getDependency('accessor',accessorIndex).then(function(accessor){geometry.addAttribute(attributeName,accessor);});}\n",
       "for(var gltfAttributeName in attributes){var threeAttributeName=ATTRIBUTES[gltfAttributeName]||gltfAttributeName.toLowerCase();if(threeAttributeName in geometry.attributes)continue;pending.push(assignAttributeAccessor(attributes[gltfAttributeName],threeAttributeName));}\n",
       "if(primitiveDef.indices!==undefined&&!geometry.index){var accessor=parser.getDependency('accessor',primitiveDef.indices).then(function(accessor){geometry.setIndex(accessor);});pending.push(accessor);}\n",
       "assignExtrasToUserData(geometry,primitiveDef);return Promise.all(pending).then(function(){return primitiveDef.targets!==undefined?addMorphTargets(geometry,primitiveDef.targets,parser):geometry;});}\n",
       "GLTFParser.prototype.loadGeometries=function(primitives){var parser=this;var extensions=this.extensions;var cache=this.primitiveCache;function createDracoPrimitive(primitive){return extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION].decodePrimitive(primitive,parser).then(function(geometry){return addPrimitiveAttributes(geometry,primitive,parser);});}\n",
       "var pending=[];for(var i=0,il=primitives.length;i<il;i++){var primitive=primitives[i];var cacheKey=createPrimitiveKey(primitive);var cached=cache[cacheKey];if(cached){pending.push(cached.promise);}else{var geometryPromise;if(primitive.extensions&&primitive.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]){geometryPromise=createDracoPrimitive(primitive);}else{geometryPromise=addPrimitiveAttributes(new THREE.BufferGeometry(),primitive,parser);}\n",
       "cache[cacheKey]={primitive:primitive,promise:geometryPromise};pending.push(geometryPromise);}}\n",
       "return Promise.all(pending);};GLTFParser.prototype.loadMesh=function(meshIndex){var parser=this;var json=this.json;var meshDef=json.meshes[meshIndex];var primitives=meshDef.primitives;var pending=[];for(var i=0,il=primitives.length;i<il;i++){var material=primitives[i].material===undefined?createDefaultMaterial():this.getDependency('material',primitives[i].material);pending.push(material);}\n",
       "return Promise.all(pending).then(function(originalMaterials){return parser.loadGeometries(primitives).then(function(geometries){var meshes=[];for(var i=0,il=geometries.length;i<il;i++){var geometry=geometries[i];var primitive=primitives[i];var mesh;var material=originalMaterials[i];if(primitive.mode===WEBGL_CONSTANTS.TRIANGLES||primitive.mode===WEBGL_CONSTANTS.TRIANGLE_STRIP||primitive.mode===WEBGL_CONSTANTS.TRIANGLE_FAN||primitive.mode===undefined){mesh=meshDef.isSkinnedMesh===true?new THREE.SkinnedMesh(geometry,material):new THREE.Mesh(geometry,material);if(mesh.isSkinnedMesh===true&&!mesh.geometry.attributes.skinWeight.normalized){mesh.normalizeSkinWeights();}\n",
       "if(primitive.mode===WEBGL_CONSTANTS.TRIANGLE_STRIP){mesh.drawMode=THREE.TriangleStripDrawMode;}else if(primitive.mode===WEBGL_CONSTANTS.TRIANGLE_FAN){mesh.drawMode=THREE.TriangleFanDrawMode;}}else if(primitive.mode===WEBGL_CONSTANTS.LINES){mesh=new THREE.LineSegments(geometry,material);}else if(primitive.mode===WEBGL_CONSTANTS.LINE_STRIP){mesh=new THREE.Line(geometry,material);}else if(primitive.mode===WEBGL_CONSTANTS.LINE_LOOP){mesh=new THREE.LineLoop(geometry,material);}else if(primitive.mode===WEBGL_CONSTANTS.POINTS){mesh=new THREE.Points(geometry,material);}else{throw new Error('THREE.GLTFLoader: Primitive mode unsupported: '+primitive.mode);}\n",
       "if(Object.keys(mesh.geometry.morphAttributes).length>0){updateMorphTargets(mesh,meshDef);}\n",
       "mesh.name=meshDef.name||('mesh_'+meshIndex);if(geometries.length>1)mesh.name+='_'+i;assignExtrasToUserData(mesh,meshDef);parser.assignFinalMaterial(mesh);meshes.push(mesh);}\n",
       "if(meshes.length===1){return meshes[0];}\n",
       "var group=new THREE.Group();for(var i=0,il=meshes.length;i<il;i++){group.add(meshes[i]);}\n",
       "return group;});});};GLTFParser.prototype.loadCamera=function(cameraIndex){var camera;var cameraDef=this.json.cameras[cameraIndex];var params=cameraDef[cameraDef.type];if(!params){console.warn('THREE.GLTFLoader: Missing camera parameters.');return;}\n",
       "if(cameraDef.type==='perspective'){camera=new THREE.PerspectiveCamera(THREE.Math.radToDeg(params.yfov),params.aspectRatio||1,params.znear||1,params.zfar||2e6);}else if(cameraDef.type==='orthographic'){camera=new THREE.OrthographicCamera(params.xmag/-2,params.xmag/2,params.ymag/2,params.ymag/-2,params.znear,params.zfar);}\n",
       "if(cameraDef.name!==undefined)camera.name=cameraDef.name;assignExtrasToUserData(camera,cameraDef);return Promise.resolve(camera);};GLTFParser.prototype.loadSkin=function(skinIndex){var skinDef=this.json.skins[skinIndex];var skinEntry={joints:skinDef.joints};if(skinDef.inverseBindMatrices===undefined){return Promise.resolve(skinEntry);}\n",
       "return this.getDependency('accessor',skinDef.inverseBindMatrices).then(function(accessor){skinEntry.inverseBindMatrices=accessor;return skinEntry;});};GLTFParser.prototype.loadAnimation=function(animationIndex){var json=this.json;var animationDef=json.animations[animationIndex];var pendingNodes=[];var pendingInputAccessors=[];var pendingOutputAccessors=[];var pendingSamplers=[];var pendingTargets=[];for(var i=0,il=animationDef.channels.length;i<il;i++){var channel=animationDef.channels[i];var sampler=animationDef.samplers[channel.sampler];var target=channel.target;var name=target.node!==undefined?target.node:target.id;var input=animationDef.parameters!==undefined?animationDef.parameters[sampler.input]:sampler.input;var output=animationDef.parameters!==undefined?animationDef.parameters[sampler.output]:sampler.output;pendingNodes.push(this.getDependency('node',name));pendingInputAccessors.push(this.getDependency('accessor',input));pendingOutputAccessors.push(this.getDependency('accessor',output));pendingSamplers.push(sampler);pendingTargets.push(target);}\n",
       "return Promise.all([Promise.all(pendingNodes),Promise.all(pendingInputAccessors),Promise.all(pendingOutputAccessors),Promise.all(pendingSamplers),Promise.all(pendingTargets)]).then(function(dependencies){var nodes=dependencies[0];var inputAccessors=dependencies[1];var outputAccessors=dependencies[2];var samplers=dependencies[3];var targets=dependencies[4];var tracks=[];for(var i=0,il=nodes.length;i<il;i++){var node=nodes[i];var inputAccessor=inputAccessors[i];var outputAccessor=outputAccessors[i];var sampler=samplers[i];var target=targets[i];if(node===undefined)continue;node.updateMatrix();node.matrixAutoUpdate=true;var TypedKeyframeTrack;switch(PATH_PROPERTIES[target.path]){case PATH_PROPERTIES.weights:TypedKeyframeTrack=THREE.NumberKeyframeTrack;break;case PATH_PROPERTIES.rotation:TypedKeyframeTrack=THREE.QuaternionKeyframeTrack;break;case PATH_PROPERTIES.position:case PATH_PROPERTIES.scale:default:TypedKeyframeTrack=THREE.VectorKeyframeTrack;break;}\n",
       "var targetName=node.name?node.name:node.uuid;var interpolation=sampler.interpolation!==undefined?INTERPOLATION[sampler.interpolation]:THREE.InterpolateLinear;var targetNames=[];if(PATH_PROPERTIES[target.path]===PATH_PROPERTIES.weights){node.traverse(function(object){if(object.isMesh===true&&object.morphTargetInfluences){targetNames.push(object.name?object.name:object.uuid);}});}else{targetNames.push(targetName);}\n",
       "var outputArray=outputAccessor.array;if(outputAccessor.normalized){var scale;if(outputArray.constructor===Int8Array){scale=1/127;}else if(outputArray.constructor===Uint8Array){scale=1/255;}else if(outputArray.constructor==Int16Array){scale=1/32767;}else if(outputArray.constructor===Uint16Array){scale=1/65535;}else{throw new Error('THREE.GLTFLoader: Unsupported output accessor component type.');}\n",
       "var scaled=new Float32Array(outputArray.length);for(var j=0,jl=outputArray.length;j<jl;j++){scaled[j]=outputArray[j]*scale;}\n",
       "outputArray=scaled;}\n",
       "for(var j=0,jl=targetNames.length;j<jl;j++){var track=new TypedKeyframeTrack(targetNames[j]+'.'+PATH_PROPERTIES[target.path],inputAccessor.array,outputArray,interpolation);if(sampler.interpolation==='CUBICSPLINE'){track.createInterpolant=function InterpolantFactoryMethodGLTFCubicSpline(result){return new GLTFCubicSplineInterpolant(this.times,this.values,this.getValueSize()/3,result);};track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline=true;}\n",
       "tracks.push(track);}}\n",
       "var name=animationDef.name!==undefined?animationDef.name:'animation_'+animationIndex;return new THREE.AnimationClip(name,undefined,tracks);});};GLTFParser.prototype.loadNode=function(nodeIndex){var json=this.json;var extensions=this.extensions;var parser=this;var meshReferences=json.meshReferences;var meshUses=json.meshUses;var nodeDef=json.nodes[nodeIndex];return(function(){if(nodeDef.isBone===true){return Promise.resolve(new THREE.Bone());}else if(nodeDef.mesh!==undefined){return parser.getDependency('mesh',nodeDef.mesh).then(function(mesh){var node;if(meshReferences[nodeDef.mesh]>1){var instanceNum=meshUses[nodeDef.mesh]++;node=mesh.clone();node.name+='_instance_'+instanceNum;node.onBeforeRender=mesh.onBeforeRender;for(var i=0,il=node.children.length;i<il;i++){node.children[i].name+='_instance_'+instanceNum;node.children[i].onBeforeRender=mesh.children[i].onBeforeRender;}}else{node=mesh;}\n",
       "if(nodeDef.weights!==undefined){node.traverse(function(o){if(!o.isMesh)return;for(var i=0,il=nodeDef.weights.length;i<il;i++){o.morphTargetInfluences[i]=nodeDef.weights[i];}});}\n",
       "return node;});}else if(nodeDef.camera!==undefined){return parser.getDependency('camera',nodeDef.camera);}else if(nodeDef.extensions&&nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL]&&nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].light!==undefined){return parser.getDependency('light',nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].light);}else{return Promise.resolve(new THREE.Object3D());}}()).then(function(node){if(nodeDef.name!==undefined){node.userData.name=nodeDef.name;node.name=THREE.PropertyBinding.sanitizeNodeName(nodeDef.name);}\n",
       "assignExtrasToUserData(node,nodeDef);if(nodeDef.extensions)addUnknownExtensionsToUserData(extensions,node,nodeDef);if(nodeDef.matrix!==undefined){var matrix=new THREE.Matrix4();matrix.fromArray(nodeDef.matrix);node.applyMatrix(matrix);}else{if(nodeDef.translation!==undefined){node.position.fromArray(nodeDef.translation);}\n",
       "if(nodeDef.rotation!==undefined){node.quaternion.fromArray(nodeDef.rotation);}\n",
       "if(nodeDef.scale!==undefined){node.scale.fromArray(nodeDef.scale);}}\n",
       "return node;});};GLTFParser.prototype.loadScene=function(){function buildNodeHierachy(nodeId,parentObject,json,parser){var nodeDef=json.nodes[nodeId];return parser.getDependency('node',nodeId).then(function(node){if(nodeDef.skin===undefined)return node;var skinEntry;return parser.getDependency('skin',nodeDef.skin).then(function(skin){skinEntry=skin;var pendingJoints=[];for(var i=0,il=skinEntry.joints.length;i<il;i++){pendingJoints.push(parser.getDependency('node',skinEntry.joints[i]));}\n",
       "return Promise.all(pendingJoints);}).then(function(jointNodes){var meshes=node.isGroup===true?node.children:[node];for(var i=0,il=meshes.length;i<il;i++){var mesh=meshes[i];var bones=[];var boneInverses=[];for(var j=0,jl=jointNodes.length;j<jl;j++){var jointNode=jointNodes[j];if(jointNode){bones.push(jointNode);var mat=new THREE.Matrix4();if(skinEntry.inverseBindMatrices!==undefined){mat.fromArray(skinEntry.inverseBindMatrices.array,j*16);}\n",
       "boneInverses.push(mat);}else{console.warn('THREE.GLTFLoader: Joint &quot;%s&quot; could not be found.',skinEntry.joints[j]);}}\n",
       "mesh.bind(new THREE.Skeleton(bones,boneInverses),mesh.matrixWorld);}\n",
       "return node;});}).then(function(node){parentObject.add(node);var pending=[];if(nodeDef.children){var children=nodeDef.children;for(var i=0,il=children.length;i<il;i++){var child=children[i];pending.push(buildNodeHierachy(child,node,json,parser));}}\n",
       "return Promise.all(pending);});}\n",
       "return function loadScene(sceneIndex){var json=this.json;var extensions=this.extensions;var sceneDef=this.json.scenes[sceneIndex];var parser=this;var scene=new THREE.Scene();if(sceneDef.name!==undefined)scene.name=sceneDef.name;assignExtrasToUserData(scene,sceneDef);if(sceneDef.extensions)addUnknownExtensionsToUserData(extensions,scene,sceneDef);var nodeIds=sceneDef.nodes||[];var pending=[];for(var i=0,il=nodeIds.length;i<il;i++){pending.push(buildNodeHierachy(nodeIds[i],scene,json,parser));}\n",
       "return Promise.all(pending).then(function(){return scene;});};}();return GLTFLoader;})();var camera,controls,scene,renderer,tracklight;function autoFit(obj,camera,controls){const boundingBox=new THREE.Box3().setFromObject(obj);const boundingSphere=new THREE.Sphere();boundingBox.getBoundingSphere((target=boundingSphere));const scale=1.0;const angularSize=camera.fov*Math.PI/180*scale;const distanceToCamera=boundingSphere.radius/Math.tan(angularSize);const len=Math.sqrt(Math.pow(distanceToCamera,2)+\n",
       "Math.pow(distanceToCamera,2)+\n",
       "Math.pow(distanceToCamera,2));camera.position.set(len,len,len);controls.update();camera.lookAt(boundingSphere.center);controls.target.set(boundingSphere.center.x,boundingSphere.center.y,boundingSphere.center.z);camera.updateProjectionMatrix();}\n",
       "function centerControls(obj,camera,controls){const boundingBox=new THREE.Box3().setFromObject(obj);const boundingSphere=new THREE.Sphere();boundingBox.getBoundingSphere((target=boundingSphere));controls.update();controls.target.set(boundingSphere.center.x,boundingSphere.center.y,boundingSphere.center.z);}\n",
       "function init(){scene=new THREE.Scene();scene.background=new THREE.Color(0xffffff);tracklight=new THREE.DirectionalLight(0xffffff,1.75);scene.add(tracklight);base64_data=&quot;[encoded data, 6145704 characters]&quot;;;renderer=new THREE.WebGLRenderer({antialias:true});renderer.setPixelRatio(window.devicePixelRatio);renderer.setSize(window.innerWidth,window.innerHeight);document.body.appendChild(renderer.domElement);loader=new THREE.GLTFLoader();loader.load(&quot;data:text/plain;base64,&quot;+base64_data,function(gltf){scene.add(gltf.scene);camera=gltf.cameras[0];controls=new THREE.TrackballControls(camera);controls.rotateSpeed=1.0;controls.zoomSpeed=1.2;controls.panSpeed=0.8;controls.noZoom=false;controls.noPan=false;controls.staticMoving=true;controls.dynamicDampingFactor=0.3;controls.keys=[65,83,68];controls.addEventListener(&quot;change&quot;,render);centerControls(scene,camera,controls);render();window.addEventListener(&quot;resize&quot;,onWindowResize,false);animate();});}\n",
       "function onWindowResize(){camera.aspect=window.innerWidth/window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth,window.innerHeight);controls.handleResize();render();}\n",
       "function animate(){requestAnimationFrame(animate);controls.update();}\n",
       "function render(){tracklight.position.copy(camera.position);renderer.render(scene,camera);}\n",
       "init();</script></body>\n",
       "</html>\" width=\"100%\" height=\"500px\" style=\"border:none;\"></iframe>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# TODO: Just use the mesh data directly (no sense in saving & re-loading)\n",
    "m = trimesh.load_mesh(mesh_fname)\n",
    "#m.show()\n",
    "scene = trimesh.Scene([m])\n",
    "scene.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
