| // namespace | |
| var MeshesJS = MeshesJS || {}; | |
| ;(function() { | |
| // Constructor | |
| function STLLoader(dropTarget) { | |
| this.dropTarget = dropTarget || null; | |
| this.addDropListener(); | |
| } | |
| // methods | |
| STLLoader.prototype.onDragLeave = function(e) { | |
| e.stopPropagation(); | |
| e.preventDefault(); | |
| } | |
| STLLoader.prototype.onDrop = function(e) { | |
| this.onDragLeave(e); | |
| this.loadFile((e.target.files || e.dataTransfer.files)[0]); | |
| } | |
| STLLoader.prototype.addDropListener = function(dropTarget) { | |
| var dropTarget = dropTarget || this.dropTarget; | |
| if (dropTarget) { | |
| var self = this; | |
| dropTarget.addEventListener('drop' , function(e) { self.onDrop(e); } , false); | |
| dropTarget.addEventListener('dragover' , function(e) { self.onDragLeave(e); }, false); | |
| dropTarget.addEventListener('dragleave', function(e) { self.onDragLeave(e); }, false); | |
| } | |
| }; | |
| STLLoader.prototype.removeDropListener = function(dropTarget) { | |
| var dropTarget = dropTarget || this.dropTarget; | |
| if (dropTarget) { | |
| var self = this; | |
| dropTarget.removeEventListener('drop' , function(e) { self.onDrop(e); } , false); | |
| dropTarget.removeEventListener('dragover' , function(e) { self.onDragLeave(e); }, false); | |
| dropTarget.removeEventListener('dragleave', function(e) { self.onDragLeave(e); }, false); | |
| } | |
| }; | |
| STLLoader.prototype.onGeometry = function(geometry) {}; | |
| STLLoader.prototype.onError = function(error) {}; | |
| STLLoader.prototype.loadFile = function(file) { | |
| // self alias | |
| var self = this; | |
| // file reader instance | |
| var reader = new FileReader(); | |
| // on file loaded | |
| reader.onloadend = function(event) { | |
| // if error/abort | |
| if (this.error) { | |
| self.onError(this.error); | |
| return; | |
| } | |
| // Parse ASCII STL | |
| if (typeof this.result === 'string' ) { | |
| self.loadString(this.result); | |
| return; | |
| } | |
| // buffer reader | |
| var view = new DataView(this.result); | |
| // get faces number | |
| try { | |
| var faces = view.getUint32(80, true); | |
| } | |
| catch(error) { | |
| self.onError(error); | |
| return; | |
| } | |
| // is binary ? | |
| var binary = view.byteLength == (80 + 4 + 50 * faces); | |
| if (! binary) { | |
| // get the file contents as string | |
| // (faster than convert array buffer) | |
| reader.readAsText(file); | |
| return; | |
| } | |
| // parse binary STL | |
| self.loadBinaryData(view, faces); | |
| }; | |
| // start reading file as array buffer | |
| reader.readAsArrayBuffer(file); | |
| }; | |
| STLLoader.prototype.loadString = function(data) { | |
| var length, normal, patternNormal, patternVertex, result, text; | |
| var geometry = new THREE.Geometry(); | |
| var patternFace = /facet([\s\S]*?)endfacet/g; | |
| while((result = patternFace.exec(data)) !== null) { | |
| text = result[0]; | |
| patternNormal = /normal[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g; | |
| patternVertex = /vertex[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g; | |
| while((result = patternNormal.exec(text)) !== null) { | |
| normal = new THREE.Vector3( | |
| parseFloat(result[1]), | |
| parseFloat(result[3]), | |
| parseFloat(result[5]) | |
| ); | |
| } | |
| while((result = patternVertex.exec(text)) !== null) { | |
| geometry.vertices.push(new THREE.Vector3( | |
| parseFloat(result[1]), | |
| parseFloat(result[3]), | |
| parseFloat(result[5]) | |
| )); | |
| } | |
| length = geometry.vertices.length; | |
| geometry.faces.push(new THREE.Face3(length-3, length-2, length-1, normal)); | |
| } | |
| geometry.computeBoundingBox(); | |
| geometry.computeBoundingSphere(); | |
| this.onGeometry(geometry); | |
| }; | |
| STLLoader.prototype.loadBinaryData = function(view, faces) { | |
| if (! view instanceof DataView) { | |
| var view = new DataView(view); | |
| } | |
| if (! faces) { | |
| try { | |
| var faces = view.getUint32(80, true); | |
| } | |
| catch(error) { | |
| this.onError(error); | |
| return; | |
| } | |
| } | |
| var dataOffset = 84; | |
| var faceLength = 12 * 4 + 2; | |
| var offset = 0; | |
| var geometry = new THREE.BufferGeometry(); | |
| var vertices = new Float32Array( faces * 3 * 3 ); | |
| var normals = new Float32Array( faces * 3 * 3 ); | |
| for ( var face = 0; face < faces; face ++ ) { | |
| var start = dataOffset + face * faceLength; | |
| var normalX = view.getFloat32( start, true ); | |
| var normalY = view.getFloat32( start + 4, true ); | |
| var normalZ = view.getFloat32( start + 8, true ); | |
| for (var i = 1; i <= 3; i ++) { | |
| var vertexstart = start + i * 12; | |
| normals[ offset ] = normalX; | |
| normals[ offset + 1 ] = normalY; | |
| normals[ offset + 2 ] = normalZ; | |
| vertices[ offset ] = view.getFloat32( vertexstart, true ); | |
| vertices[ offset + 1 ] = view.getFloat32( vertexstart + 4, true ); | |
| vertices[ offset + 2 ] = view.getFloat32( vertexstart + 8, true ); | |
| offset += 3; | |
| } | |
| } | |
| geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3)); | |
| geometry.addAttribute('normal', new THREE.BufferAttribute(normals, 3)); | |
| this.onGeometry(geometry); | |
| }; | |
| // export module | |
| MeshesJS.STLLoader = STLLoader; | |
| })(); |