瀏覽代碼

Auto stash before merge of "master" and "origin/master"

Jean Philippe 7 年之前
父節點
當前提交
cc54e4ae50

+ 789 - 0
loaders/src/OBJ/babylon.objFileLoader.js

@@ -0,0 +1,789 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * Class reading and parsing the MTL file bundled with the obj file.
+     */
+    var MTLFileLoader = /** @class */ (function () {
+        function MTLFileLoader() {
+            // All material loaded from the mtl will be set here
+            this.materials = [];
+        }
+        /**
+         * This function will read the mtl file and create each material described inside
+         * This function could be improve by adding :
+         * -some component missing (Ni, Tf...)
+         * -including the specific options available
+         *
+         * @param scene
+         * @param data
+         * @param rootUrl
+         */
+        MTLFileLoader.prototype.parseMTL = function (scene, data, rootUrl) {
+            //Split the lines from the file
+            var lines = data.split('\n');
+            //Space char
+            var delimiter_pattern = /\s+/;
+            //Array with RGB colors
+            var color;
+            //New material
+            var material = null;
+            //Look at each line
+            for (var i = 0; i < lines.length; i++) {
+                var line = lines[i].trim();
+                // Blank line or comment
+                if (line.length === 0 || line.charAt(0) === '#') {
+                    continue;
+                }
+                //Get the first parameter (keyword)
+                var pos = line.indexOf(' ');
+                var key = (pos >= 0) ? line.substring(0, pos) : line;
+                key = key.toLowerCase();
+                //Get the data following the key
+                var value = (pos >= 0) ? line.substring(pos + 1).trim() : "";
+                //This mtl keyword will create the new material
+                if (key === "newmtl") {
+                    //Check if it is the first material.
+                    // Materials specifications are described after this keyword.
+                    if (material) {
+                        //Add the previous material in the material array.
+                        this.materials.push(material);
+                    }
+                    //Create a new material.
+                    // value is the name of the material read in the mtl file
+                    material = new BABYLON.StandardMaterial(value, scene);
+                }
+                else if (key === "kd" && material) {
+                    // Diffuse color (color under white light) using RGB values
+                    //value  = "r g b"
+                    color = value.split(delimiter_pattern, 3).map(parseFloat);
+                    //color = [r,g,b]
+                    //Set tghe color into the material
+                    material.diffuseColor = BABYLON.Color3.FromArray(color);
+                }
+                else if (key === "ka" && material) {
+                    // Ambient color (color under shadow) using RGB values
+                    //value = "r g b"
+                    color = value.split(delimiter_pattern, 3).map(parseFloat);
+                    //color = [r,g,b]
+                    //Set tghe color into the material
+                    material.ambientColor = BABYLON.Color3.FromArray(color);
+                }
+                else if (key === "ks" && material) {
+                    // Specular color (color when light is reflected from shiny surface) using RGB values
+                    //value = "r g b"
+                    color = value.split(delimiter_pattern, 3).map(parseFloat);
+                    //color = [r,g,b]
+                    //Set the color into the material
+                    material.specularColor = BABYLON.Color3.FromArray(color);
+                }
+                else if (key === "ke" && material) {
+                    // Emissive color using RGB values
+                    color = value.split(delimiter_pattern, 3).map(parseFloat);
+                    material.emissiveColor = BABYLON.Color3.FromArray(color);
+                }
+                else if (key === "ns" && material) {
+                    //value = "Integer"
+                    material.specularPower = parseFloat(value);
+                }
+                else if (key === "d" && material) {
+                    //d is dissolve for current material. It mean alpha for BABYLON
+                    material.alpha = parseFloat(value);
+                    //Texture
+                    //This part can be improved by adding the possible options of texture
+                }
+                else if (key === "map_ka" && material) {
+                    // ambient texture map with a loaded image
+                    //We must first get the folder of the image
+                    material.ambientTexture = MTLFileLoader._getTexture(rootUrl, value, scene);
+                }
+                else if (key === "map_kd" && material) {
+                    // Diffuse texture map with a loaded image
+                    material.diffuseTexture = MTLFileLoader._getTexture(rootUrl, value, scene);
+                }
+                else if (key === "map_ks" && material) {
+                    // Specular texture map with a loaded image
+                    //We must first get the folder of the image
+                    material.specularTexture = MTLFileLoader._getTexture(rootUrl, value, scene);
+                }
+                else if (key === "map_ns") {
+                    //Specular
+                    //Specular highlight component
+                    //We must first get the folder of the image
+                    //
+                    //Not supported by BABYLON
+                    //
+                    //    continue;
+                }
+                else if (key === "map_bump" && material) {
+                    //The bump texture
+                    material.bumpTexture = MTLFileLoader._getTexture(rootUrl, value, scene);
+                }
+                else if (key === "map_d" && material) {
+                    // The dissolve of the material
+                    material.opacityTexture = MTLFileLoader._getTexture(rootUrl, value, scene);
+                    //Options for illumination
+                }
+                else if (key === "illum") {
+                    //Illumination
+                    if (value === "0") {
+                        //That mean Kd == Kd
+                    }
+                    else if (value === "1") {
+                        //Color on and Ambient on
+                    }
+                    else if (value === "2") {
+                        //Highlight on
+                    }
+                    else if (value === "3") {
+                        //Reflection on and Ray trace on
+                    }
+                    else if (value === "4") {
+                        //Transparency: Glass on, Reflection: Ray trace on
+                    }
+                    else if (value === "5") {
+                        //Reflection: Fresnel on and Ray trace on
+                    }
+                    else if (value === "6") {
+                        //Transparency: Refraction on, Reflection: Fresnel off and Ray trace on
+                    }
+                    else if (value === "7") {
+                        //Transparency: Refraction on, Reflection: Fresnel on and Ray trace on
+                    }
+                    else if (value === "8") {
+                        //Reflection on and Ray trace off
+                    }
+                    else if (value === "9") {
+                        //Transparency: Glass on, Reflection: Ray trace off
+                    }
+                    else if (value === "10") {
+                        //Casts shadows onto invisible surfaces
+                    }
+                }
+                else {
+                    // console.log("Unhandled expression at line : " + i +'\n' + "with value : " + line);
+                }
+            }
+            //At the end of the file, add the last material
+            if (material) {
+                this.materials.push(material);
+            }
+        };
+        /**
+         * Gets the texture for the material.
+         *
+         * If the material is imported from input file,
+         * We sanitize the url to ensure it takes the textre from aside the material.
+         *
+         * @param rootUrl The root url to load from
+         * @param value The value stored in the mtl
+         * @return The Texture
+         */
+        MTLFileLoader._getTexture = function (rootUrl, value, scene) {
+            if (!value) {
+                return null;
+            }
+            var url = rootUrl;
+            // Load from input file.
+            if (rootUrl === "file:") {
+                var lastDelimiter = value.lastIndexOf("\\");
+                if (lastDelimiter === -1) {
+                    lastDelimiter = value.lastIndexOf("/");
+                }
+                if (lastDelimiter > -1) {
+                    url += value.substr(lastDelimiter + 1);
+                }
+                else {
+                    url += value;
+                }
+            }
+            else {
+                url += value;
+            }
+            return new BABYLON.Texture(url, scene);
+        };
+        return MTLFileLoader;
+    }());
+    BABYLON.MTLFileLoader = MTLFileLoader;
+    var OBJFileLoader = /** @class */ (function () {
+        function OBJFileLoader() {
+            this.name = "obj";
+            this.extensions = ".obj";
+            this.obj = /^o/;
+            this.group = /^g/;
+            this.mtllib = /^mtllib /;
+            this.usemtl = /^usemtl /;
+            this.smooth = /^s /;
+            this.vertexPattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
+            // vn float float float
+            this.normalPattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
+            // vt float float
+            this.uvPattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
+            // f vertex vertex vertex ...
+            this.facePattern1 = /f\s+(([\d]{1,}[\s]?){3,})+/;
+            // f vertex/uvs vertex/uvs vertex/uvs ...
+            this.facePattern2 = /f\s+((([\d]{1,}\/[\d]{1,}[\s]?){3,})+)/;
+            // f vertex/uvs/normal vertex/uvs/normal vertex/uvs/normal ...
+            this.facePattern3 = /f\s+((([\d]{1,}\/[\d]{1,}\/[\d]{1,}[\s]?){3,})+)/;
+            // f vertex//normal vertex//normal vertex//normal ...
+            this.facePattern4 = /f\s+((([\d]{1,}\/\/[\d]{1,}[\s]?){3,})+)/;
+        }
+        /**
+         * Calls synchronously the MTL file attached to this obj.
+         * Load function or importMesh function don't enable to load 2 files in the same time asynchronously.
+         * Without this function materials are not displayed in the first frame (but displayed after).
+         * In consequence it is impossible to get material information in your HTML file
+         *
+         * @param url The URL of the MTL file
+         * @param rootUrl
+         * @param onSuccess Callback function to be called when the MTL file is loaded
+         * @private
+         */
+        OBJFileLoader.prototype._loadMTL = function (url, rootUrl, onSuccess) {
+            //The complete path to the mtl file
+            var pathOfFile = BABYLON.Tools.BaseUrl + rootUrl + url;
+            // Loads through the babylon tools to allow fileInput search.
+            BABYLON.Tools.LoadFile(pathOfFile, onSuccess, undefined, undefined, false, function () { console.warn("Error - Unable to load " + pathOfFile); });
+        };
+        OBJFileLoader.prototype.importMesh = function (meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons) {
+            //get the meshes from OBJ file
+            var loadedMeshes = this._parseSolid(meshesNames, scene, data, rootUrl);
+            //Push meshes from OBJ file into the variable mesh of this function
+            if (meshes) {
+                loadedMeshes.forEach(function (mesh) {
+                    meshes.push(mesh);
+                });
+            }
+            return true;
+        };
+        OBJFileLoader.prototype.load = function (scene, data, rootUrl) {
+            //Get the 3D model
+            return this.importMesh(null, scene, data, rootUrl, null, null, null);
+        };
+        /**
+         * Read the OBJ file and create an Array of meshes.
+         * Each mesh contains all information given by the OBJ and the MTL file.
+         * i.e. vertices positions and indices, optional normals values, optional UV values, optional material
+         *
+         * @param meshesNames
+         * @param scene BABYLON.Scene The scene where are displayed the data
+         * @param data String The content of the obj file
+         * @param rootUrl String The path to the folder
+         * @returns Array<AbstractMesh>
+         * @private
+         */
+        OBJFileLoader.prototype._parseSolid = function (meshesNames, scene, data, rootUrl) {
+            var positions = []; //values for the positions of vertices
+            var normals = []; //Values for the normals
+            var uvs = []; //Values for the textures
+            var meshesFromObj = []; //[mesh] Contains all the obj meshes
+            var handledMesh; //The current mesh of meshes array
+            var indicesForBabylon = []; //The list of indices for VertexData
+            var wrappedPositionForBabylon = []; //The list of position in vectors
+            var wrappedUvsForBabylon = []; //Array with all value of uvs to match with the indices
+            var wrappedNormalsForBabylon = []; //Array with all value of normals to match with the indices
+            var tuplePosNorm = []; //Create a tuple with indice of Position, Normal, UV  [pos, norm, uvs]
+            var curPositionInIndices = 0;
+            var hasMeshes = false; //Meshes are defined in the file
+            var unwrappedPositionsForBabylon = []; //Value of positionForBabylon w/o Vector3() [x,y,z]
+            var unwrappedNormalsForBabylon = []; //Value of normalsForBabylon w/o Vector3()  [x,y,z]
+            var unwrappedUVForBabylon = []; //Value of uvsForBabylon w/o Vector3()      [x,y,z]
+            var triangles = []; //Indices from new triangles coming from polygons
+            var materialNameFromObj = ""; //The name of the current material
+            var fileToLoad = ""; //The name of the mtlFile to load
+            var materialsFromMTLFile = new MTLFileLoader();
+            var objMeshName = ""; //The name of the current obj mesh
+            var increment = 1; //Id for meshes created by the multimaterial
+            var isFirstMaterial = true;
+            /**
+             * Search for obj in the given array.
+             * This function is called to check if a couple of data already exists in an array.
+             *
+             * If found, returns the index of the founded tuple index. Returns -1 if not found
+             * @param arr Array<{ normals: Array<number>, idx: Array<number> }>
+             * @param obj Array<number>
+             * @returns {boolean}
+             */
+            var isInArray = function (arr, obj) {
+                if (!arr[obj[0]])
+                    arr[obj[0]] = { normals: [], idx: [] };
+                var idx = arr[obj[0]].normals.indexOf(obj[1]);
+                return idx === -1 ? -1 : arr[obj[0]].idx[idx];
+            };
+            var isInArrayUV = function (arr, obj) {
+                if (!arr[obj[0]])
+                    arr[obj[0]] = { normals: [], idx: [], uv: [] };
+                var idx = arr[obj[0]].normals.indexOf(obj[1]);
+                if (idx != 1 && (obj[2] == arr[obj[0]].uv[idx])) {
+                    return arr[obj[0]].idx[idx];
+                }
+                return -1;
+            };
+            /**
+             * This function set the data for each triangle.
+             * Data are position, normals and uvs
+             * If a tuple of (position, normal) is not set, add the data into the corresponding array
+             * If the tuple already exist, add only their indice
+             *
+             * @param indicePositionFromObj Integer The index in positions array
+             * @param indiceUvsFromObj Integer The index in uvs array
+             * @param indiceNormalFromObj Integer The index in normals array
+             * @param positionVectorFromOBJ Vector3 The value of position at index objIndice
+             * @param textureVectorFromOBJ Vector3 The value of uvs
+             * @param normalsVectorFromOBJ Vector3 The value of normals at index objNormale
+             */
+            var setData = function (indicePositionFromObj, indiceUvsFromObj, indiceNormalFromObj, positionVectorFromOBJ, textureVectorFromOBJ, normalsVectorFromOBJ) {
+                //Check if this tuple already exists in the list of tuples
+                var _index;
+                if (OBJFileLoader.OPTIMIZE_WITH_UV) {
+                    _index = isInArrayUV(tuplePosNorm, [
+                        indicePositionFromObj,
+                        indiceNormalFromObj,
+                        indiceUvsFromObj
+                    ]);
+                }
+                else {
+                    _index = isInArray(tuplePosNorm, [
+                        indicePositionFromObj,
+                        indiceNormalFromObj
+                    ]);
+                }
+                //If it not exists
+                if (_index == -1) {
+                    //Add an new indice.
+                    //The array of indices is only an array with his length equal to the number of triangles - 1.
+                    //We add vertices data in this order
+                    indicesForBabylon.push(wrappedPositionForBabylon.length);
+                    //Push the position of vertice for Babylon
+                    //Each element is a BABYLON.Vector3(x,y,z)
+                    wrappedPositionForBabylon.push(positionVectorFromOBJ);
+                    //Push the uvs for Babylon
+                    //Each element is a BABYLON.Vector3(u,v)
+                    wrappedUvsForBabylon.push(textureVectorFromOBJ);
+                    //Push the normals for Babylon
+                    //Each element is a BABYLON.Vector3(x,y,z)
+                    wrappedNormalsForBabylon.push(normalsVectorFromOBJ);
+                    //Add the tuple in the comparison list
+                    tuplePosNorm[indicePositionFromObj].normals.push(indiceNormalFromObj);
+                    tuplePosNorm[indicePositionFromObj].idx.push(curPositionInIndices++);
+                    if (OBJFileLoader.OPTIMIZE_WITH_UV)
+                        tuplePosNorm[indicePositionFromObj].uv.push(indiceUvsFromObj);
+                }
+                else {
+                    //The tuple already exists
+                    //Add the index of the already existing tuple
+                    //At this index we can get the value of position, normal and uvs of vertex
+                    indicesForBabylon.push(_index);
+                }
+            };
+            /**
+             * Transform BABYLON.Vector() object onto 3 digits in an array
+             */
+            var unwrapData = function () {
+                //Every array has the same length
+                for (var l = 0; l < wrappedPositionForBabylon.length; l++) {
+                    //Push the x, y, z values of each element in the unwrapped array
+                    unwrappedPositionsForBabylon.push(wrappedPositionForBabylon[l].x, wrappedPositionForBabylon[l].y, wrappedPositionForBabylon[l].z);
+                    unwrappedNormalsForBabylon.push(wrappedNormalsForBabylon[l].x, wrappedNormalsForBabylon[l].y, wrappedNormalsForBabylon[l].z);
+                    unwrappedUVForBabylon.push(wrappedUvsForBabylon[l].x, wrappedUvsForBabylon[l].y); //z is an optional value not supported by BABYLON
+                }
+                // Reset arrays for the next new meshes
+                wrappedPositionForBabylon = [];
+                wrappedNormalsForBabylon = [];
+                wrappedUvsForBabylon = [];
+                tuplePosNorm = [];
+                curPositionInIndices = 0;
+            };
+            /**
+             * Create triangles from polygons by recursion
+             * The best to understand how it works is to draw it in the same time you get the recursion.
+             * It is important to notice that a triangle is a polygon
+             * We get 4 patterns of face defined in OBJ File :
+             * facePattern1 = ["1","2","3","4","5","6"]
+             * facePattern2 = ["1/1","2/2","3/3","4/4","5/5","6/6"]
+             * facePattern3 = ["1/1/1","2/2/2","3/3/3","4/4/4","5/5/5","6/6/6"]
+             * facePattern4 = ["1//1","2//2","3//3","4//4","5//5","6//6"]
+             * Each pattern is divided by the same method
+             * @param face Array[String] The indices of elements
+             * @param v Integer The variable to increment
+             */
+            var getTriangles = function (face, v) {
+                //Work for each element of the array
+                if (v + 1 < face.length) {
+                    //Add on the triangle variable the indexes to obtain triangles
+                    triangles.push(face[0], face[v], face[v + 1]);
+                    //Incrementation for recursion
+                    v += 1;
+                    //Recursion
+                    getTriangles(face, v);
+                }
+                //Result obtained after 2 iterations:
+                //Pattern1 => triangle = ["1","2","3","1","3","4"];
+                //Pattern2 => triangle = ["1/1","2/2","3/3","1/1","3/3","4/4"];
+                //Pattern3 => triangle = ["1/1/1","2/2/2","3/3/3","1/1/1","3/3/3","4/4/4"];
+                //Pattern4 => triangle = ["1//1","2//2","3//3","1//1","3//3","4//4"];
+            };
+            /**
+             * Create triangles and push the data for each polygon for the pattern 1
+             * In this pattern we get vertice positions
+             * @param face
+             * @param v
+             */
+            var setDataForCurrentFaceWithPattern1 = function (face, v) {
+                //Get the indices of triangles for each polygon
+                getTriangles(face, v);
+                //For each element in the triangles array.
+                //This var could contains 1 to an infinity of triangles
+                for (var k = 0; k < triangles.length; k++) {
+                    // Set position indice
+                    var indicePositionFromObj = parseInt(triangles[k]) - 1;
+                    setData(indicePositionFromObj, 0, 0, //In the pattern 1, normals and uvs are not defined
+                    positions[indicePositionFromObj], //Get the vectors data
+                    BABYLON.Vector2.Zero(), BABYLON.Vector3.Up() //Create default vectors
+                    );
+                }
+                //Reset variable for the next line
+                triangles = [];
+            };
+            /**
+             * Create triangles and push the data for each polygon for the pattern 2
+             * In this pattern we get vertice positions and uvsu
+             * @param face
+             * @param v
+             */
+            var setDataForCurrentFaceWithPattern2 = function (face, v) {
+                //Get the indices of triangles for each polygon
+                getTriangles(face, v);
+                for (var k = 0; k < triangles.length; k++) {
+                    //triangle[k] = "1/1"
+                    //Split the data for getting position and uv
+                    var point = triangles[k].split("/"); // ["1", "1"]
+                    //Set position indice
+                    var indicePositionFromObj = parseInt(point[0]) - 1;
+                    //Set uv indice
+                    var indiceUvsFromObj = parseInt(point[1]) - 1;
+                    setData(indicePositionFromObj, indiceUvsFromObj, 0, //Default value for normals
+                    positions[indicePositionFromObj], //Get the values for each element
+                    uvs[indiceUvsFromObj], BABYLON.Vector3.Up() //Default value for normals
+                    );
+                }
+                //Reset variable for the next line
+                triangles = [];
+            };
+            /**
+             * Create triangles and push the data for each polygon for the pattern 3
+             * In this pattern we get vertice positions, uvs and normals
+             * @param face
+             * @param v
+             */
+            var setDataForCurrentFaceWithPattern3 = function (face, v) {
+                //Get the indices of triangles for each polygon
+                getTriangles(face, v);
+                for (var k = 0; k < triangles.length; k++) {
+                    //triangle[k] = "1/1/1"
+                    //Split the data for getting position, uv, and normals
+                    var point = triangles[k].split("/"); // ["1", "1", "1"]
+                    // Set position indice
+                    var indicePositionFromObj = parseInt(point[0]) - 1;
+                    // Set uv indice
+                    var indiceUvsFromObj = parseInt(point[1]) - 1;
+                    // Set normal indice
+                    var indiceNormalFromObj = parseInt(point[2]) - 1;
+                    setData(indicePositionFromObj, indiceUvsFromObj, indiceNormalFromObj, positions[indicePositionFromObj], uvs[indiceUvsFromObj], normals[indiceNormalFromObj] //Set the vector for each component
+                    );
+                }
+                //Reset variable for the next line
+                triangles = [];
+            };
+            /**
+             * Create triangles and push the data for each polygon for the pattern 4
+             * In this pattern we get vertice positions and normals
+             * @param face
+             * @param v
+             */
+            var setDataForCurrentFaceWithPattern4 = function (face, v) {
+                getTriangles(face, v);
+                for (var k = 0; k < triangles.length; k++) {
+                    //triangle[k] = "1//1"
+                    //Split the data for getting position and normals
+                    var point = triangles[k].split("//"); // ["1", "1"]
+                    // We check indices, and normals
+                    var indicePositionFromObj = parseInt(point[0]) - 1;
+                    var indiceNormalFromObj = parseInt(point[1]) - 1;
+                    setData(indicePositionFromObj, 1, //Default value for uv
+                    indiceNormalFromObj, positions[indicePositionFromObj], //Get each vector of data
+                    BABYLON.Vector2.Zero(), normals[indiceNormalFromObj]);
+                }
+                //Reset variable for the next line
+                triangles = [];
+            };
+            var addPreviousObjMesh = function () {
+                //Check if it is not the first mesh. Otherwise we don't have data.
+                if (meshesFromObj.length > 0) {
+                    //Get the previous mesh for applying the data about the faces
+                    //=> in obj file, faces definition append after the name of the mesh
+                    handledMesh = meshesFromObj[meshesFromObj.length - 1];
+                    //Set the data into Array for the mesh
+                    unwrapData();
+                    // Reverse tab. Otherwise face are displayed in the wrong sens
+                    indicesForBabylon.reverse();
+                    //Set the information for the mesh
+                    //Slice the array to avoid rewriting because of the fact this is the same var which be rewrited
+                    handledMesh.indices = indicesForBabylon.slice();
+                    handledMesh.positions = unwrappedPositionsForBabylon.slice();
+                    handledMesh.normals = unwrappedNormalsForBabylon.slice();
+                    handledMesh.uvs = unwrappedUVForBabylon.slice();
+                    //Reset the array for the next mesh
+                    indicesForBabylon = [];
+                    unwrappedPositionsForBabylon = [];
+                    unwrappedNormalsForBabylon = [];
+                    unwrappedUVForBabylon = [];
+                }
+            };
+            //Main function
+            //Split the file into lines
+            var lines = data.split('\n');
+            //Look at each line
+            for (var i = 0; i < lines.length; i++) {
+                var line = lines[i].trim();
+                var result;
+                //Comment or newLine
+                if (line.length === 0 || line.charAt(0) === '#') {
+                    continue;
+                    //Get information about one position possible for the vertices
+                }
+                else if ((result = this.vertexPattern.exec(line)) !== null) {
+                    //Create a Vector3 with the position x, y, z
+                    //Value of result:
+                    // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
+                    //Add the Vector in the list of positions
+                    positions.push(new BABYLON.Vector3(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3])));
+                }
+                else if ((result = this.normalPattern.exec(line)) !== null) {
+                    //Create a Vector3 with the normals x, y, z
+                    //Value of result
+                    // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
+                    //Add the Vector in the list of normals
+                    normals.push(new BABYLON.Vector3(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3])));
+                }
+                else if ((result = this.uvPattern.exec(line)) !== null) {
+                    //Create a Vector2 with the normals u, v
+                    //Value of result
+                    // ["vt 0.1 0.2 0.3", "0.1", "0.2"]
+                    //Add the Vector in the list of uvs
+                    uvs.push(new BABYLON.Vector2(parseFloat(result[1]), parseFloat(result[2])));
+                    //Identify patterns of faces
+                    //Face could be defined in different type of pattern
+                }
+                else if ((result = this.facePattern3.exec(line)) !== null) {
+                    //Value of result:
+                    //["f 1/1/1 2/2/2 3/3/3", "1/1/1 2/2/2 3/3/3"...]
+                    //Set the data for this face
+                    setDataForCurrentFaceWithPattern3(result[1].trim().split(" "), // ["1/1/1", "2/2/2", "3/3/3"]
+                    1);
+                }
+                else if ((result = this.facePattern4.exec(line)) !== null) {
+                    //Value of result:
+                    //["f 1//1 2//2 3//3", "1//1 2//2 3//3"...]
+                    //Set the data for this face
+                    setDataForCurrentFaceWithPattern4(result[1].trim().split(" "), // ["1//1", "2//2", "3//3"]
+                    1);
+                }
+                else if ((result = this.facePattern2.exec(line)) !== null) {
+                    //Value of result:
+                    //["f 1/1 2/2 3/3", "1/1 2/2 3/3"...]
+                    //Set the data for this face
+                    setDataForCurrentFaceWithPattern2(result[1].trim().split(" "), // ["1/1", "2/2", "3/3"]
+                    1);
+                }
+                else if ((result = this.facePattern1.exec(line)) !== null) {
+                    //Value of result
+                    //["f 1 2 3", "1 2 3"...]
+                    //Set the data for this face
+                    setDataForCurrentFaceWithPattern1(result[1].trim().split(" "), // ["1", "2", "3"]
+                    1);
+                    //Define a mesh or an object
+                    //Each time this keyword is analysed, create a new Object with all data for creating a babylonMesh
+                }
+                else if (this.group.test(line) || this.obj.test(line)) {
+                    //Create a new mesh corresponding to the name of the group.
+                    //Definition of the mesh
+                    var objMesh = 
+                    //Set the name of the current obj mesh
+                    {
+                        name: line.substring(2).trim(),
+                        indices: undefined,
+                        positions: undefined,
+                        normals: undefined,
+                        uvs: undefined,
+                        materialName: ""
+                    };
+                    addPreviousObjMesh();
+                    //Push the last mesh created with only the name
+                    meshesFromObj.push(objMesh);
+                    //Set this variable to indicate that now meshesFromObj has objects defined inside
+                    hasMeshes = true;
+                    isFirstMaterial = true;
+                    increment = 1;
+                    //Keyword for applying a material
+                }
+                else if (this.usemtl.test(line)) {
+                    //Get the name of the material
+                    materialNameFromObj = line.substring(7).trim();
+                    //If this new material is in the same mesh
+                    if (!isFirstMaterial) {
+                        //Set the data for the previous mesh
+                        addPreviousObjMesh();
+                        //Create a new mesh
+                        var objMesh = 
+                        //Set the name of the current obj mesh
+                        {
+                            name: objMeshName + "_mm" + increment.toString(),
+                            indices: undefined,
+                            positions: undefined,
+                            normals: undefined,
+                            uvs: undefined,
+                            materialName: materialNameFromObj
+                        };
+                        increment++;
+                        //If meshes are already defined
+                        meshesFromObj.push(objMesh);
+                    }
+                    //Set the material name if the previous line define a mesh
+                    if (hasMeshes && isFirstMaterial) {
+                        //Set the material name to the previous mesh (1 material per mesh)
+                        meshesFromObj[meshesFromObj.length - 1].materialName = materialNameFromObj;
+                        isFirstMaterial = false;
+                    }
+                    //Keyword for loading the mtl file
+                }
+                else if (this.mtllib.test(line)) {
+                    //Get the name of mtl file
+                    fileToLoad = line.substring(7).trim();
+                    //Apply smoothing
+                }
+                else if (this.smooth.test(line)) {
+                    // smooth shading => apply smoothing
+                    //Toda  y I don't know it work with babylon and with obj.
+                    //With the obj file  an integer is set
+                }
+                else {
+                    //If there is another possibility
+                    console.log("Unhandled expression at line : " + line);
+                }
+            }
+            //At the end of the file, add the last mesh into the meshesFromObj array
+            if (hasMeshes) {
+                //Set the data for the last mesh
+                handledMesh = meshesFromObj[meshesFromObj.length - 1];
+                //Reverse indices for displaying faces in the good sens
+                indicesForBabylon.reverse();
+                //Get the good array
+                unwrapData();
+                //Set array
+                handledMesh.indices = indicesForBabylon;
+                handledMesh.positions = unwrappedPositionsForBabylon;
+                handledMesh.normals = unwrappedNormalsForBabylon;
+                handledMesh.uvs = unwrappedUVForBabylon;
+            }
+            //If any o or g keyword found, create a mesj with a random id
+            if (!hasMeshes) {
+                // reverse tab of indices
+                indicesForBabylon.reverse();
+                //Get positions normals uvs
+                unwrapData();
+                //Set data for one mesh
+                meshesFromObj.push({
+                    name: BABYLON.Geometry.RandomId(),
+                    indices: indicesForBabylon,
+                    positions: unwrappedPositionsForBabylon,
+                    normals: unwrappedNormalsForBabylon,
+                    uvs: unwrappedUVForBabylon,
+                    materialName: materialNameFromObj
+                });
+            }
+            //Create a BABYLON.Mesh list
+            var babylonMeshesArray = []; //The mesh for babylon
+            var materialToUse = new Array();
+            //Set data for each mesh
+            for (var j = 0; j < meshesFromObj.length; j++) {
+                //check meshesNames (stlFileLoader)
+                if (meshesNames && meshesFromObj[j].name) {
+                    if (meshesNames instanceof Array) {
+                        if (meshesNames.indexOf(meshesFromObj[j].name) == -1) {
+                            continue;
+                        }
+                    }
+                    else {
+                        if (meshesFromObj[j].name !== meshesNames) {
+                            continue;
+                        }
+                    }
+                }
+                //Get the current mesh
+                //Set the data with VertexBuffer for each mesh
+                handledMesh = meshesFromObj[j];
+                //Create a BABYLON.Mesh with the name of the obj mesh
+                var babylonMesh = new BABYLON.Mesh(meshesFromObj[j].name, scene);
+                //Push the name of the material to an array
+                //This is indispensable for the importMesh function
+                materialToUse.push(meshesFromObj[j].materialName);
+                var vertexData = new BABYLON.VertexData(); //The container for the values
+                //Set the data for the babylonMesh
+                vertexData.positions = handledMesh.positions;
+                vertexData.normals = handledMesh.normals;
+                vertexData.uvs = handledMesh.uvs;
+                vertexData.indices = handledMesh.indices;
+                //Set the data from the VertexBuffer to the current BABYLON.Mesh
+                vertexData.applyToMesh(babylonMesh);
+                //Push the mesh into an array
+                babylonMeshesArray.push(babylonMesh);
+            }
+            //load the materials
+            //Check if we have a file to load
+            if (fileToLoad !== "") {
+                //Load the file synchronously
+                this._loadMTL(fileToLoad, rootUrl, function (dataLoaded) {
+                    //Create materials thanks MTLLoader function
+                    materialsFromMTLFile.parseMTL(scene, dataLoaded, rootUrl);
+                    //Look at each material loaded in the mtl file
+                    for (var n = 0; n < materialsFromMTLFile.materials.length; n++) {
+                        //Three variables to get all meshes with the same material
+                        var startIndex = 0;
+                        var _indices = [];
+                        var _index;
+                        //The material from MTL file is used in the meshes loaded
+                        //Push the indice in an array
+                        //Check if the material is not used for another mesh
+                        while ((_index = materialToUse.indexOf(materialsFromMTLFile.materials[n].name, startIndex)) > -1) {
+                            _indices.push(_index);
+                            startIndex = _index + 1;
+                        }
+                        //If the material is not used dispose it
+                        if (_index == -1 && _indices.length == 0) {
+                            //If the material is not needed, remove it
+                            materialsFromMTLFile.materials[n].dispose();
+                        }
+                        else {
+                            for (var o = 0; o < _indices.length; o++) {
+                                //Apply the material to the BABYLON.Mesh for each mesh with the material
+                                babylonMeshesArray[_indices[o]].material = materialsFromMTLFile.materials[n];
+                            }
+                        }
+                    }
+                });
+            }
+            //Return an array with all BABYLON.Mesh
+            return babylonMeshesArray;
+        };
+        OBJFileLoader.OPTIMIZE_WITH_UV = false;
+        return OBJFileLoader;
+    }());
+    BABYLON.OBJFileLoader = OBJFileLoader;
+    if (BABYLON.SceneLoader) {
+        //Add this loader into the register plugin
+        BABYLON.SceneLoader.RegisterPlugin(new OBJFileLoader());
+    }
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.objFileLoader.js.map

+ 164 - 0
loaders/src/STL/babylon.stlFileLoader.js

@@ -0,0 +1,164 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+var BABYLON;
+(function (BABYLON) {
+    var STLFileLoader = /** @class */ (function () {
+        function STLFileLoader() {
+            this.solidPattern = /solid (\S*)([\S\s]*)endsolid[ ]*(\S*)/g;
+            this.facetsPattern = /facet([\s\S]*?)endfacet/g;
+            this.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;
+            this.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;
+            this.name = "stl";
+            // force data to come in as an ArrayBuffer
+            // we'll convert to string if it looks like it's an ASCII .stl
+            this.extensions = {
+                ".stl": { isBinary: true },
+            };
+        }
+        STLFileLoader.prototype.importMesh = function (meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons) {
+            var matches;
+            if (this.isBinary(data)) {
+                // binary .stl
+                var babylonMesh = new BABYLON.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];
+                var meshNameFromEnd = matches[3];
+                if (meshName != meshNameFromEnd) {
+                    BABYLON.Tools.Error("Error in STL, solid name != endsolid name");
+                    return false;
+                }
+                // check meshesNames
+                if (meshesNames && meshName) {
+                    if (meshesNames instanceof Array) {
+                        if (!meshesNames.indexOf(meshName)) {
+                            continue;
+                        }
+                    }
+                    else {
+                        if (meshName !== meshesNames) {
+                            continue;
+                        }
+                    }
+                }
+                // stl mesh name can be empty as well
+                meshName = meshName || "stlmesh";
+                var babylonMesh = new BABYLON.Mesh(meshName, scene);
+                this.parseASCII(babylonMesh, matches[2]);
+                if (meshes) {
+                    meshes.push(babylonMesh);
+                }
+            }
+            return true;
+        };
+        STLFileLoader.prototype.load = function (scene, data, rootUrl) {
+            var result = this.importMesh(null, scene, data, rootUrl, null, null, null);
+            if (result) {
+                scene.createDefaultCameraOrLight();
+            }
+            return result;
+        };
+        STLFileLoader.prototype.isBinary = function (data) {
+            // 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) > 127) {
+                    return true;
+                }
+            }
+            return false;
+        };
+        STLFileLoader.prototype.parseBinary = function (mesh, data) {
+            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(BABYLON.VertexBuffer.PositionKind, positions);
+            mesh.setVerticesData(BABYLON.VertexBuffer.NormalKind, normals);
+            mesh.setIndices(indices);
+            mesh.computeWorldMatrix(true);
+        };
+        STLFileLoader.prototype.parseASCII = function (mesh, solidData) {
+            var positions = [];
+            var normals = [];
+            var indices = [];
+            var indicesCount = 0;
+            //load facets, ignoring loop as the standard doesn't define it can contain more than vertices
+            var matches;
+            while (matches = this.facetsPattern.exec(solidData)) {
+                var facet = matches[1];
+                //one normal per face
+                var normalMatches = this.normalPattern.exec(facet);
+                this.normalPattern.lastIndex = 0;
+                if (!normalMatches) {
+                    continue;
+                }
+                var normal = [Number(normalMatches[1]), Number(normalMatches[5]), Number(normalMatches[3])];
+                var vertexMatch;
+                while (vertexMatch = this.vertexPattern.exec(facet)) {
+                    positions.push(Number(vertexMatch[1]), Number(vertexMatch[5]), Number(vertexMatch[3]));
+                    normals.push(normal[0], normal[1], normal[2]);
+                }
+                indices.push(indicesCount++, indicesCount++, indicesCount++);
+                this.vertexPattern.lastIndex = 0;
+            }
+            this.facetsPattern.lastIndex = 0;
+            mesh.setVerticesData(BABYLON.VertexBuffer.PositionKind, positions);
+            mesh.setVerticesData(BABYLON.VertexBuffer.NormalKind, normals);
+            mesh.setIndices(indices);
+            mesh.computeWorldMatrix(true);
+        };
+        return STLFileLoader;
+    }());
+    BABYLON.STLFileLoader = STLFileLoader;
+    if (BABYLON.SceneLoader) {
+        BABYLON.SceneLoader.RegisterPlugin(new STLFileLoader());
+    }
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.stlFileLoader.js.map

+ 76 - 0
loaders/src/glTF/1.0/babylon.glTFBinaryExtension.js

@@ -0,0 +1,76 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var BABYLON;
+(function (BABYLON) {
+    var GLTF1;
+    (function (GLTF1) {
+        var BinaryExtensionBufferName = "binary_glTF";
+        ;
+        ;
+        var GLTFBinaryExtension = /** @class */ (function (_super) {
+            __extends(GLTFBinaryExtension, _super);
+            function GLTFBinaryExtension() {
+                return _super.call(this, "KHR_binary_glTF") || this;
+            }
+            GLTFBinaryExtension.prototype.loadRuntimeAsync = function (scene, data, rootUrl, onSuccess, onError) {
+                var extensionsUsed = data.json.extensionsUsed;
+                if (!extensionsUsed || extensionsUsed.indexOf(this.name) === -1 || !data.bin) {
+                    return false;
+                }
+                this._bin = data.bin;
+                onSuccess(GLTF1.GLTFLoaderBase.CreateRuntime(data.json, scene, rootUrl));
+                return true;
+            };
+            GLTFBinaryExtension.prototype.loadBufferAsync = function (gltfRuntime, id, onSuccess, onError) {
+                if (gltfRuntime.extensionsUsed.indexOf(this.name) === -1) {
+                    return false;
+                }
+                if (id !== BinaryExtensionBufferName) {
+                    return false;
+                }
+                onSuccess(this._bin);
+                return true;
+            };
+            GLTFBinaryExtension.prototype.loadTextureBufferAsync = function (gltfRuntime, id, onSuccess, onError) {
+                var texture = gltfRuntime.textures[id];
+                var source = gltfRuntime.images[texture.source];
+                if (!source.extensions || !(this.name in source.extensions)) {
+                    return false;
+                }
+                var sourceExt = source.extensions[this.name];
+                var bufferView = gltfRuntime.bufferViews[sourceExt.bufferView];
+                var buffer = GLTF1.GLTFUtils.GetBufferFromBufferView(gltfRuntime, bufferView, 0, bufferView.byteLength, GLTF1.EComponentType.UNSIGNED_BYTE);
+                onSuccess(buffer);
+                return true;
+            };
+            GLTFBinaryExtension.prototype.loadShaderStringAsync = function (gltfRuntime, id, onSuccess, onError) {
+                var shader = gltfRuntime.shaders[id];
+                if (!shader.extensions || !(this.name in shader.extensions)) {
+                    return false;
+                }
+                var binaryExtensionShader = shader.extensions[this.name];
+                var bufferView = gltfRuntime.bufferViews[binaryExtensionShader.bufferView];
+                var shaderBytes = GLTF1.GLTFUtils.GetBufferFromBufferView(gltfRuntime, bufferView, 0, bufferView.byteLength, GLTF1.EComponentType.UNSIGNED_BYTE);
+                setTimeout(function () {
+                    var shaderString = GLTF1.GLTFUtils.DecodeBufferToText(shaderBytes);
+                    onSuccess(shaderString);
+                });
+                return true;
+            };
+            return GLTFBinaryExtension;
+        }(GLTF1.GLTFLoaderExtension));
+        GLTF1.GLTFBinaryExtension = GLTFBinaryExtension;
+        GLTF1.GLTFLoader.RegisterExtension(new GLTFBinaryExtension());
+    })(GLTF1 = BABYLON.GLTF1 || (BABYLON.GLTF1 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.glTFBinaryExtension.js.map

文件差異過大導致無法顯示
+ 1453 - 0
loaders/src/glTF/1.0/babylon.glTFLoader.js


+ 140 - 0
loaders/src/glTF/1.0/babylon.glTFLoaderExtension.js

@@ -0,0 +1,140 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+var BABYLON;
+(function (BABYLON) {
+    var GLTF1;
+    (function (GLTF1) {
+        var GLTFLoaderExtension = /** @class */ (function () {
+            function GLTFLoaderExtension(name) {
+                this._name = name;
+            }
+            Object.defineProperty(GLTFLoaderExtension.prototype, "name", {
+                get: function () {
+                    return this._name;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            /**
+            * Defines an override for loading the runtime
+            * Return true to stop further extensions from loading the runtime
+            */
+            GLTFLoaderExtension.prototype.loadRuntimeAsync = function (scene, data, rootUrl, onSuccess, onError) {
+                return false;
+            };
+            /**
+             * Defines an onverride for creating gltf runtime
+             * Return true to stop further extensions from creating the runtime
+             */
+            GLTFLoaderExtension.prototype.loadRuntimeExtensionsAsync = function (gltfRuntime, onSuccess, onError) {
+                return false;
+            };
+            /**
+            * Defines an override for loading buffers
+            * Return true to stop further extensions from loading this buffer
+            */
+            GLTFLoaderExtension.prototype.loadBufferAsync = function (gltfRuntime, id, onSuccess, onError, onProgress) {
+                return false;
+            };
+            /**
+            * Defines an override for loading texture buffers
+            * Return true to stop further extensions from loading this texture data
+            */
+            GLTFLoaderExtension.prototype.loadTextureBufferAsync = function (gltfRuntime, id, onSuccess, onError) {
+                return false;
+            };
+            /**
+            * Defines an override for creating textures
+            * Return true to stop further extensions from loading this texture
+            */
+            GLTFLoaderExtension.prototype.createTextureAsync = function (gltfRuntime, id, buffer, onSuccess, onError) {
+                return false;
+            };
+            /**
+            * Defines an override for loading shader strings
+            * Return true to stop further extensions from loading this shader data
+            */
+            GLTFLoaderExtension.prototype.loadShaderStringAsync = function (gltfRuntime, id, onSuccess, onError) {
+                return false;
+            };
+            /**
+            * Defines an override for loading materials
+            * Return true to stop further extensions from loading this material
+            */
+            GLTFLoaderExtension.prototype.loadMaterialAsync = function (gltfRuntime, id, onSuccess, onError) {
+                return false;
+            };
+            // ---------
+            // Utilities
+            // ---------
+            GLTFLoaderExtension.LoadRuntimeAsync = function (scene, data, rootUrl, onSuccess, onError) {
+                GLTFLoaderExtension.ApplyExtensions(function (loaderExtension) {
+                    return loaderExtension.loadRuntimeAsync(scene, data, rootUrl, onSuccess, onError);
+                }, function () {
+                    setTimeout(function () {
+                        onSuccess(GLTF1.GLTFLoaderBase.CreateRuntime(data.json, scene, rootUrl));
+                    });
+                });
+            };
+            GLTFLoaderExtension.LoadRuntimeExtensionsAsync = function (gltfRuntime, onSuccess, onError) {
+                GLTFLoaderExtension.ApplyExtensions(function (loaderExtension) {
+                    return loaderExtension.loadRuntimeExtensionsAsync(gltfRuntime, onSuccess, onError);
+                }, function () {
+                    setTimeout(function () {
+                        onSuccess();
+                    });
+                });
+            };
+            GLTFLoaderExtension.LoadBufferAsync = function (gltfRuntime, id, onSuccess, onError, onProgress) {
+                GLTFLoaderExtension.ApplyExtensions(function (loaderExtension) {
+                    return loaderExtension.loadBufferAsync(gltfRuntime, id, onSuccess, onError, onProgress);
+                }, function () {
+                    GLTF1.GLTFLoaderBase.LoadBufferAsync(gltfRuntime, id, onSuccess, onError, onProgress);
+                });
+            };
+            GLTFLoaderExtension.LoadTextureAsync = function (gltfRuntime, id, onSuccess, onError) {
+                GLTFLoaderExtension.LoadTextureBufferAsync(gltfRuntime, id, function (buffer) { return GLTFLoaderExtension.CreateTextureAsync(gltfRuntime, id, buffer, onSuccess, onError); }, onError);
+            };
+            GLTFLoaderExtension.LoadShaderStringAsync = function (gltfRuntime, id, onSuccess, onError) {
+                GLTFLoaderExtension.ApplyExtensions(function (loaderExtension) {
+                    return loaderExtension.loadShaderStringAsync(gltfRuntime, id, onSuccess, onError);
+                }, function () {
+                    GLTF1.GLTFLoaderBase.LoadShaderStringAsync(gltfRuntime, id, onSuccess, onError);
+                });
+            };
+            GLTFLoaderExtension.LoadMaterialAsync = function (gltfRuntime, id, onSuccess, onError) {
+                GLTFLoaderExtension.ApplyExtensions(function (loaderExtension) {
+                    return loaderExtension.loadMaterialAsync(gltfRuntime, id, onSuccess, onError);
+                }, function () {
+                    GLTF1.GLTFLoaderBase.LoadMaterialAsync(gltfRuntime, id, onSuccess, onError);
+                });
+            };
+            GLTFLoaderExtension.LoadTextureBufferAsync = function (gltfRuntime, id, onSuccess, onError) {
+                GLTFLoaderExtension.ApplyExtensions(function (loaderExtension) {
+                    return loaderExtension.loadTextureBufferAsync(gltfRuntime, id, onSuccess, onError);
+                }, function () {
+                    GLTF1.GLTFLoaderBase.LoadTextureBufferAsync(gltfRuntime, id, onSuccess, onError);
+                });
+            };
+            GLTFLoaderExtension.CreateTextureAsync = function (gltfRuntime, id, buffer, onSuccess, onError) {
+                GLTFLoaderExtension.ApplyExtensions(function (loaderExtension) {
+                    return loaderExtension.createTextureAsync(gltfRuntime, id, buffer, onSuccess, onError);
+                }, function () {
+                    GLTF1.GLTFLoaderBase.CreateTextureAsync(gltfRuntime, id, buffer, onSuccess, onError);
+                });
+            };
+            GLTFLoaderExtension.ApplyExtensions = function (func, defaultFunc) {
+                for (var extensionName in GLTF1.GLTFLoader.Extensions) {
+                    var loaderExtension = GLTF1.GLTFLoader.Extensions[extensionName];
+                    if (func(loaderExtension)) {
+                        return;
+                    }
+                }
+                defaultFunc();
+            };
+            return GLTFLoaderExtension;
+        }());
+        GLTF1.GLTFLoaderExtension = GLTFLoaderExtension;
+    })(GLTF1 = BABYLON.GLTF1 || (BABYLON.GLTF1 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.glTFLoaderExtension.js.map

+ 96 - 0
loaders/src/glTF/1.0/babylon.glTFLoaderInterfaces.js

@@ -0,0 +1,96 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+var BABYLON;
+(function (BABYLON) {
+    var GLTF1;
+    (function (GLTF1) {
+        /**
+        * Enums
+        */
+        var EComponentType;
+        (function (EComponentType) {
+            EComponentType[EComponentType["BYTE"] = 5120] = "BYTE";
+            EComponentType[EComponentType["UNSIGNED_BYTE"] = 5121] = "UNSIGNED_BYTE";
+            EComponentType[EComponentType["SHORT"] = 5122] = "SHORT";
+            EComponentType[EComponentType["UNSIGNED_SHORT"] = 5123] = "UNSIGNED_SHORT";
+            EComponentType[EComponentType["FLOAT"] = 5126] = "FLOAT";
+        })(EComponentType = GLTF1.EComponentType || (GLTF1.EComponentType = {}));
+        var EShaderType;
+        (function (EShaderType) {
+            EShaderType[EShaderType["FRAGMENT"] = 35632] = "FRAGMENT";
+            EShaderType[EShaderType["VERTEX"] = 35633] = "VERTEX";
+        })(EShaderType = GLTF1.EShaderType || (GLTF1.EShaderType = {}));
+        var EParameterType;
+        (function (EParameterType) {
+            EParameterType[EParameterType["BYTE"] = 5120] = "BYTE";
+            EParameterType[EParameterType["UNSIGNED_BYTE"] = 5121] = "UNSIGNED_BYTE";
+            EParameterType[EParameterType["SHORT"] = 5122] = "SHORT";
+            EParameterType[EParameterType["UNSIGNED_SHORT"] = 5123] = "UNSIGNED_SHORT";
+            EParameterType[EParameterType["INT"] = 5124] = "INT";
+            EParameterType[EParameterType["UNSIGNED_INT"] = 5125] = "UNSIGNED_INT";
+            EParameterType[EParameterType["FLOAT"] = 5126] = "FLOAT";
+            EParameterType[EParameterType["FLOAT_VEC2"] = 35664] = "FLOAT_VEC2";
+            EParameterType[EParameterType["FLOAT_VEC3"] = 35665] = "FLOAT_VEC3";
+            EParameterType[EParameterType["FLOAT_VEC4"] = 35666] = "FLOAT_VEC4";
+            EParameterType[EParameterType["INT_VEC2"] = 35667] = "INT_VEC2";
+            EParameterType[EParameterType["INT_VEC3"] = 35668] = "INT_VEC3";
+            EParameterType[EParameterType["INT_VEC4"] = 35669] = "INT_VEC4";
+            EParameterType[EParameterType["BOOL"] = 35670] = "BOOL";
+            EParameterType[EParameterType["BOOL_VEC2"] = 35671] = "BOOL_VEC2";
+            EParameterType[EParameterType["BOOL_VEC3"] = 35672] = "BOOL_VEC3";
+            EParameterType[EParameterType["BOOL_VEC4"] = 35673] = "BOOL_VEC4";
+            EParameterType[EParameterType["FLOAT_MAT2"] = 35674] = "FLOAT_MAT2";
+            EParameterType[EParameterType["FLOAT_MAT3"] = 35675] = "FLOAT_MAT3";
+            EParameterType[EParameterType["FLOAT_MAT4"] = 35676] = "FLOAT_MAT4";
+            EParameterType[EParameterType["SAMPLER_2D"] = 35678] = "SAMPLER_2D";
+        })(EParameterType = GLTF1.EParameterType || (GLTF1.EParameterType = {}));
+        var ETextureWrapMode;
+        (function (ETextureWrapMode) {
+            ETextureWrapMode[ETextureWrapMode["CLAMP_TO_EDGE"] = 33071] = "CLAMP_TO_EDGE";
+            ETextureWrapMode[ETextureWrapMode["MIRRORED_REPEAT"] = 33648] = "MIRRORED_REPEAT";
+            ETextureWrapMode[ETextureWrapMode["REPEAT"] = 10497] = "REPEAT";
+        })(ETextureWrapMode = GLTF1.ETextureWrapMode || (GLTF1.ETextureWrapMode = {}));
+        var ETextureFilterType;
+        (function (ETextureFilterType) {
+            ETextureFilterType[ETextureFilterType["NEAREST"] = 9728] = "NEAREST";
+            ETextureFilterType[ETextureFilterType["LINEAR"] = 9728] = "LINEAR";
+            ETextureFilterType[ETextureFilterType["NEAREST_MIPMAP_NEAREST"] = 9984] = "NEAREST_MIPMAP_NEAREST";
+            ETextureFilterType[ETextureFilterType["LINEAR_MIPMAP_NEAREST"] = 9985] = "LINEAR_MIPMAP_NEAREST";
+            ETextureFilterType[ETextureFilterType["NEAREST_MIPMAP_LINEAR"] = 9986] = "NEAREST_MIPMAP_LINEAR";
+            ETextureFilterType[ETextureFilterType["LINEAR_MIPMAP_LINEAR"] = 9987] = "LINEAR_MIPMAP_LINEAR";
+        })(ETextureFilterType = GLTF1.ETextureFilterType || (GLTF1.ETextureFilterType = {}));
+        var ETextureFormat;
+        (function (ETextureFormat) {
+            ETextureFormat[ETextureFormat["ALPHA"] = 6406] = "ALPHA";
+            ETextureFormat[ETextureFormat["RGB"] = 6407] = "RGB";
+            ETextureFormat[ETextureFormat["RGBA"] = 6408] = "RGBA";
+            ETextureFormat[ETextureFormat["LUMINANCE"] = 6409] = "LUMINANCE";
+            ETextureFormat[ETextureFormat["LUMINANCE_ALPHA"] = 6410] = "LUMINANCE_ALPHA";
+        })(ETextureFormat = GLTF1.ETextureFormat || (GLTF1.ETextureFormat = {}));
+        var ECullingType;
+        (function (ECullingType) {
+            ECullingType[ECullingType["FRONT"] = 1028] = "FRONT";
+            ECullingType[ECullingType["BACK"] = 1029] = "BACK";
+            ECullingType[ECullingType["FRONT_AND_BACK"] = 1032] = "FRONT_AND_BACK";
+        })(ECullingType = GLTF1.ECullingType || (GLTF1.ECullingType = {}));
+        var EBlendingFunction;
+        (function (EBlendingFunction) {
+            EBlendingFunction[EBlendingFunction["ZERO"] = 0] = "ZERO";
+            EBlendingFunction[EBlendingFunction["ONE"] = 1] = "ONE";
+            EBlendingFunction[EBlendingFunction["SRC_COLOR"] = 768] = "SRC_COLOR";
+            EBlendingFunction[EBlendingFunction["ONE_MINUS_SRC_COLOR"] = 769] = "ONE_MINUS_SRC_COLOR";
+            EBlendingFunction[EBlendingFunction["DST_COLOR"] = 774] = "DST_COLOR";
+            EBlendingFunction[EBlendingFunction["ONE_MINUS_DST_COLOR"] = 775] = "ONE_MINUS_DST_COLOR";
+            EBlendingFunction[EBlendingFunction["SRC_ALPHA"] = 770] = "SRC_ALPHA";
+            EBlendingFunction[EBlendingFunction["ONE_MINUS_SRC_ALPHA"] = 771] = "ONE_MINUS_SRC_ALPHA";
+            EBlendingFunction[EBlendingFunction["DST_ALPHA"] = 772] = "DST_ALPHA";
+            EBlendingFunction[EBlendingFunction["ONE_MINUS_DST_ALPHA"] = 773] = "ONE_MINUS_DST_ALPHA";
+            EBlendingFunction[EBlendingFunction["CONSTANT_COLOR"] = 32769] = "CONSTANT_COLOR";
+            EBlendingFunction[EBlendingFunction["ONE_MINUS_CONSTANT_COLOR"] = 32770] = "ONE_MINUS_CONSTANT_COLOR";
+            EBlendingFunction[EBlendingFunction["CONSTANT_ALPHA"] = 32771] = "CONSTANT_ALPHA";
+            EBlendingFunction[EBlendingFunction["ONE_MINUS_CONSTANT_ALPHA"] = 32772] = "ONE_MINUS_CONSTANT_ALPHA";
+            EBlendingFunction[EBlendingFunction["SRC_ALPHA_SATURATE"] = 776] = "SRC_ALPHA_SATURATE";
+        })(EBlendingFunction = GLTF1.EBlendingFunction || (GLTF1.EBlendingFunction = {}));
+    })(GLTF1 = BABYLON.GLTF1 || (BABYLON.GLTF1 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.glTFLoaderInterfaces.js.map

+ 254 - 0
loaders/src/glTF/1.0/babylon.glTFLoaderUtils.js

@@ -0,0 +1,254 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+var BABYLON;
+(function (BABYLON) {
+    var GLTF1;
+    (function (GLTF1) {
+        /**
+        * Utils functions for GLTF
+        */
+        var GLTFUtils = /** @class */ (function () {
+            function GLTFUtils() {
+            }
+            /**
+             * Sets the given "parameter" matrix
+             * @param scene: the {BABYLON.Scene} object
+             * @param source: the source node where to pick the matrix
+             * @param parameter: the GLTF technique parameter
+             * @param uniformName: the name of the shader's uniform
+             * @param shaderMaterial: the shader material
+             */
+            GLTFUtils.SetMatrix = function (scene, source, parameter, uniformName, shaderMaterial) {
+                var mat = null;
+                if (parameter.semantic === "MODEL") {
+                    mat = source.getWorldMatrix();
+                }
+                else if (parameter.semantic === "PROJECTION") {
+                    mat = scene.getProjectionMatrix();
+                }
+                else if (parameter.semantic === "VIEW") {
+                    mat = scene.getViewMatrix();
+                }
+                else if (parameter.semantic === "MODELVIEWINVERSETRANSPOSE") {
+                    mat = BABYLON.Matrix.Transpose(source.getWorldMatrix().multiply(scene.getViewMatrix()).invert());
+                }
+                else if (parameter.semantic === "MODELVIEW") {
+                    mat = source.getWorldMatrix().multiply(scene.getViewMatrix());
+                }
+                else if (parameter.semantic === "MODELVIEWPROJECTION") {
+                    mat = source.getWorldMatrix().multiply(scene.getTransformMatrix());
+                }
+                else if (parameter.semantic === "MODELINVERSE") {
+                    mat = source.getWorldMatrix().invert();
+                }
+                else if (parameter.semantic === "VIEWINVERSE") {
+                    mat = scene.getViewMatrix().invert();
+                }
+                else if (parameter.semantic === "PROJECTIONINVERSE") {
+                    mat = scene.getProjectionMatrix().invert();
+                }
+                else if (parameter.semantic === "MODELVIEWINVERSE") {
+                    mat = source.getWorldMatrix().multiply(scene.getViewMatrix()).invert();
+                }
+                else if (parameter.semantic === "MODELVIEWPROJECTIONINVERSE") {
+                    mat = source.getWorldMatrix().multiply(scene.getTransformMatrix()).invert();
+                }
+                else if (parameter.semantic === "MODELINVERSETRANSPOSE") {
+                    mat = BABYLON.Matrix.Transpose(source.getWorldMatrix().invert());
+                }
+                else {
+                    debugger;
+                }
+                if (mat) {
+                    switch (parameter.type) {
+                        case GLTF1.EParameterType.FLOAT_MAT2:
+                            shaderMaterial.setMatrix2x2(uniformName, BABYLON.Matrix.GetAsMatrix2x2(mat));
+                            break;
+                        case GLTF1.EParameterType.FLOAT_MAT3:
+                            shaderMaterial.setMatrix3x3(uniformName, BABYLON.Matrix.GetAsMatrix3x3(mat));
+                            break;
+                        case GLTF1.EParameterType.FLOAT_MAT4:
+                            shaderMaterial.setMatrix(uniformName, mat);
+                            break;
+                        default: break;
+                    }
+                }
+            };
+            /**
+             * Sets the given "parameter" matrix
+             * @param shaderMaterial: the shader material
+             * @param uniform: the name of the shader's uniform
+             * @param value: the value of the uniform
+             * @param type: the uniform's type (EParameterType FLOAT, VEC2, VEC3 or VEC4)
+             */
+            GLTFUtils.SetUniform = function (shaderMaterial, uniform, value, type) {
+                switch (type) {
+                    case GLTF1.EParameterType.FLOAT:
+                        shaderMaterial.setFloat(uniform, value);
+                        return true;
+                    case GLTF1.EParameterType.FLOAT_VEC2:
+                        shaderMaterial.setVector2(uniform, BABYLON.Vector2.FromArray(value));
+                        return true;
+                    case GLTF1.EParameterType.FLOAT_VEC3:
+                        shaderMaterial.setVector3(uniform, BABYLON.Vector3.FromArray(value));
+                        return true;
+                    case GLTF1.EParameterType.FLOAT_VEC4:
+                        shaderMaterial.setVector4(uniform, BABYLON.Vector4.FromArray(value));
+                        return true;
+                    default: return false;
+                }
+            };
+            /**
+            * If the uri is a base64 string
+            * @param uri: the uri to test
+            */
+            GLTFUtils.IsBase64 = function (uri) {
+                return uri.length < 5 ? false : uri.substr(0, 5) === "data:";
+            };
+            /**
+            * Decode the base64 uri
+            * @param uri: the uri to decode
+            */
+            GLTFUtils.DecodeBase64 = function (uri) {
+                var decodedString = atob(uri.split(",")[1]);
+                var bufferLength = decodedString.length;
+                var bufferView = new Uint8Array(new ArrayBuffer(bufferLength));
+                for (var i = 0; i < bufferLength; i++) {
+                    bufferView[i] = decodedString.charCodeAt(i);
+                }
+                return bufferView.buffer;
+            };
+            /**
+            * Returns the wrap mode of the texture
+            * @param mode: the mode value
+            */
+            GLTFUtils.GetWrapMode = function (mode) {
+                switch (mode) {
+                    case GLTF1.ETextureWrapMode.CLAMP_TO_EDGE: return BABYLON.Texture.CLAMP_ADDRESSMODE;
+                    case GLTF1.ETextureWrapMode.MIRRORED_REPEAT: return BABYLON.Texture.MIRROR_ADDRESSMODE;
+                    case GLTF1.ETextureWrapMode.REPEAT: return BABYLON.Texture.WRAP_ADDRESSMODE;
+                    default: return BABYLON.Texture.WRAP_ADDRESSMODE;
+                }
+            };
+            /**
+             * Returns the byte stride giving an accessor
+             * @param accessor: the GLTF accessor objet
+             */
+            GLTFUtils.GetByteStrideFromType = function (accessor) {
+                // Needs this function since "byteStride" isn't requiered in glTF format
+                var type = accessor.type;
+                switch (type) {
+                    case "VEC2": return 2;
+                    case "VEC3": return 3;
+                    case "VEC4": return 4;
+                    case "MAT2": return 4;
+                    case "MAT3": return 9;
+                    case "MAT4": return 16;
+                    default: return 1;
+                }
+            };
+            /**
+             * Returns the texture filter mode giving a mode value
+             * @param mode: the filter mode value
+             */
+            GLTFUtils.GetTextureFilterMode = function (mode) {
+                switch (mode) {
+                    case GLTF1.ETextureFilterType.LINEAR:
+                    case GLTF1.ETextureFilterType.LINEAR_MIPMAP_NEAREST:
+                    case GLTF1.ETextureFilterType.LINEAR_MIPMAP_LINEAR: return BABYLON.Texture.TRILINEAR_SAMPLINGMODE;
+                    case GLTF1.ETextureFilterType.NEAREST:
+                    case GLTF1.ETextureFilterType.NEAREST_MIPMAP_NEAREST: return BABYLON.Texture.NEAREST_SAMPLINGMODE;
+                    default: return BABYLON.Texture.BILINEAR_SAMPLINGMODE;
+                }
+            };
+            GLTFUtils.GetBufferFromBufferView = function (gltfRuntime, bufferView, byteOffset, byteLength, componentType) {
+                var byteOffset = bufferView.byteOffset + byteOffset;
+                var loadedBufferView = gltfRuntime.loadedBufferViews[bufferView.buffer];
+                if (byteOffset + byteLength > loadedBufferView.byteLength) {
+                    throw new Error("Buffer access is out of range");
+                }
+                var buffer = loadedBufferView.buffer;
+                byteOffset += loadedBufferView.byteOffset;
+                switch (componentType) {
+                    case GLTF1.EComponentType.BYTE: return new Int8Array(buffer, byteOffset, byteLength);
+                    case GLTF1.EComponentType.UNSIGNED_BYTE: return new Uint8Array(buffer, byteOffset, byteLength);
+                    case GLTF1.EComponentType.SHORT: return new Int16Array(buffer, byteOffset, byteLength);
+                    case GLTF1.EComponentType.UNSIGNED_SHORT: return new Uint16Array(buffer, byteOffset, byteLength);
+                    default: return new Float32Array(buffer, byteOffset, byteLength);
+                }
+            };
+            /**
+             * Returns a buffer from its accessor
+             * @param gltfRuntime: the GLTF runtime
+             * @param accessor: the GLTF accessor
+             */
+            GLTFUtils.GetBufferFromAccessor = function (gltfRuntime, accessor) {
+                var bufferView = gltfRuntime.bufferViews[accessor.bufferView];
+                var byteLength = accessor.count * GLTFUtils.GetByteStrideFromType(accessor);
+                return GLTFUtils.GetBufferFromBufferView(gltfRuntime, bufferView, accessor.byteOffset, byteLength, accessor.componentType);
+            };
+            /**
+             * Decodes a buffer view into a string
+             * @param view: the buffer view
+             */
+            GLTFUtils.DecodeBufferToText = function (view) {
+                var result = "";
+                var length = view.byteLength;
+                for (var i = 0; i < length; ++i) {
+                    result += String.fromCharCode(view[i]);
+                }
+                return result;
+            };
+            /**
+             * Returns the default material of gltf. Related to
+             * https://github.com/KhronosGroup/glTF/tree/master/specification/1.0#appendix-a-default-material
+             * @param scene: the Babylon.js scene
+             */
+            GLTFUtils.GetDefaultMaterial = function (scene) {
+                if (!GLTFUtils._DefaultMaterial) {
+                    BABYLON.Effect.ShadersStore["GLTFDefaultMaterialVertexShader"] = [
+                        "precision highp float;",
+                        "",
+                        "uniform mat4 worldView;",
+                        "uniform mat4 projection;",
+                        "",
+                        "attribute vec3 position;",
+                        "",
+                        "void main(void)",
+                        "{",
+                        "    gl_Position = projection * worldView * vec4(position, 1.0);",
+                        "}"
+                    ].join("\n");
+                    BABYLON.Effect.ShadersStore["GLTFDefaultMaterialPixelShader"] = [
+                        "precision highp float;",
+                        "",
+                        "uniform vec4 u_emission;",
+                        "",
+                        "void main(void)",
+                        "{",
+                        "    gl_FragColor = u_emission;",
+                        "}"
+                    ].join("\n");
+                    var shaderPath = {
+                        vertex: "GLTFDefaultMaterial",
+                        fragment: "GLTFDefaultMaterial"
+                    };
+                    var options = {
+                        attributes: ["position"],
+                        uniforms: ["worldView", "projection", "u_emission"],
+                        samplers: new Array(),
+                        needAlphaBlending: false
+                    };
+                    GLTFUtils._DefaultMaterial = new BABYLON.ShaderMaterial("GLTFDefaultMaterial", scene, shaderPath, options);
+                    GLTFUtils._DefaultMaterial.setColor4("u_emission", new BABYLON.Color4(0.5, 0.5, 0.5, 1.0));
+                }
+                return GLTFUtils._DefaultMaterial;
+            };
+            // The GLTF default material
+            GLTFUtils._DefaultMaterial = null;
+            return GLTFUtils;
+        }());
+        GLTF1.GLTFUtils = GLTFUtils;
+    })(GLTF1 = BABYLON.GLTF1 || (BABYLON.GLTF1 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.glTFLoaderUtils.js.map

+ 131 - 0
loaders/src/glTF/1.0/babylon.glTFMaterialsCommonExtension.js

@@ -0,0 +1,131 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var BABYLON;
+(function (BABYLON) {
+    var GLTF1;
+    (function (GLTF1) {
+        ;
+        ;
+        ;
+        var GLTFMaterialsCommonExtension = /** @class */ (function (_super) {
+            __extends(GLTFMaterialsCommonExtension, _super);
+            function GLTFMaterialsCommonExtension() {
+                return _super.call(this, "KHR_materials_common") || this;
+            }
+            GLTFMaterialsCommonExtension.prototype.loadRuntimeExtensionsAsync = function (gltfRuntime, onSuccess, onError) {
+                if (!gltfRuntime.extensions)
+                    return false;
+                var extension = gltfRuntime.extensions[this.name];
+                if (!extension)
+                    return false;
+                // Create lights
+                var lights = extension.lights;
+                if (lights) {
+                    for (var thing in lights) {
+                        var light = lights[thing];
+                        switch (light.type) {
+                            case "ambient":
+                                var ambientLight = new BABYLON.HemisphericLight(light.name, new BABYLON.Vector3(0, 1, 0), gltfRuntime.scene);
+                                var ambient = light.ambient;
+                                if (ambient) {
+                                    ambientLight.diffuse = BABYLON.Color3.FromArray(ambient.color || [1, 1, 1]);
+                                }
+                                break;
+                            case "point":
+                                var pointLight = new BABYLON.PointLight(light.name, new BABYLON.Vector3(10, 10, 10), gltfRuntime.scene);
+                                var point = light.point;
+                                if (point) {
+                                    pointLight.diffuse = BABYLON.Color3.FromArray(point.color || [1, 1, 1]);
+                                }
+                                break;
+                            case "directional":
+                                var dirLight = new BABYLON.DirectionalLight(light.name, new BABYLON.Vector3(0, -1, 0), gltfRuntime.scene);
+                                var directional = light.directional;
+                                if (directional) {
+                                    dirLight.diffuse = BABYLON.Color3.FromArray(directional.color || [1, 1, 1]);
+                                }
+                                break;
+                            case "spot":
+                                var spot = light.spot;
+                                if (spot) {
+                                    var spotLight = new BABYLON.SpotLight(light.name, new BABYLON.Vector3(0, 10, 0), new BABYLON.Vector3(0, -1, 0), spot.fallOffAngle || Math.PI, spot.fallOffExponent || 0.0, gltfRuntime.scene);
+                                    spotLight.diffuse = BABYLON.Color3.FromArray(spot.color || [1, 1, 1]);
+                                }
+                                break;
+                            default:
+                                BABYLON.Tools.Warn("GLTF Material Common extension: light type \"" + light.type + "\” not supported");
+                                break;
+                        }
+                    }
+                }
+                return false;
+            };
+            GLTFMaterialsCommonExtension.prototype.loadMaterialAsync = function (gltfRuntime, id, onSuccess, onError) {
+                var material = gltfRuntime.materials[id];
+                if (!material || !material.extensions)
+                    return false;
+                var extension = material.extensions[this.name];
+                if (!extension)
+                    return false;
+                var standardMaterial = new BABYLON.StandardMaterial(id, gltfRuntime.scene);
+                standardMaterial.sideOrientation = BABYLON.Material.CounterClockWiseSideOrientation;
+                if (extension.technique === "CONSTANT") {
+                    standardMaterial.disableLighting = true;
+                }
+                standardMaterial.backFaceCulling = extension.doubleSided === undefined ? false : !extension.doubleSided;
+                standardMaterial.alpha = extension.values.transparency === undefined ? 1.0 : extension.values.transparency;
+                standardMaterial.specularPower = extension.values.shininess === undefined ? 0.0 : extension.values.shininess;
+                // Ambient
+                if (typeof extension.values.ambient === "string") {
+                    this._loadTexture(gltfRuntime, extension.values.ambient, standardMaterial, "ambientTexture", onError);
+                }
+                else {
+                    standardMaterial.ambientColor = BABYLON.Color3.FromArray(extension.values.ambient || [0, 0, 0]);
+                }
+                // Diffuse
+                if (typeof extension.values.diffuse === "string") {
+                    this._loadTexture(gltfRuntime, extension.values.diffuse, standardMaterial, "diffuseTexture", onError);
+                }
+                else {
+                    standardMaterial.diffuseColor = BABYLON.Color3.FromArray(extension.values.diffuse || [0, 0, 0]);
+                }
+                // Emission
+                if (typeof extension.values.emission === "string") {
+                    this._loadTexture(gltfRuntime, extension.values.emission, standardMaterial, "emissiveTexture", onError);
+                }
+                else {
+                    standardMaterial.emissiveColor = BABYLON.Color3.FromArray(extension.values.emission || [0, 0, 0]);
+                }
+                // Specular
+                if (typeof extension.values.specular === "string") {
+                    this._loadTexture(gltfRuntime, extension.values.specular, standardMaterial, "specularTexture", onError);
+                }
+                else {
+                    standardMaterial.specularColor = BABYLON.Color3.FromArray(extension.values.specular || [0, 0, 0]);
+                }
+                return true;
+            };
+            GLTFMaterialsCommonExtension.prototype._loadTexture = function (gltfRuntime, id, material, propertyPath, onError) {
+                // Create buffer from texture url
+                GLTF1.GLTFLoaderBase.LoadTextureBufferAsync(gltfRuntime, id, function (buffer) {
+                    // Create texture from buffer
+                    GLTF1.GLTFLoaderBase.CreateTextureAsync(gltfRuntime, id, buffer, function (texture) { return material[propertyPath] = texture; }, onError);
+                }, onError);
+            };
+            return GLTFMaterialsCommonExtension;
+        }(GLTF1.GLTFLoaderExtension));
+        GLTF1.GLTFMaterialsCommonExtension = GLTFMaterialsCommonExtension;
+        GLTF1.GLTFLoader.RegisterExtension(new GLTFMaterialsCommonExtension());
+    })(GLTF1 = BABYLON.GLTF1 || (BABYLON.GLTF1 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.glTFMaterialsCommonExtension.js.map

+ 71 - 0
loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.js

@@ -0,0 +1,71 @@
+/// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        var Extensions;
+        (function (Extensions) {
+            var KHRMaterialsPbrSpecularGlossiness = /** @class */ (function (_super) {
+                __extends(KHRMaterialsPbrSpecularGlossiness, _super);
+                function KHRMaterialsPbrSpecularGlossiness() {
+                    return _super !== null && _super.apply(this, arguments) || this;
+                }
+                Object.defineProperty(KHRMaterialsPbrSpecularGlossiness.prototype, "name", {
+                    get: function () {
+                        return "KHR_materials_pbrSpecularGlossiness";
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                KHRMaterialsPbrSpecularGlossiness.prototype._loadMaterial = function (loader, context, material, assign) {
+                    var _this = this;
+                    return this._loadExtension(context, material, function (context, extension, onComplete) {
+                        loader._createPbrMaterial(material);
+                        loader._loadMaterialBaseProperties(context, material);
+                        _this._loadSpecularGlossinessProperties(loader, context, material, extension);
+                        assign(material.babylonMaterial, true);
+                        onComplete();
+                    });
+                };
+                KHRMaterialsPbrSpecularGlossiness.prototype._loadSpecularGlossinessProperties = function (loader, context, material, properties) {
+                    var babylonMaterial = material.babylonMaterial;
+                    babylonMaterial.albedoColor = properties.diffuseFactor ? BABYLON.Color3.FromArray(properties.diffuseFactor) : new BABYLON.Color3(1, 1, 1);
+                    babylonMaterial.reflectivityColor = properties.specularFactor ? BABYLON.Color3.FromArray(properties.specularFactor) : new BABYLON.Color3(1, 1, 1);
+                    babylonMaterial.microSurface = properties.glossinessFactor == null ? 1 : properties.glossinessFactor;
+                    if (properties.diffuseTexture) {
+                        var texture = GLTF2.GLTFLoader._GetProperty(loader._gltf.textures, properties.diffuseTexture.index);
+                        if (!texture) {
+                            throw new Error(context + ": Failed to find diffuse texture " + properties.diffuseTexture.index);
+                        }
+                        babylonMaterial.albedoTexture = loader._loadTexture("textures[" + texture.index + "]", texture, properties.diffuseTexture.texCoord);
+                    }
+                    if (properties.specularGlossinessTexture) {
+                        var texture = GLTF2.GLTFLoader._GetProperty(loader._gltf.textures, properties.specularGlossinessTexture.index);
+                        if (!texture) {
+                            throw new Error(context + ": Failed to find diffuse texture " + properties.specularGlossinessTexture.index);
+                        }
+                        babylonMaterial.reflectivityTexture = loader._loadTexture("textures[" + texture.index + "]", texture, properties.specularGlossinessTexture.texCoord);
+                        babylonMaterial.reflectivityTexture.hasAlpha = true;
+                        babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
+                    }
+                    loader._loadMaterialAlphaProperties(context, material, properties.diffuseFactor);
+                };
+                return KHRMaterialsPbrSpecularGlossiness;
+            }(GLTF2.GLTFLoaderExtension));
+            Extensions.KHRMaterialsPbrSpecularGlossiness = KHRMaterialsPbrSpecularGlossiness;
+            GLTF2.GLTFLoader.RegisterExtension(new KHRMaterialsPbrSpecularGlossiness());
+        })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=KHR_materials_pbrSpecularGlossiness.js.map

+ 142 - 0
loaders/src/glTF/2.0/Extensions/MSFT_lod.js

@@ -0,0 +1,142 @@
+/// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        var Extensions;
+        (function (Extensions) {
+            // See https://github.com/sbtron/glTF/tree/MSFT_lod/extensions/Vendor/MSFT_lod for more information about this extension.
+            var MSFTLOD = /** @class */ (function (_super) {
+                __extends(MSFTLOD, _super);
+                function MSFTLOD() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                    /**
+                     * Specify the minimal delay between LODs in ms (default = 250)
+                     */
+                    _this.Delay = 250;
+                    return _this;
+                }
+                Object.defineProperty(MSFTLOD.prototype, "name", {
+                    get: function () {
+                        return "MSFT_lod";
+                    },
+                    enumerable: true,
+                    configurable: true
+                });
+                MSFTLOD.prototype._traverseNode = function (loader, context, node, action, parentNode) {
+                    return this._loadExtension(context, node, function (context, extension, onComplete) {
+                        for (var i = extension.ids.length - 1; i >= 0; i--) {
+                            var lodNode = GLTF2.GLTFLoader._GetProperty(loader._gltf.nodes, extension.ids[i]);
+                            if (!lodNode) {
+                                throw new Error(context + ": Failed to find node " + extension.ids[i]);
+                            }
+                            loader._traverseNode(context, lodNode, action, parentNode);
+                        }
+                        loader._traverseNode(context, node, action, parentNode);
+                        onComplete();
+                    });
+                };
+                MSFTLOD.prototype._loadNode = function (loader, context, node) {
+                    var _this = this;
+                    return this._loadExtension(context, node, function (context, extension, onComplete) {
+                        var nodes = [node];
+                        for (var _i = 0, _a = extension.ids; _i < _a.length; _i++) {
+                            var index = _a[_i];
+                            var lodNode = GLTF2.GLTFLoader._GetProperty(loader._gltf.nodes, index);
+                            if (!lodNode) {
+                                throw new Error(context + ": Failed to find node " + index);
+                            }
+                            nodes.push(lodNode);
+                        }
+                        loader._addLoaderPendingData(node);
+                        _this._loadNodeLOD(loader, context, nodes, nodes.length - 1, function () {
+                            loader._removeLoaderPendingData(node);
+                            onComplete();
+                        });
+                    });
+                };
+                MSFTLOD.prototype._loadNodeLOD = function (loader, context, nodes, index, onComplete) {
+                    var _this = this;
+                    loader._whenAction(function () {
+                        loader._loadNode(context, nodes[index]);
+                    }, function () {
+                        if (index !== nodes.length - 1) {
+                            var previousNode = nodes[index + 1];
+                            previousNode.babylonMesh.setEnabled(false);
+                        }
+                        if (index === 0) {
+                            onComplete();
+                            return;
+                        }
+                        setTimeout(function () {
+                            loader._tryCatchOnError(function () {
+                                _this._loadNodeLOD(loader, context, nodes, index - 1, onComplete);
+                            });
+                        }, _this.Delay);
+                    });
+                };
+                MSFTLOD.prototype._loadMaterial = function (loader, context, material, assign) {
+                    var _this = this;
+                    return this._loadExtension(context, material, function (context, extension, onComplete) {
+                        var materials = [material];
+                        for (var _i = 0, _a = extension.ids; _i < _a.length; _i++) {
+                            var index = _a[_i];
+                            var lodMaterial = GLTF2.GLTFLoader._GetProperty(loader._gltf.materials, index);
+                            if (!lodMaterial) {
+                                throw new Error(context + ": Failed to find material " + index);
+                            }
+                            materials.push(lodMaterial);
+                        }
+                        loader._addLoaderPendingData(material);
+                        _this._loadMaterialLOD(loader, context, materials, materials.length - 1, assign, function () {
+                            loader._removeLoaderPendingData(material);
+                            onComplete();
+                        });
+                    });
+                };
+                MSFTLOD.prototype._loadMaterialLOD = function (loader, context, materials, index, assign, onComplete) {
+                    var _this = this;
+                    loader._loadMaterial(context, materials[index], function (babylonMaterial, isNew) {
+                        if (index === materials.length - 1) {
+                            assign(babylonMaterial, isNew);
+                            // Load the next LOD when the loader is ready to render.
+                            loader._executeWhenRenderReady(function () {
+                                _this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
+                            });
+                        }
+                        else {
+                            BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
+                                assign(babylonMaterial, isNew);
+                                if (index === 0) {
+                                    onComplete();
+                                }
+                                else {
+                                    setTimeout(function () {
+                                        loader._tryCatchOnError(function () {
+                                            _this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
+                                        });
+                                    }, _this.Delay);
+                                }
+                            });
+                        }
+                    });
+                };
+                return MSFTLOD;
+            }(GLTF2.GLTFLoaderExtension));
+            Extensions.MSFTLOD = MSFTLOD;
+            GLTF2.GLTFLoader.RegisterExtension(new MSFTLOD());
+        })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=MSFT_lod.js.map

文件差異過大導致無法顯示
+ 1614 - 0
loaders/src/glTF/2.0/babylon.glTFLoader.js


+ 62 - 0
loaders/src/glTF/2.0/babylon.glTFLoaderExtension.js

@@ -0,0 +1,62 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        var GLTFLoaderExtension = /** @class */ (function () {
+            function GLTFLoaderExtension() {
+                this.enabled = true;
+            }
+            GLTFLoaderExtension.prototype._traverseNode = function (loader, context, node, action, parentNode) { return false; };
+            GLTFLoaderExtension.prototype._loadNode = function (loader, context, node) { return false; };
+            GLTFLoaderExtension.prototype._loadMaterial = function (loader, context, material, assign) { return false; };
+            GLTFLoaderExtension.prototype._loadExtension = function (context, property, action) {
+                var _this = this;
+                if (!property.extensions) {
+                    return false;
+                }
+                var extension = property.extensions[this.name];
+                if (!extension) {
+                    return false;
+                }
+                // Clear out the extension before executing the action to avoid recursing into the same property.
+                property.extensions[this.name] = undefined;
+                action(context + "extensions/" + this.name, extension, function () {
+                    // Restore the extension after completing the action.
+                    property.extensions[_this.name] = extension;
+                });
+                return true;
+            };
+            GLTFLoaderExtension.TraverseNode = function (loader, context, node, action, parentNode) {
+                return this._ApplyExtensions(function (extension) { return extension._traverseNode(loader, context, node, action, parentNode); });
+            };
+            GLTFLoaderExtension.LoadNode = function (loader, context, node) {
+                return this._ApplyExtensions(function (extension) { return extension._loadNode(loader, context, node); });
+            };
+            GLTFLoaderExtension.LoadMaterial = function (loader, context, material, assign) {
+                return this._ApplyExtensions(function (extension) { return extension._loadMaterial(loader, context, material, assign); });
+            };
+            GLTFLoaderExtension._ApplyExtensions = function (action) {
+                var extensions = GLTFLoaderExtension._Extensions;
+                if (!extensions) {
+                    return false;
+                }
+                for (var _i = 0, extensions_1 = extensions; _i < extensions_1.length; _i++) {
+                    var extension = extensions_1[_i];
+                    if (extension.enabled && action(extension)) {
+                        return true;
+                    }
+                }
+                return false;
+            };
+            //
+            // Utilities
+            //
+            GLTFLoaderExtension._Extensions = [];
+            return GLTFLoaderExtension;
+        }());
+        GLTF2.GLTFLoaderExtension = GLTFLoaderExtension;
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.glTFLoaderExtension.js.map

+ 51 - 0
loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.js

@@ -0,0 +1,51 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        /**
+        * Enums
+        */
+        var EComponentType;
+        (function (EComponentType) {
+            EComponentType[EComponentType["BYTE"] = 5120] = "BYTE";
+            EComponentType[EComponentType["UNSIGNED_BYTE"] = 5121] = "UNSIGNED_BYTE";
+            EComponentType[EComponentType["SHORT"] = 5122] = "SHORT";
+            EComponentType[EComponentType["UNSIGNED_SHORT"] = 5123] = "UNSIGNED_SHORT";
+            EComponentType[EComponentType["UNSIGNED_INT"] = 5125] = "UNSIGNED_INT";
+            EComponentType[EComponentType["FLOAT"] = 5126] = "FLOAT";
+        })(EComponentType = GLTF2.EComponentType || (GLTF2.EComponentType = {}));
+        var EMeshPrimitiveMode;
+        (function (EMeshPrimitiveMode) {
+            EMeshPrimitiveMode[EMeshPrimitiveMode["POINTS"] = 0] = "POINTS";
+            EMeshPrimitiveMode[EMeshPrimitiveMode["LINES"] = 1] = "LINES";
+            EMeshPrimitiveMode[EMeshPrimitiveMode["LINE_LOOP"] = 2] = "LINE_LOOP";
+            EMeshPrimitiveMode[EMeshPrimitiveMode["LINE_STRIP"] = 3] = "LINE_STRIP";
+            EMeshPrimitiveMode[EMeshPrimitiveMode["TRIANGLES"] = 4] = "TRIANGLES";
+            EMeshPrimitiveMode[EMeshPrimitiveMode["TRIANGLE_STRIP"] = 5] = "TRIANGLE_STRIP";
+            EMeshPrimitiveMode[EMeshPrimitiveMode["TRIANGLE_FAN"] = 6] = "TRIANGLE_FAN";
+        })(EMeshPrimitiveMode = GLTF2.EMeshPrimitiveMode || (GLTF2.EMeshPrimitiveMode = {}));
+        var ETextureMagFilter;
+        (function (ETextureMagFilter) {
+            ETextureMagFilter[ETextureMagFilter["NEAREST"] = 9728] = "NEAREST";
+            ETextureMagFilter[ETextureMagFilter["LINEAR"] = 9729] = "LINEAR";
+        })(ETextureMagFilter = GLTF2.ETextureMagFilter || (GLTF2.ETextureMagFilter = {}));
+        var ETextureMinFilter;
+        (function (ETextureMinFilter) {
+            ETextureMinFilter[ETextureMinFilter["NEAREST"] = 9728] = "NEAREST";
+            ETextureMinFilter[ETextureMinFilter["LINEAR"] = 9729] = "LINEAR";
+            ETextureMinFilter[ETextureMinFilter["NEAREST_MIPMAP_NEAREST"] = 9984] = "NEAREST_MIPMAP_NEAREST";
+            ETextureMinFilter[ETextureMinFilter["LINEAR_MIPMAP_NEAREST"] = 9985] = "LINEAR_MIPMAP_NEAREST";
+            ETextureMinFilter[ETextureMinFilter["NEAREST_MIPMAP_LINEAR"] = 9986] = "NEAREST_MIPMAP_LINEAR";
+            ETextureMinFilter[ETextureMinFilter["LINEAR_MIPMAP_LINEAR"] = 9987] = "LINEAR_MIPMAP_LINEAR";
+        })(ETextureMinFilter = GLTF2.ETextureMinFilter || (GLTF2.ETextureMinFilter = {}));
+        var ETextureWrapMode;
+        (function (ETextureWrapMode) {
+            ETextureWrapMode[ETextureWrapMode["CLAMP_TO_EDGE"] = 33071] = "CLAMP_TO_EDGE";
+            ETextureWrapMode[ETextureWrapMode["MIRRORED_REPEAT"] = 33648] = "MIRRORED_REPEAT";
+            ETextureWrapMode[ETextureWrapMode["REPEAT"] = 10497] = "REPEAT";
+        })(ETextureWrapMode = GLTF2.ETextureWrapMode || (GLTF2.ETextureWrapMode = {}));
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.glTFLoaderInterfaces.js.map

+ 41 - 0
loaders/src/glTF/2.0/babylon.glTFLoaderUtils.js

@@ -0,0 +1,41 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        /**
+        * Utils functions for GLTF
+        */
+        var GLTFUtils = /** @class */ (function () {
+            function GLTFUtils() {
+            }
+            /**
+            * If the uri is a base64 string
+            * @param uri: the uri to test
+            */
+            GLTFUtils.IsBase64 = function (uri) {
+                return uri.length < 5 ? false : uri.substr(0, 5) === "data:";
+            };
+            /**
+            * Decode the base64 uri
+            * @param uri: the uri to decode
+            */
+            GLTFUtils.DecodeBase64 = function (uri) {
+                var decodedString = atob(uri.split(",")[1]);
+                var bufferLength = decodedString.length;
+                var bufferView = new Uint8Array(new ArrayBuffer(bufferLength));
+                for (var i = 0; i < bufferLength; i++) {
+                    bufferView[i] = decodedString.charCodeAt(i);
+                }
+                return bufferView.buffer;
+            };
+            GLTFUtils.ValidateUri = function (uri) {
+                return (uri.indexOf("..") === -1);
+            };
+            return GLTFUtils;
+        }());
+        GLTF2.GLTFUtils = GLTFUtils;
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.glTFLoaderUtils.js.map

+ 293 - 0
loaders/src/glTF/babylon.glTFFileLoader.js

@@ -0,0 +1,293 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+var BABYLON;
+(function (BABYLON) {
+    var GLTFLoaderCoordinateSystemMode;
+    (function (GLTFLoaderCoordinateSystemMode) {
+        /**
+         * Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene.
+         */
+        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["AUTO"] = 0] = "AUTO";
+        /**
+         * Sets the useRightHandedSystem flag on the scene.
+         */
+        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["FORCE_RIGHT_HANDED"] = 1] = "FORCE_RIGHT_HANDED";
+    })(GLTFLoaderCoordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode || (BABYLON.GLTFLoaderCoordinateSystemMode = {}));
+    var GLTFLoaderAnimationStartMode;
+    (function (GLTFLoaderAnimationStartMode) {
+        /**
+         * No animation will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["NONE"] = 0] = "NONE";
+        /**
+         * The first animation will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["FIRST"] = 1] = "FIRST";
+        /**
+         * All animations will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["ALL"] = 2] = "ALL";
+    })(GLTFLoaderAnimationStartMode = BABYLON.GLTFLoaderAnimationStartMode || (BABYLON.GLTFLoaderAnimationStartMode = {}));
+    var GLTFFileLoader = /** @class */ (function () {
+        function GLTFFileLoader() {
+            // #endregion
+            // #region V2 options
+            /**
+             * The coordinate system mode (AUTO, FORCE_RIGHT_HANDED).
+             */
+            this.coordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
+            /**
+             * The animation start mode (NONE, FIRST, ALL).
+             */
+            this.animationStartMode = GLTFLoaderAnimationStartMode.FIRST;
+            /**
+             * Set to true to compile materials before raising the success callback.
+             */
+            this.compileMaterials = false;
+            /**
+             * Set to true to also compile materials with clip planes.
+             */
+            this.useClipPlane = false;
+            /**
+             * Set to true to compile shadow generators before raising the success callback.
+             */
+            this.compileShadowGenerators = false;
+            this.name = "gltf";
+            this.extensions = {
+                ".gltf": { isBinary: false },
+                ".glb": { isBinary: true }
+            };
+        }
+        /**
+         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
+         */
+        GLTFFileLoader.prototype.dispose = function () {
+            if (this._loader) {
+                this._loader.dispose();
+            }
+        };
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
+            try {
+                var loaderData = GLTFFileLoader._parse(data);
+                if (this.onParsed) {
+                    this.onParsed(loaderData);
+                }
+                this._loader = this._getLoader(loaderData);
+                this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            }
+            catch (e) {
+                onError(e.message);
+            }
+        };
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
+            try {
+                var loaderData = GLTFFileLoader._parse(data);
+                if (this.onParsed) {
+                    this.onParsed(loaderData);
+                }
+                this._loader = this._getLoader(loaderData);
+                this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            }
+            catch (e) {
+                onError(e.message);
+            }
+        };
+        GLTFFileLoader.prototype.canDirectLoad = function (data) {
+            return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
+        };
+        GLTFFileLoader.prototype.createPlugin = function () {
+            return new GLTFFileLoader();
+        };
+        GLTFFileLoader._parse = function (data) {
+            if (data instanceof ArrayBuffer) {
+                return GLTFFileLoader._parseBinary(data);
+            }
+            return {
+                json: JSON.parse(data),
+                bin: null
+            };
+        };
+        GLTFFileLoader.prototype._getLoader = function (loaderData) {
+            var loaderVersion = { major: 2, minor: 0 };
+            var asset = loaderData.json.asset || {};
+            var version = GLTFFileLoader._parseVersion(asset.version);
+            if (!version) {
+                throw new Error("Invalid version: " + asset.version);
+            }
+            if (asset.minVersion !== undefined) {
+                var minVersion = GLTFFileLoader._parseVersion(asset.minVersion);
+                if (!minVersion) {
+                    throw new Error("Invalid minimum version: " + asset.minVersion);
+                }
+                if (GLTFFileLoader._compareVersion(minVersion, loaderVersion) > 0) {
+                    throw new Error("Incompatible minimum version: " + asset.minVersion);
+                }
+            }
+            var createLoaders = {
+                1: GLTFFileLoader.CreateGLTFLoaderV1,
+                2: GLTFFileLoader.CreateGLTFLoaderV2
+            };
+            var createLoader = createLoaders[version.major];
+            if (!createLoader) {
+                throw new Error("Unsupported version: " + asset.version);
+            }
+            return createLoader(this);
+        };
+        GLTFFileLoader._parseBinary = function (data) {
+            var Binary = {
+                Magic: 0x46546C67
+            };
+            var binaryReader = new BinaryReader(data);
+            var magic = binaryReader.readUint32();
+            if (magic !== Binary.Magic) {
+                throw new Error("Unexpected magic: " + magic);
+            }
+            var version = binaryReader.readUint32();
+            switch (version) {
+                case 1: return GLTFFileLoader._parseV1(binaryReader);
+                case 2: return GLTFFileLoader._parseV2(binaryReader);
+            }
+            throw new Error("Unsupported version: " + version);
+        };
+        GLTFFileLoader._parseV1 = function (binaryReader) {
+            var ContentFormat = {
+                JSON: 0
+            };
+            var length = binaryReader.readUint32();
+            if (length != binaryReader.getLength()) {
+                throw new Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
+            }
+            var contentLength = binaryReader.readUint32();
+            var contentFormat = binaryReader.readUint32();
+            var content;
+            switch (contentFormat) {
+                case ContentFormat.JSON: {
+                    content = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(contentLength)));
+                    break;
+                }
+                default: {
+                    throw new Error("Unexpected content format: " + contentFormat);
+                }
+            }
+            var bytesRemaining = binaryReader.getLength() - binaryReader.getPosition();
+            var body = binaryReader.readUint8Array(bytesRemaining);
+            return {
+                json: content,
+                bin: body
+            };
+        };
+        GLTFFileLoader._parseV2 = function (binaryReader) {
+            var ChunkFormat = {
+                JSON: 0x4E4F534A,
+                BIN: 0x004E4942
+            };
+            var length = binaryReader.readUint32();
+            if (length !== binaryReader.getLength()) {
+                throw new Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
+            }
+            // JSON chunk
+            var chunkLength = binaryReader.readUint32();
+            var chunkFormat = binaryReader.readUint32();
+            if (chunkFormat !== ChunkFormat.JSON) {
+                throw new Error("First chunk format is not JSON");
+            }
+            var json = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(chunkLength)));
+            // Look for BIN chunk
+            var bin = null;
+            while (binaryReader.getPosition() < binaryReader.getLength()) {
+                var chunkLength_1 = binaryReader.readUint32();
+                var chunkFormat_1 = binaryReader.readUint32();
+                switch (chunkFormat_1) {
+                    case ChunkFormat.JSON: {
+                        throw new Error("Unexpected JSON chunk");
+                    }
+                    case ChunkFormat.BIN: {
+                        bin = binaryReader.readUint8Array(chunkLength_1);
+                        break;
+                    }
+                    default: {
+                        // ignore unrecognized chunkFormat
+                        binaryReader.skipBytes(chunkLength_1);
+                        break;
+                    }
+                }
+            }
+            return {
+                json: json,
+                bin: bin
+            };
+        };
+        GLTFFileLoader._parseVersion = function (version) {
+            if (version === "1.0" || version === "1.0.1") {
+                return {
+                    major: 1,
+                    minor: 0
+                };
+            }
+            var match = (version + "").match(/^(\d+)\.(\d+)/);
+            if (!match) {
+                return null;
+            }
+            return {
+                major: parseInt(match[1]),
+                minor: parseInt(match[2])
+            };
+        };
+        GLTFFileLoader._compareVersion = function (a, b) {
+            if (a.major > b.major)
+                return 1;
+            if (a.major < b.major)
+                return -1;
+            if (a.minor > b.minor)
+                return 1;
+            if (a.minor < b.minor)
+                return -1;
+            return 0;
+        };
+        GLTFFileLoader._decodeBufferToText = function (buffer) {
+            var result = "";
+            var length = buffer.byteLength;
+            for (var i = 0; i < length; i++) {
+                result += String.fromCharCode(buffer[i]);
+            }
+            return result;
+        };
+        // #endregion
+        // #region V1 options
+        GLTFFileLoader.IncrementalLoading = true;
+        GLTFFileLoader.HomogeneousCoordinates = false;
+        return GLTFFileLoader;
+    }());
+    BABYLON.GLTFFileLoader = GLTFFileLoader;
+    var BinaryReader = /** @class */ (function () {
+        function BinaryReader(arrayBuffer) {
+            this._arrayBuffer = arrayBuffer;
+            this._dataView = new DataView(arrayBuffer);
+            this._byteOffset = 0;
+        }
+        BinaryReader.prototype.getPosition = function () {
+            return this._byteOffset;
+        };
+        BinaryReader.prototype.getLength = function () {
+            return this._arrayBuffer.byteLength;
+        };
+        BinaryReader.prototype.readUint32 = function () {
+            var value = this._dataView.getUint32(this._byteOffset, true);
+            this._byteOffset += 4;
+            return value;
+        };
+        BinaryReader.prototype.readUint8Array = function (length) {
+            var value = new Uint8Array(this._arrayBuffer, this._byteOffset, length);
+            this._byteOffset += length;
+            return value;
+        };
+        BinaryReader.prototype.skipBytes = function (length) {
+            this._byteOffset += length;
+        };
+        return BinaryReader;
+    }());
+    if (BABYLON.SceneLoader) {
+        BABYLON.SceneLoader.RegisterPlugin(new GLTFFileLoader());
+    }
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.glTFFileLoader.js.map