|  | @@ -0,0 +1,277 @@
 | 
	
		
			
				|  |  | +// Copyright 2016 The Draco Authors.
 | 
	
		
			
				|  |  | +//
 | 
	
		
			
				|  |  | +// Licensed under the Apache License, Version 2.0 (the "License");
 | 
	
		
			
				|  |  | +// you may not use this file except in compliance with the License.
 | 
	
		
			
				|  |  | +// You may obtain a copy of the License at
 | 
	
		
			
				|  |  | +//
 | 
	
		
			
				|  |  | +//      http://www.apache.org/licenses/LICENSE-2.0
 | 
	
		
			
				|  |  | +//
 | 
	
		
			
				|  |  | +// Unless required by applicable law or agreed to in writing, software
 | 
	
		
			
				|  |  | +// distributed under the License is distributed on an "AS IS" BASIS,
 | 
	
		
			
				|  |  | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
	
		
			
				|  |  | +// See the License for the specific language governing permissions and
 | 
	
		
			
				|  |  | +// limitations under the License.
 | 
	
		
			
				|  |  | +//
 | 
	
		
			
				|  |  | +'use strict';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +THREE.DRACOLoader = function(manager) {
 | 
	
		
			
				|  |  | +    this.manager = (manager !== undefined) ? manager :
 | 
	
		
			
				|  |  | +        THREE.DefaultLoadingManager;
 | 
	
		
			
				|  |  | +    this.materials = null;
 | 
	
		
			
				|  |  | +    this.verbosity = 0;
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +THREE.DRACOLoader.prototype = {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    constructor: THREE.DRACOLoader,
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    load: function(url, onLoad, onProgress, onError) {
 | 
	
		
			
				|  |  | +        const scope = this;
 | 
	
		
			
				|  |  | +        const loader = new THREE.FileLoader(scope.manager);
 | 
	
		
			
				|  |  | +        loader.setPath(this.path);
 | 
	
		
			
				|  |  | +        loader.setResponseType('arraybuffer');
 | 
	
		
			
				|  |  | +        loader.load(url, function(blob) {
 | 
	
		
			
				|  |  | +            onLoad(scope.decodeDracoFile(blob));
 | 
	
		
			
				|  |  | +        }, onProgress, onError);
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    setPath: function(value) {
 | 
	
		
			
				|  |  | +        this.path = value;
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    setVerbosity: function(level) {
 | 
	
		
			
				|  |  | +        this.verbosity = level;
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    decodeDracoFile: ( function() {
 | 
	
		
			
				|  |  | +        let dracoDecoder;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (typeof DracoModule === 'function') {
 | 
	
		
			
				|  |  | +          dracoDecoder = DracoModule();
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          console.error('THREE.DRACOLoader: DracoModule not found.');
 | 
	
		
			
				|  |  | +          return;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return function(rawBuffer) {
 | 
	
		
			
				|  |  | +          const scope = this;
 | 
	
		
			
				|  |  | +          /*
 | 
	
		
			
				|  |  | +           * Here is how to use Draco Javascript decoder and get the geometry.
 | 
	
		
			
				|  |  | +           */
 | 
	
		
			
				|  |  | +          const buffer = new dracoDecoder.DecoderBuffer();
 | 
	
		
			
				|  |  | +          buffer.Init(new Int8Array(rawBuffer), rawBuffer.byteLength);
 | 
	
		
			
				|  |  | +          const wrapper = new dracoDecoder.WebIDLWrapper();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          /*
 | 
	
		
			
				|  |  | +           * Determine what type is this file: mesh or point cloud.
 | 
	
		
			
				|  |  | +           */
 | 
	
		
			
				|  |  | +          const geometryType = wrapper.GetEncodedGeometryType(buffer);
 | 
	
		
			
				|  |  | +          if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
 | 
	
		
			
				|  |  | +            if (this.verbosity > 0) {
 | 
	
		
			
				|  |  | +              console.log('Loaded a mesh.');
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          } else if (geometryType == dracoDecoder.POINT_CLOUD) {
 | 
	
		
			
				|  |  | +            if (this.verbosity > 0) {
 | 
	
		
			
				|  |  | +              console.log('Loaded a point cloud.');
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          } else {
 | 
	
		
			
				|  |  | +            const errorMsg = 'THREE.DRACOLoader: Unknown geometry type.'
 | 
	
		
			
				|  |  | +            console.error(errorMsg);
 | 
	
		
			
				|  |  | +            throw new Error(errorMsg);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          return scope.convertDracoGeometryTo3JS(wrapper, geometryType, buffer,
 | 
	
		
			
				|  |  | +                                                 dracoDecoder);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    } )(),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    convertDracoGeometryTo3JS: function(wrapper, geometryType, buffer,
 | 
	
		
			
				|  |  | +                                        dracoDecoder) {
 | 
	
		
			
				|  |  | +        let dracoGeometry;
 | 
	
		
			
				|  |  | +        const start_time = performance.now();
 | 
	
		
			
				|  |  | +        if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
 | 
	
		
			
				|  |  | +          dracoGeometry = wrapper.DecodeMeshFromBuffer(buffer);
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          dracoGeometry = wrapper.DecodePointCloudFromBuffer(buffer);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        const decode_end = performance.now();
 | 
	
		
			
				|  |  | +        dracoDecoder.destroy(buffer);
 | 
	
		
			
				|  |  | +        /*
 | 
	
		
			
				|  |  | +         * Example on how to retrieve mesh and attributes.
 | 
	
		
			
				|  |  | +         */
 | 
	
		
			
				|  |  | +        let numFaces, numPoints;
 | 
	
		
			
				|  |  | +        let numVertexCoordinates, numTextureCoordinates, numAttributes;
 | 
	
		
			
				|  |  | +        // For output basic geometry information.
 | 
	
		
			
				|  |  | +        let geometryInfoStr;
 | 
	
		
			
				|  |  | +        if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
 | 
	
		
			
				|  |  | +          numFaces = dracoGeometry.num_faces();
 | 
	
		
			
				|  |  | +          if (this.verbosity > 0) {
 | 
	
		
			
				|  |  | +            console.log('Number of faces loaded: ' + numFaces.toString());
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          numFaces = 0;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        numPoints = dracoGeometry.num_points();
 | 
	
		
			
				|  |  | +        numVertexCoordinates = numPoints * 3;
 | 
	
		
			
				|  |  | +        numTextureCoordinates = numPoints * 2;
 | 
	
		
			
				|  |  | +        numAttributes = dracoGeometry.num_attributes();
 | 
	
		
			
				|  |  | +        if (this.verbosity > 0) {
 | 
	
		
			
				|  |  | +          console.log('Number of points loaded: ' + numPoints.toString());
 | 
	
		
			
				|  |  | +          console.log('Number of attributes loaded: ' +
 | 
	
		
			
				|  |  | +              numAttributes.toString());
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Get position attribute. Must exists.
 | 
	
		
			
				|  |  | +        const posAttId = wrapper.GetAttributeId(dracoGeometry,
 | 
	
		
			
				|  |  | +                                                dracoDecoder.POSITION);
 | 
	
		
			
				|  |  | +        if (posAttId == -1) {
 | 
	
		
			
				|  |  | +          const errorMsg = 'THREE.DRACOLoader: No position attribute found.';
 | 
	
		
			
				|  |  | +          console.error(errorMsg);
 | 
	
		
			
				|  |  | +          dracoDecoder.destroy(wrapper);
 | 
	
		
			
				|  |  | +          dracoDecoder.destroy(dracoGeometry);
 | 
	
		
			
				|  |  | +          throw new Error(errorMsg);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        const posAttribute = wrapper.GetAttribute(dracoGeometry, posAttId);
 | 
	
		
			
				|  |  | +        const posAttributeData = new dracoDecoder.DracoFloat32Array();
 | 
	
		
			
				|  |  | +        wrapper.GetAttributeFloatForAllPoints(
 | 
	
		
			
				|  |  | +            dracoGeometry, posAttribute, posAttributeData);
 | 
	
		
			
				|  |  | +        // Get color attributes if exists.
 | 
	
		
			
				|  |  | +        const colorAttId = wrapper.GetAttributeId(dracoGeometry,
 | 
	
		
			
				|  |  | +                                                  dracoDecoder.COLOR);
 | 
	
		
			
				|  |  | +        let colAttributeData;
 | 
	
		
			
				|  |  | +        if (colorAttId != -1) {
 | 
	
		
			
				|  |  | +          if (this.verbosity > 0) {
 | 
	
		
			
				|  |  | +            console.log('Loaded color attribute.');
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          const colAttribute = wrapper.GetAttribute(dracoGeometry, colorAttId);
 | 
	
		
			
				|  |  | +          colAttributeData = new dracoDecoder.DracoFloat32Array();
 | 
	
		
			
				|  |  | +          wrapper.GetAttributeFloatForAllPoints(dracoGeometry, colAttribute,
 | 
	
		
			
				|  |  | +                                                colAttributeData);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Get normal attributes if exists.
 | 
	
		
			
				|  |  | +        const normalAttId =
 | 
	
		
			
				|  |  | +            wrapper.GetAttributeId(dracoGeometry, dracoDecoder.NORMAL);
 | 
	
		
			
				|  |  | +        let norAttributeData;
 | 
	
		
			
				|  |  | +        if (normalAttId != -1) {
 | 
	
		
			
				|  |  | +          if (this.verbosity > 0) {
 | 
	
		
			
				|  |  | +            console.log('Loaded normal attribute.');
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          const norAttribute = wrapper.GetAttribute(dracoGeometry, normalAttId);
 | 
	
		
			
				|  |  | +          norAttributeData = new dracoDecoder.DracoFloat32Array();
 | 
	
		
			
				|  |  | +          wrapper.GetAttributeFloatForAllPoints(dracoGeometry, norAttribute,
 | 
	
		
			
				|  |  | +                                                norAttributeData);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Get texture coord attributes if exists.
 | 
	
		
			
				|  |  | +        const texCoordAttId =
 | 
	
		
			
				|  |  | +            wrapper.GetAttributeId(dracoGeometry, dracoDecoder.TEX_COORD);
 | 
	
		
			
				|  |  | +        let textCoordAttributeData;
 | 
	
		
			
				|  |  | +        if (texCoordAttId != -1) {
 | 
	
		
			
				|  |  | +          if (this.verbosity > 0) {
 | 
	
		
			
				|  |  | +            console.log('Loaded texture coordinate attribute.');
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          const texCoordAttribute = wrapper.GetAttribute(dracoGeometry,
 | 
	
		
			
				|  |  | +                                                         texCoordAttId);
 | 
	
		
			
				|  |  | +          textCoordAttributeData = new dracoDecoder.DracoFloat32Array();
 | 
	
		
			
				|  |  | +          wrapper.GetAttributeFloatForAllPoints(dracoGeometry,
 | 
	
		
			
				|  |  | +                                                texCoordAttribute,
 | 
	
		
			
				|  |  | +                                                textCoordAttributeData);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Structure for converting to THREEJS geometry later.
 | 
	
		
			
				|  |  | +        const numIndices = numFaces * 3;
 | 
	
		
			
				|  |  | +        const geometryBuffer = {
 | 
	
		
			
				|  |  | +            indices: new Uint32Array(numIndices),
 | 
	
		
			
				|  |  | +            vertices: new Float32Array(numVertexCoordinates),
 | 
	
		
			
				|  |  | +            normals: new Float32Array(numVertexCoordinates),
 | 
	
		
			
				|  |  | +            uvs: new Float32Array(numTextureCoordinates),
 | 
	
		
			
				|  |  | +            colors: new Float32Array(numVertexCoordinates)
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for (let i = 0; i < numVertexCoordinates; i += 3) {
 | 
	
		
			
				|  |  | +            geometryBuffer.vertices[i] = posAttributeData.GetValue(i);
 | 
	
		
			
				|  |  | +            geometryBuffer.vertices[i + 1] = posAttributeData.GetValue(i + 1);
 | 
	
		
			
				|  |  | +            geometryBuffer.vertices[i + 2] = posAttributeData.GetValue(i + 2);
 | 
	
		
			
				|  |  | +            // Add color.
 | 
	
		
			
				|  |  | +            // ThreeJS vertex colors need to be normalized to properly display
 | 
	
		
			
				|  |  | +            if (colorAttId != -1) {
 | 
	
		
			
				|  |  | +              geometryBuffer.colors[i] = colAttributeData.GetValue(i) / 255;
 | 
	
		
			
				|  |  | +              geometryBuffer.colors[i + 1] =
 | 
	
		
			
				|  |  | +                  colAttributeData.GetValue(i + 1) / 255;
 | 
	
		
			
				|  |  | +              geometryBuffer.colors[i + 2] =
 | 
	
		
			
				|  |  | +                  colAttributeData.GetValue(i + 2) / 255;
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +              // Default is white. This is faster than TypedArray.fill().
 | 
	
		
			
				|  |  | +              geometryBuffer.colors[i] = 1.0;
 | 
	
		
			
				|  |  | +              geometryBuffer.colors[i + 1] = 1.0;
 | 
	
		
			
				|  |  | +              geometryBuffer.colors[i + 2] = 1.0;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            // Add normal.
 | 
	
		
			
				|  |  | +            if (normalAttId != -1) {
 | 
	
		
			
				|  |  | +              geometryBuffer.normals[i] = norAttributeData.GetValue(i);
 | 
	
		
			
				|  |  | +              geometryBuffer.normals[i + 1] = norAttributeData.GetValue(i + 1);
 | 
	
		
			
				|  |  | +              geometryBuffer.normals[i + 2] = norAttributeData.GetValue(i + 2);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Add texture coordinates.
 | 
	
		
			
				|  |  | +        if (texCoordAttId != -1) {
 | 
	
		
			
				|  |  | +          for (let i = 0; i < numTextureCoordinates; i += 2) {
 | 
	
		
			
				|  |  | +            geometryBuffer.uvs[i] = textCoordAttributeData.GetValue(i);
 | 
	
		
			
				|  |  | +            geometryBuffer.uvs[i + 1] = textCoordAttributeData.GetValue(i + 1);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        dracoDecoder.destroy(posAttributeData);
 | 
	
		
			
				|  |  | +        if (colorAttId != -1)
 | 
	
		
			
				|  |  | +          dracoDecoder.destroy(colAttributeData);
 | 
	
		
			
				|  |  | +        if (normalAttId != -1)
 | 
	
		
			
				|  |  | +          dracoDecoder.destroy(norAttributeData);
 | 
	
		
			
				|  |  | +        if (texCoordAttId != -1)
 | 
	
		
			
				|  |  | +          dracoDecoder.destroy(textCoordAttributeData);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // For mesh, we need to generate the faces.
 | 
	
		
			
				|  |  | +        if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
 | 
	
		
			
				|  |  | +          const ia = new dracoDecoder.DracoInt32Array();
 | 
	
		
			
				|  |  | +          for (let i = 0; i < numFaces; ++i) {
 | 
	
		
			
				|  |  | +            wrapper.GetFaceFromMesh(dracoGeometry, i, ia);
 | 
	
		
			
				|  |  | +            const index = i * 3;
 | 
	
		
			
				|  |  | +            geometryBuffer.indices[index] = ia.GetValue(0);
 | 
	
		
			
				|  |  | +            geometryBuffer.indices[index + 1] = ia.GetValue(1);
 | 
	
		
			
				|  |  | +            geometryBuffer.indices[index + 2] = ia.GetValue(2);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          dracoDecoder.destroy(ia);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        dracoDecoder.destroy(wrapper);
 | 
	
		
			
				|  |  | +        dracoDecoder.destroy(dracoGeometry);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Import data to Three JS geometry.
 | 
	
		
			
				|  |  | +        const geometry = new THREE.BufferGeometry();
 | 
	
		
			
				|  |  | +        if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
 | 
	
		
			
				|  |  | +          geometry.setIndex(new(geometryBuffer.indices.length > 65535 ?
 | 
	
		
			
				|  |  | +                THREE.Uint32BufferAttribute : THREE.Uint16BufferAttribute)
 | 
	
		
			
				|  |  | +              (geometryBuffer.indices, 1));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        geometry.addAttribute('position',
 | 
	
		
			
				|  |  | +            new THREE.Float32BufferAttribute(geometryBuffer.vertices, 3));
 | 
	
		
			
				|  |  | +        geometry.addAttribute('color',
 | 
	
		
			
				|  |  | +            new THREE.Float32BufferAttribute(geometryBuffer.colors, 3));
 | 
	
		
			
				|  |  | +        if (normalAttId != -1) {
 | 
	
		
			
				|  |  | +          geometry.addAttribute('normal',
 | 
	
		
			
				|  |  | +              new THREE.Float32BufferAttribute(geometryBuffer.normals, 3));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (texCoordAttId != -1) {
 | 
	
		
			
				|  |  | +          geometry.addAttribute('uv',
 | 
	
		
			
				|  |  | +              new THREE.Float32BufferAttribute(geometryBuffer.uvs, 2));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        this.decode_time = decode_end - start_time;
 | 
	
		
			
				|  |  | +        this.import_time = performance.now() - decode_end;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (this.verbosity > 0) {
 | 
	
		
			
				|  |  | +          console.log('Decode time: ' + this.decode_time);
 | 
	
		
			
				|  |  | +          console.log('Import time: ' + this.import_time);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return geometry;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +};
 |