|
@@ -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);
|