Jelajahi Sumber

add an improved version of the STLLoader

OpenShift guest 12 tahun lalu
induk
melakukan
bd7fda284d
1 mengubah file dengan 190 tambahan dan 166 penghapusan
  1. 190 166
      examples/js/loaders/STLLoader.js

+ 190 - 166
examples/js/loaders/STLLoader.js

@@ -8,7 +8,7 @@
  * Supports both binary and ASCII encoded files, with automatic detection of type.
  *
  * Limitations: Binary decoding ignores header. There doesn't seem to be much of a use for it.
- *				There is perhaps some question as to how valid it is to always assume little-endian-ness.
+ *    			There is perhaps some question as to how valid it is to always assume little-endian-ness.
  *				ASCII decoding assumes file is UTF-8. Seems to work for the examples...
  *
  * Usage:
@@ -46,7 +46,7 @@ THREE.STLLoader.prototype.load = function (url, callback) {
 
 		if ( event.target.status === 200 || event.target.status === 0 ) {
 
-				var geometry = scope.parse( event.target.responseText );
+				var geometry = scope.parse( event.target.response || event.target.responseText );
 
 				scope.dispatchEvent( { type: 'load', content: geometry } );
 
@@ -77,64 +77,68 @@ THREE.STLLoader.prototype.load = function (url, callback) {
 
 	xhr.overrideMimeType('text/plain; charset=x-user-defined');
 	xhr.open( 'GET', url, true );
+	xhr.responseType = "arraybuffer";
 	xhr.send( null );
 
 };
 
 THREE.STLLoader.prototype.parse = function (data) {
 
-	var isBinary = function (data) {
+
+	var isBinary = function () {
 
 		var expect, face_size, n_faces, reader;
-		reader = new THREE.STLLoader.BinaryReader(data);
-		reader.seek(80);
+		reader = new DataView( binData );
 		face_size = (32 / 8 * 3) + ((32 / 8 * 3) * 3) + (16 / 8);
-		n_faces = reader.readUInt32();
+		n_faces = reader.getUint32(80,true);
 		expect = 80 + (32 / 8) + (n_faces * face_size);
-		return expect === reader.getSize();
+		return expect === reader.byteLength;
 
 	};
+	
+	var binData = this.ensureBinary(data);
 
-	if (isBinary(data)) {
+	if (isBinary()) {
 
-		return this.parseBinary(data);
+		return this.parseBinary(binData);
 
 	} else {
-
-		return this.parseASCII(data);
+		
+		return this.parseASCII(this.ensureString(data));
 
 	}
 };
 
 THREE.STLLoader.prototype.parseBinary = function (data) {
 
-	var face, geometry, n_faces, reader, length, normal, i;
-
-	reader = new THREE.STLLoader.BinaryReader(data);
-	reader.seek(80);
-	n_faces = reader.readUInt32();
+	var face, geometry, n_faces, reader, length, normal, i, dataOffset, faceLength, start, vertexstart;
+	
+	reader = new DataView( data );
+	n_faces = reader.getUint32(80,true);
 	geometry = new THREE.Geometry();
-
+    dataOffset = 84;
+	faceLength = 12 * 4 + 2;
+	
 	for (face = 0; face < n_faces; face++) {
 
-		normal = new THREE.Vector3(reader.readFloat(),reader.readFloat(),reader.readFloat());
+        start = dataOffset + face * faceLength;
+		normal = new THREE.Vector3(reader.getFloat32(start,true),reader.getFloat32(start + 4,true),reader.getFloat32(start + 8,true));
 
 		for (i = 1; i <= 3; i++) {
-
-			geometry.vertices.push(new THREE.Vector3(reader.readFloat(),reader.readFloat(),reader.readFloat()));
+			
+            vertexstart = start + i * 12;
+			geometry.vertices.push(new THREE.Vector3(reader.getFloat32(vertexstart,true),reader.getFloat32(vertexstart +4,true),reader.getFloat32(vertexstart + 8,true)));
 
 		}
 
-		reader.readUInt16(); // attr doesn't get used yet.
 		length = geometry.vertices.length;
 		geometry.faces.push(new THREE.Face3(length - 3, length - 2, length - 1, normal));
 
 	}
 
 	geometry.computeCentroids();
-	geometry.computeBoundingBox();
 	geometry.computeBoundingSphere();
-
+	
 	return geometry;
 
 };
@@ -177,153 +181,173 @@ THREE.STLLoader.prototype.parseASCII = function (data) {
 
 };
 
-
-THREE.STLLoader.BinaryReader = function (data) {
-
-	this._buffer = data;
-	this._pos = 0;
+THREE.STLLoader.prototype.ensureString = function (buf) {
+	
+	if (typeof buf !== "string"){
+		var array_buffer = new Uint8Array(buf);
+		var str = '';
+		for(var i = 0; i < buf.byteLength; i++) {
+			str += String.fromCharCode(array_buffer[i]); // implicitly assumes little-endian
+		}
+		return str;
+	} else {
+		return buf;
+	}
 
 };
+THREE.STLLoader.prototype.ensureBinary = function (buf) {
+	
+	if (typeof buf === "string"){
+		var array_buffer = new Uint8Array(buf.length);
+		for(var i = 0; i < buf.length; i++) {
+			array_buffer[i] = buf.charCodeAt(i) & 0xff; // implicitly assumes little-endian
+		}
+		return array_buffer.buffer || array_buffer;
+	} else {
+		return buf;
+	}
 
-THREE.STLLoader.BinaryReader.prototype = {
-
-	/* Public */
-
-	readInt8:	function (){ return this._decodeInt(8, true); },
-	readUInt8:	function (){ return this._decodeInt(8, false); },
-	readInt16:	function (){ return this._decodeInt(16, true); },
-	readUInt16:	function (){ return this._decodeInt(16, false); },
-	readInt32:	function (){ return this._decodeInt(32, true); },
-	readUInt32:	function (){ return this._decodeInt(32, false); },
-
-	readFloat:	function (){ return this._decodeFloat(23, 8); },
-	readDouble:	function (){ return this._decodeFloat(52, 11); },
-
-	readChar:	function () { return this.readString(1); },
-
-	readString: function (length) {
-
-		this._checkSize(length * 8);
-		var result = this._buffer.substr(this._pos, length);
-		this._pos += length;
-		return result;
-
-	},
-
-	seek: function (pos) {
-
-		this._pos = pos;
-		this._checkSize(0);
-
-	},
-
-	getPosition: function () {
-
-		return this._pos;
-
-	},
-
-	getSize: function () {
-
-		return this._buffer.length;
-
-	},
-
-
-	/* Private */
-
-	_decodeFloat: function(precisionBits, exponentBits){
-
-		var length = precisionBits + exponentBits + 1;
-		var size = length >> 3;
-
-		this._checkSize(length);
+};
 
-		var bias = Math.pow(2, exponentBits - 1) - 1;
-		var signal = this._readBits(precisionBits + exponentBits, 1, size);
-		var exponent = this._readBits(precisionBits, exponentBits, size);
-		var significand = 0;
-		var divisor = 2;
-	// var curByte = length + (-precisionBits >> 3) - 1;
-		var curByte = 0;
-		do {
-			var byteValue = this._readByte(++curByte, size);
-			var startBit = precisionBits % 8 || 8;
-			var mask = 1 << startBit;
-			while (mask >>= 1) {
-				if (byteValue & mask) {
-					significand += 1 / divisor;
+if ( typeof DataView === 'undefined'){
+    
+    DataView = function(buffer, byteOffset, byteLength){
+        this.buffer = buffer;
+        this.byteOffset = byteOffset || 0;
+        this.byteLength = byteLength || buffer.byteLength || buffer.length;
+        this._isString = typeof buffer === "string";
+        
+    }
+    
+   DataView.prototype = {
+		_getCharCodes:function(buffer,start,length){
+			start = start || 0;
+			length = length || buffer.length;
+			var end = start + length;
+			var codes = [];
+			for (var i = start; i < end; i++) {
+				codes.push(buffer.charCodeAt(i) & 0xff);
+			}
+			return codes;
+		},
+   	
+        _getBytes: function (length, byteOffset, littleEndian) {
+			var result;
+		
+			// Handle the lack of endianness
+			if (littleEndian === undefined) {
+				littleEndian = this._littleEndian;
+			}
+		
+			// Handle the lack of byteOffset
+			if (byteOffset === undefined) {
+				byteOffset = this.byteOffset;
+			} else {
+				byteOffset = this.byteOffset + byteOffset;
+			}
+		
+			if (length === undefined) {
+				length = this.byteLength - byteOffset;
+			}
+		
+			// Error Checking
+			if (typeof byteOffset !== 'number') {
+				throw new TypeError('DataView byteOffset is not a number');
+			}
+			if (length < 0 || byteOffset + length > this.byteLength) {
+				throw new Error('DataView length or (byteOffset+length) value is out of bounds');
+			}
+		
+			if (this.isString){
+				result = this._getCharCodes(this.buffer, byteOffset, byteOffset + length);
+			} else {
+				result = this.buffer.slice(byteOffset, byteOffset + length);
+			}
+		
+			if (!littleEndian && length > 1) {
+				if (!(result instanceof Array)) {
+					result = Array.prototype.slice.call(result);
 				}
-				divisor *= 2;
+		
+				result.reverse();
 			}
-		} while (precisionBits -= startBit);
-
-		this._pos += size;
-
-		return exponent == (bias << 1) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity
-			: (1 + signal * -2) * (exponent || significand ? !exponent ? Math.pow(2, -bias + 1) * significand
-			: Math.pow(2, exponent - bias) * (1 + significand) : 0);
-
-	},
-
-	_decodeInt: function(bits, signed){
-
-		var x = this._readBits(0, bits, bits / 8), max = Math.pow(2, bits);
-		var result = signed && x >= max / 2 ? x - max : x;
-
-		this._pos += bits / 8;
-		return result;
-
-	},
-
-	//shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
-	_shl: function (a, b){
-
-		for (++b; --b; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1);
-		return a;
-
-	},
-
-	_readByte: function (i, size) {
-
-		return this._buffer.charCodeAt(this._pos + size - i - 1) & 0xff;
-
-	},
-
-	_readBits: function (start, length, size) {
-
-		var offsetLeft = (start + length) % 8;
-		var offsetRight = start % 8;
-		var curByte = size - (start >> 3) - 1;
-		var lastByte = size + (-(start + length) >> 3);
-		var diff = curByte - lastByte;
-
-		var sum = (this._readByte(curByte, size) >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1);
-
-		if (diff && offsetLeft) {
-
-			sum += (this._readByte(lastByte++, size) & ((1 << offsetLeft) - 1)) << (diff-- << 3) - offsetRight;
-
-		}
-
-		while (diff) {
-
-			sum += this._shl(this._readByte(lastByte++, size), (diff-- << 3) - offsetRight);
-
-		}
-
-		return sum;
-
-	},
-
-	_checkSize: function (neededBits) {
-
-		if (!(this._pos + Math.ceil(neededBits / 8) < this._buffer.length)) {
-
-			throw new Error("Index out of bound");
-
+		
+			return result;
+		},
+		
+		// Compatibility functions on a String Buffer
+		
+		getFloat64: function (byteOffset, littleEndian) {
+			var b = this._getBytes(8, byteOffset, littleEndian),
+		
+				sign = 1 - (2 * (b[7] >> 7)),
+				exponent = ((((b[7] << 1) & 0xff) << 3) | (b[6] >> 4)) - ((1 << 10) - 1),
+		
+			// Binary operators such as | and << operate on 32 bit values, using + and Math.pow(2) instead
+				mantissa = ((b[6] & 0x0f) * Math.pow(2, 48)) + (b[5] * Math.pow(2, 40)) + (b[4] * Math.pow(2, 32)) +
+							(b[3] * Math.pow(2, 24)) + (b[2] * Math.pow(2, 16)) + (b[1] * Math.pow(2, 8)) + b[0];
+		
+			if (exponent === 1024) {
+				if (mantissa !== 0) {
+					return NaN;
+				} else {
+					return sign * Infinity;
+				}
+			}
+		
+			if (exponent === -1023) { // Denormalized
+				return sign * mantissa * Math.pow(2, -1022 - 52);
+			}
+		
+			return sign * (1 + mantissa * Math.pow(2, -52)) * Math.pow(2, exponent);
+		},
+		
+		getFloat32: function (byteOffset, littleEndian) {
+			var b = this._getBytes(4, byteOffset, littleEndian),
+		
+				sign = 1 - (2 * (b[3] >> 7)),
+				exponent = (((b[3] << 1) & 0xff) | (b[2] >> 7)) - 127,
+				mantissa = ((b[2] & 0x7f) << 16) | (b[1] << 8) | b[0];
+		
+			if (exponent === 128) {
+				if (mantissa !== 0) {
+					return NaN;
+				} else {
+					return sign * Infinity;
+				}
+			}
+		
+			if (exponent === -127) { // Denormalized
+				return sign * mantissa * Math.pow(2, -126 - 23);
+			}
+		
+			return sign * (1 + mantissa * Math.pow(2, -23)) * Math.pow(2, exponent);
+		},
+		
+		getInt32: function (byteOffset, littleEndian) {
+			var b = this._getBytes(4, byteOffset, littleEndian);
+			return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
+		},
+		
+		getUint32: function (byteOffset, littleEndian) {
+			return this.getInt32(byteOffset, littleEndian) >>> 0;
+		},
+		
+		getInt16: function (byteOffset, littleEndian) {
+			return (this.getUint16(byteOffset, littleEndian) << 16) >> 16;
+		},
+		
+		getUint16: function (byteOffset, littleEndian) {
+			var b = this._getBytes(2, byteOffset, littleEndian);
+			return (b[1] << 8) | b[0];
+		},
+		
+		getInt8: function (byteOffset) {
+			return (this.getUint8(byteOffset) << 24) >> 24;
+		},
+		
+		getUint8: function (byteOffset) {
+			return this._getBytes(1, byteOffset)[0];
 		}
-
-	}
-
-};
+   };
+}