Browse Source

Merge pull request #2292 from focomoso/master

Added binary stl loading
David Catuhe 8 years ago
parent
commit
810682bd8a
1 changed files with 106 additions and 10 deletions
  1. 106 10
      loaders/src/STL/babylon.stlFileLoader.ts

+ 106 - 10
loaders/src/STL/babylon.stlFileLoader.ts

@@ -9,15 +9,34 @@ module BABYLON {
         public normalPattern = /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;
         public vertexPattern = /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;
 
-        public extensions = ".stl";
+        // force data to come in as an ArrayBuffer
+        // we'll convert to string if it looks like it's an ASCII .stl
+        public extensions: ISceneLoaderPluginExtensions = {
+            ".stl": {isBinary: true},
+        };
 
         public importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]): boolean {
             var matches;
 
-            if (typeof data !== "string") {
-                Tools.Error("STL format not recognized. Ensure it's ASCII formatted");
-                return false;
+            if (this.isBinary(data)) {
+                // binary .stl
+                var babylonMesh = new Mesh("stlmesh", scene);
+                this.parseBinary(babylonMesh, data);
+                if (meshes) {
+                    meshes.push(babylonMesh);
+                }
+                return true;
+            }
+
+            // ASCII .stl
+
+            // convert to string
+            var array_buffer = new Uint8Array(data);
+            var str = '';
+            for (var i = 0; i < data.byteLength; i++) {
+                str += String.fromCharCode( array_buffer[ i ] ); // implicitly assumes little-endian
             }
+            data = str;
 
             while (matches = this.solidPattern.exec(data)) {
                 var meshName = matches[1];
@@ -42,16 +61,19 @@ module BABYLON {
 
                 // stl mesh name can be empty as well
                 meshName = meshName || "stlmesh";
-                var babylonMesh = new Mesh(meshName, scene);
-                this.parseSolid(babylonMesh, matches[2]);
 
-                meshes.push(babylonMesh);
+                var babylonMesh = new Mesh(meshName, scene);
+                this.parseASCII(babylonMesh, matches[2]);
+                if (meshes) {
+                    meshes.push(babylonMesh);
+                }
             }
 
             return true;
+
         }
 
-        public load(scene: Scene, data: string, rootUrl: string): boolean {
+        public load(scene: Scene, data: any, rootUrl: string): boolean {
             var result = this.importMesh(null, scene, data, rootUrl, null, null, null);
 
             if (result) {
@@ -61,9 +83,82 @@ module BABYLON {
             return result;
         }
 
-        private parseSolid(mesh: Mesh, solidData: string) {
-            var normals = [];
+        private isBinary (data: any) {
+
+            // check if file size is correct for binary stl
+            var faceSize, nFaces, reader;
+            reader = new DataView(data);
+            faceSize = (32 / 8 * 3) + ((32 / 8 * 3) * 3) + (16 / 8);
+            nFaces = reader.getUint32( 80, true );
+
+            if (80 + (32 / 8) + (nFaces * faceSize) === reader.byteLength) {
+                return true;
+            }
+
+            // check characters higher than ASCII to confirm binary
+            var fileLength = reader.byteLength;
+            for (var index=0; index < fileLength; index++) {
+                if (reader.getUint8( index, false ) > 127) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        private parseBinary(mesh: Mesh, data: ArrayBuffer) {
+
+            var reader = new DataView(data);
+            var faces = reader.getUint32(80, true);
+
+            var dataOffset = 84;
+            var faceLength = 12 * 4 + 2;
+
+            var offset = 0;
+
+            var positions = new Float32Array(faces * 3 * 3);
+            var normals = new Float32Array(faces * 3 * 3);
+            var indices = new Uint32Array(faces * 3);
+            var indicesCount = 0;
+
+            for (var face = 0; face < faces; face++) {
+
+                var start = dataOffset + face * faceLength;
+                var normalX = reader.getFloat32( start, true );
+                var normalY = reader.getFloat32( start + 4, true );
+                var normalZ = reader.getFloat32( start + 8, true );
+
+
+                for (var i = 1; i <= 3; i++) {
+
+                    var vertexstart = start + i * 12;
+
+                    // ordering is intentional to match ascii import
+                    positions[offset] = reader.getFloat32( vertexstart, true );
+                    positions[offset + 2] = reader.getFloat32( vertexstart + 4, true );
+                    positions[offset + 1] = reader.getFloat32( vertexstart + 8, true );
+
+                    normals[offset] = normalX;
+                    normals[offset + 2] = normalY;
+                    normals[offset + 1] = normalZ;
+
+                    offset += 3;
+                }
+                indices[indicesCount] = indicesCount++;
+                indices[indicesCount] = indicesCount++;
+                indices[indicesCount] = indicesCount++;
+            }
+
+            mesh.setVerticesData(VertexBuffer.PositionKind, positions);
+            mesh.setVerticesData(VertexBuffer.NormalKind, normals);
+            mesh.setIndices(indices);
+            mesh.computeWorldMatrix(true);
+        }
+
+        private parseASCII(mesh: Mesh, solidData: string) {
+
             var positions = [];
+            var normals = [];
             var indices = [];
             var indicesCount = 0;
 
@@ -87,6 +182,7 @@ module BABYLON {
                 indices.push(indicesCount++, indicesCount++, indicesCount++);
                 this.vertexPattern.lastIndex = 0;
             }
+
             this.facetsPattern.lastIndex = 0;
             mesh.setVerticesData(VertexBuffer.PositionKind, positions);
             mesh.setVerticesData(VertexBuffer.NormalKind, normals);