Browse Source

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

noalak 7 years ago
parent
commit
4976864190
100 changed files with 131601 additions and 25327 deletions
  1. 26 13
      .vscode/launch.json
  2. 2 0
      Playground/_headers
  3. 2 0
      Playground/zipContent/index.html
  4. 0 6
      Tools/ConvertToBinary/App.config
  5. 0 67
      Tools/ConvertToBinary/ConvertToBinary.csproj
  6. 0 447
      Tools/ConvertToBinary/Program.cs
  7. 0 36
      Tools/ConvertToBinary/Properties/AssemblyInfo.cs
  8. 1 22
      Tools/Gulp/config.json
  9. 0 9
      Tools/Gulp/gulpfile.js
  10. 0 1
      Tools/Gulp/package.json
  11. 0 6
      Tools/MakeIncremental/App.config
  12. 0 105
      Tools/MakeIncremental/MakeIncremental.csproj
  13. 0 282
      Tools/MakeIncremental/Program.cs
  14. 0 36
      Tools/MakeIncremental/Properties/AssemblyInfo.cs
  15. 35 0
      Viewer/README.md
  16. BIN
      Viewer/assets/img/fullscreen.png
  17. BIN
      Viewer/assets/img/loading.png
  18. 30 0
      Viewer/assets/templates/default/defaultTemplate.html
  19. 39 0
      Viewer/assets/templates/default/defaultViewer.html
  20. 26 0
      Viewer/assets/templates/default/loadingScreen.html
  21. 69 0
      Viewer/assets/templates/default/navbar.html
  22. 26 0
      Viewer/dist/basicExample.html
  23. 41 0
      Viewer/dist/domExample.html
  24. BIN
      Viewer/dist/environment.dds
  25. 104839 0
      Viewer/dist/viewer.js
  26. 48 0
      Viewer/package.json
  27. 269 0
      Viewer/src/configuration/configuration.ts
  28. 0 0
      Viewer/src/configuration/index.ts
  29. 76 0
      Viewer/src/configuration/loader.ts
  30. 123 0
      Viewer/src/configuration/mappers.ts
  31. 41 0
      Viewer/src/helper.ts
  32. 23 0
      Viewer/src/index.ts
  33. 15 0
      Viewer/src/initializer.ts
  34. 5 0
      Viewer/src/interfaces.ts
  35. 248 0
      Viewer/src/templateManager.ts
  36. 333 0
      Viewer/src/viewer/defaultViewer.ts
  37. 134 0
      Viewer/src/viewer/viewer.ts
  38. 26 0
      Viewer/tsconfig.json
  39. 63 0
      Viewer/webpack.config.js
  40. BIN
      assets/meshes/controllers/microsoft/045E-065D/left.glb
  41. BIN
      assets/meshes/controllers/microsoft/045E-065D/right.glb
  42. 2048 2216
      dist/preview release/babylon.d.ts
  43. 48 47
      dist/preview release/babylon.js
  44. 2201 1594
      dist/preview release/babylon.max.js
  45. 2048 2216
      dist/preview release/babylon.module.d.ts
  46. 49 48
      dist/preview release/babylon.worker.js
  47. 7469 7637
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  48. 50 49
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  49. 2435 1783
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  50. 7469 7637
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
  51. 1 1
      dist/preview release/gui/package.json
  52. 3 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  53. 0 3
      dist/preview release/inspector/babylon.inspector.d.ts
  54. 1 10
      dist/preview release/inspector/babylon.inspector.js
  55. 3 4
      dist/preview release/inspector/babylon.inspector.min.js
  56. 6 9
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  57. 21 12
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  58. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  59. 10 12
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  60. 235 191
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  61. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  62. 11 12
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  63. 238 191
      dist/preview release/loaders/babylon.glTFFileLoader.js
  64. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  65. 238 191
      dist/preview release/loaders/babylonjs.loaders.js
  66. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  67. 11 12
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  68. 1 1
      dist/preview release/loaders/package.json
  69. 1 1
      dist/preview release/loaders/readme.md
  70. 1 0
      dist/preview release/materialsLibrary/babylon.customMaterial.d.ts
  71. 1 0
      dist/preview release/materialsLibrary/babylon.customMaterial.js
  72. 2 2
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  73. 1 0
      dist/preview release/materialsLibrary/babylonjs.materials.js
  74. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  75. 1 0
      dist/preview release/materialsLibrary/babylonjs.materials.module.d.ts
  76. 1 1
      dist/preview release/materialsLibrary/package.json
  77. 1 1
      dist/preview release/materialsLibrary/readme.md
  78. 1 1
      dist/preview release/postProcessesLibrary/package.json
  79. 1 1
      dist/preview release/postProcessesLibrary/readme.md
  80. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  81. 1 1
      dist/preview release/proceduralTexturesLibrary/readme.md
  82. 4 2
      dist/preview release/what's new.md
  83. 0 3
      inspector/src/properties.ts
  84. 1 8
      inspector/src/tabs/TextureTab.ts
  85. 4 0
      loaders/src/glTF/1.0/babylon.glTFLoader.ts
  86. 3 3
      loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts
  87. 11 7
      loaders/src/glTF/2.0/Extensions/MSFT_lod.ts
  88. 284 268
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  89. 3 4
      loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts
  90. 5 5
      loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts
  91. 47 45
      loaders/src/glTF/babylon.glTFFileLoader.ts
  92. 2 2
      localDev/index.html
  93. 1 0
      materialsLibrary/src/custom/babylon.customMaterial.ts
  94. 1 1
      package.json
  95. 3 3
      src/Actions/babylon.action.ts
  96. 22 20
      src/Actions/babylon.actionManager.ts
  97. 8 5
      src/Animations/babylon.animatable.ts
  98. 41 20
      src/Animations/babylon.animation.ts
  99. 1 1
      src/Animations/babylon.runtimeAnimation.ts
  100. 0 0
      src/Audio/babylon.analyser.ts

+ 26 - 13
.vscode/launch.json

@@ -2,6 +2,19 @@
     "version": "0.1.0",
     "configurations": [
         {
+            "name": "Launch Viewer (Chrome)",
+            "type": "chrome",
+            "request": "launch",
+            "url": "http://localhost:9000/",
+            "webRoot": "${workspaceRoot}/Viewer/dist/",
+            "sourceMaps": true,
+            //"preLaunchTask": "build-viewer", // TODO - test why this fails.
+            "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
+            "runtimeArgs": [
+                "--enable-unsafe-es3-apis"
+            ]
+        },
+        {
             "name": "Launch nullEngine",
             "type": "node",
             "request": "launch",
@@ -17,22 +30,22 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
-        },         
+        },
         {
             "name": "Launch playground (Chrome)",
             "type": "chrome",
             "request": "launch",
             "url": "http://localhost:1338/Playground/index-local.html",
             "webRoot": "${workspaceRoot}/",
-            "sourceMaps": true,            
+            "sourceMaps": true,
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
-        },        
+        },
         {
             "name": "Launch playground (Chrome+WebGL 1.0 forced)",
             "type": "chrome",
@@ -43,7 +56,7 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--disable-es3-apis" 
+                "--disable-es3-apis"
             ]
         },
         {
@@ -56,7 +69,7 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
         },
         {
@@ -69,7 +82,7 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
         },
         {
@@ -82,7 +95,7 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
         },
         {
@@ -95,7 +108,7 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
         },
         {
@@ -108,9 +121,9 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
-        },      
+        },
         {
             "name": "Launch Build Validation (Chrome)",
             "type": "chrome",
@@ -121,7 +134,7 @@
             "preLaunchTask": "run",
             "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
             "runtimeArgs": [
-                "--enable-unsafe-es3-apis" 
+                "--enable-unsafe-es3-apis"
             ]
         }
     ]

+ 2 - 0
Playground/_headers

@@ -0,0 +1,2 @@
+/*
+	Access-Control-Allow-Origin: *

+ 2 - 0
Playground/zipContent/index.html

@@ -6,9 +6,11 @@
         <title>Babylon.js sample code</title>
         <!-- Babylon.js -->
         <script src="https://www.babylonjs.com/hand.minified-1.2.js"></script>
+        <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
         <script src="https://preview.babylonjs.com/cannon.js"></script>
         <script src="https://preview.babylonjs.com/oimo.js"></script>
         <script src="https://preview.babylonjs.com/babylon.js"></script>
+        
         <style>
             html, body {
                 overflow: hidden;

+ 0 - 6
Tools/ConvertToBinary/App.config

@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<configuration>
-    <startup> 
-        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
-    </startup>
-</configuration>

+ 0 - 67
Tools/ConvertToBinary/ConvertToBinary.csproj

@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{6A8A02E3-324F-4807-8AF9-AAD3CAF86376}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>ConvertToBinary</RootNamespace>
-    <AssemblyName>ConvertToBinary</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <SccProjectName>SAK</SccProjectName>
-    <SccLocalPath>SAK</SccLocalPath>
-    <SccAuxPath>SAK</SccAuxPath>
-    <SccProvider>SAK</SccProvider>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\Newtonsoft.Json.5.0.4\lib\net45\Newtonsoft.Json.dll</HintPath>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Web" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="App.config" />
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>

+ 0 - 447
Tools/ConvertToBinary/Program.cs

@@ -1,447 +0,0 @@
-using System;
-using System.IO;
-using System.Linq;
-using System.Web;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using System.Collections.Generic;
-using System.Net;
-
-namespace ConvertToBinary
-{
-    public enum DataType { Int32, Float };
-
-    class Program
-    {
-        static void Main(string[] args)
-        {
-            if (args.Length < 1)
-            {
-                DisplayUsage();
-                return;
-            }
-
-            // Parsing arguments
-            string srcFilename = "";
-            string dstPath = "";
-
-            foreach (var arg in args)
-            {
-                var order = arg.Substring(0, 3);
-
-                switch (order)
-                {
-                    case "/i:":
-                        srcFilename = arg.Substring(3);
-                        break;
-                    case "/o:":
-                        dstPath = arg.Substring(3);
-                        break;
-                    default:
-                        DisplayUsage();
-                        return;
-                }
-            }
-
-            if (string.IsNullOrEmpty(srcFilename) || string.IsNullOrEmpty(dstPath))
-            {
-                DisplayUsage();
-                return;
-            }
-
-            ProcessSourceFile(srcFilename, dstPath);
-        }
-
-        static void ProcessSourceFile(string srcFilename, string dstPath)
-        {
-            try
-            {
-                if (!Directory.Exists(dstPath))
-                    Directory.CreateDirectory(dstPath);
-
-                string srcPath = Path.GetDirectoryName(srcFilename);
-                string dstFilename = Path.Combine(dstPath, Path.GetFileNameWithoutExtension(srcFilename) + ".binary.babylon");
-
-                dynamic scene;
-
-                // Loading
-                Console.ForegroundColor = ConsoleColor.Green;
-                Console.WriteLine("Loading " + srcFilename);
-                Console.WriteLine();
-                Console.ResetColor();
-
-                using (var streamReader = new StreamReader(srcFilename))
-                {
-                    using (var reader = new JsonTextReader(streamReader))
-                    {
-                        scene = JObject.Load(reader);
-                    }
-                }
-
-                // Marking scene
-                string objName = scene.name;
-
-                if(string.IsNullOrEmpty(objName))
-                    objName = Path.GetFileNameWithoutExtension(srcFilename);
-
-                int atDot = objName.IndexOf(".incremental");
-                if(atDot > 0)
-                    objName = objName.Substring(0, atDot);
-
-                scene["autoClear"] = true;
-                scene["useDelayedTextureLoading"] = true;
-
-                var doNotDelayLoadingForGeometries = new List<string>();
-
-                // Parsing meshes
-                bool isMesh = true;
-                var meshes = (JArray)scene.meshes;
-                foreach (dynamic mesh in meshes)
-                {
-                    if (mesh.checkCollisions.Value) // Do not delay load collisions object
-                    {
-                        if (mesh.geometryId != null)
-                            doNotDelayLoadingForGeometries.Add(mesh.geometryId.Value);
-                        continue;
-                    }
-
-                    isMesh = true;
-
-                    Extract(srcPath, dstPath, objName, mesh, isMesh);
-                }
-
-
-                // Parsing vertexData
-                var geometries = scene.geometries;
-                if (geometries != null)
-                {
-                    var vertexData = (JArray)geometries.vertexData;
-                    foreach (dynamic geometry in vertexData)
-                    {
-                        var id = geometry.id.Value;
-
-                        if (doNotDelayLoadingForGeometries.Any(g => g == id))
-                            continue;
-
-                        isMesh = false;
-
-                        Extract(srcPath, dstPath, objName, geometry, isMesh);
-                    }
-                }
-
-                // Saving
-                Console.ForegroundColor = ConsoleColor.Green;
-                Console.WriteLine("Saving " + dstFilename);
-                string json = scene.ToString(Formatting.Indented);
-
-                using (var writer = new StreamWriter(WebUtility.UrlDecode(dstFilename)))
-                {
-                    writer.Write(json);
-                }
-
-                Console.WriteLine();
-                Console.ResetColor();
-            }
-            catch (Exception ex)
-            {
-                Console.ForegroundColor = ConsoleColor.Red;
-                Console.WriteLine("Fatal error encountered:");
-                Console.WriteLine(ex.Message);
-                Console.ResetColor();
-            }
-        }
-
-        
-        static void Extract(string srcPath, string dstPath, string objName, dynamic meshObj, bool isMesh)
-        {
-            try
-            {
-                string dstFilename = meshObj.delayLoadingFile;
-                string dstExt = (isMesh ? ".babylonbinarymeshdata" : ".babylonbinarygeometrydata");
-                
-                if(!string.IsNullOrEmpty(dstFilename))
-                {
-                    string filename = WebUtility.UrlDecode(Path.Combine(srcPath, (string)meshObj.delayLoadingFile));
-
-                    using (var streamReader = new StreamReader(filename))
-                    {
-                        using (var reader = new JsonTextReader(streamReader))
-                        {
-                            var meshData = JObject.Load(reader);
-                            meshObj.positions = meshData["positions"];
-                            meshObj.normals = meshData["normals"];
-                            meshObj.indices = meshData["indices"];
-                            meshObj.uvs = meshData["uvs"];
-                            meshObj.uvs2 = meshData["uvs2"];
-                            meshObj.colors = meshData["colors"];
-                            meshObj.matricesIndices = meshData["matricesIndices"];
-                            meshObj.matricesWeights = meshData["matricesWeights"];
-                            meshObj.subMeshes = meshData["subMeshes"];
-                        }
-                    }
-                }
-
-                if (meshObj.positions == null || meshObj.normals == null || meshObj.indices == null)
-                    return;
-
-                Console.WriteLine("Extracting " + (isMesh ? meshObj.name : meshObj.id));
-
-                ComputeBoundingBox(meshObj);
-
-                string meshName = meshObj.name.ToString();
-                meshName = meshName.Trim();
-                if (meshName.Length > 40)
-                    meshName = meshName.Substring(0, 40);
-
-                if (isMesh && !string.IsNullOrEmpty(meshName))
-                    dstFilename = objName + "." + meshName + "." + meshObj.id.ToString() + dstExt;
-                else
-                    dstFilename = objName + meshObj.id.ToString() + dstExt;
-
-                dstFilename = dstFilename.Replace("+", "_").Replace(" ", "_").Replace("/", "_").Replace("\\", "_");
-
-                meshObj.delayLoadingFile = WebUtility.UrlEncode(dstFilename);
-                Console.WriteLine("Creating delayLoadingFile: " + meshObj.delayLoadingFile);
-
-
-                var binaryInfo = new JObject();
-
-                using (var stream = File.Open(WebUtility.UrlDecode(Path.Combine(dstPath, dstFilename)), FileMode.Create))
-                {
-                    BinaryWriter writer = new BinaryWriter(stream);
-
-                    if (meshObj.positions != null && meshObj.positions.Count > 0)
-                    {
-                        var attrData = new JObject();
-                        attrData["count"] = meshObj.positions.Count;
-                        attrData["stride"] = 3;
-                        attrData["offset"] = stream.Length;
-                        attrData["dataType"] = (int)DataType.Float;
-
-                        binaryInfo["positionsAttrDesc"] = attrData;
-
-                        for (int x = 0; x < meshObj.positions.Count; x++)
-                            writer.Write((float)meshObj.positions[x]);
-
-                        meshObj.positions = null;
-                    }
-
-
-                    if (meshObj.colors != null && meshObj.colors.Count > 0)
-                    {
-                        var attrData = new JObject();
-                        attrData["count"] = meshObj.colors.Count;
-                        attrData["stride"] = 3;
-                        attrData["offset"] = stream.Length;
-                        attrData["dataType"] = (int)DataType.Float;
-
-                        binaryInfo["colorsAttrDesc"] = attrData;
-
-                        for (int x = 0; x < meshObj.colors.Count; x++)
-                            writer.Write((float)meshObj.colors[x]);
-
-                        meshObj["hasColors"] = true;
-                        meshObj.colors = null;
-                    }
-
-
-                    if (meshObj.normals != null && meshObj.normals.Count > 0)
-                    {
-                        var attrData = new JObject();
-                        attrData["count"] = meshObj.normals.Count;
-                        attrData["stride"] = 3;
-                        attrData["offset"] = stream.Length;
-                        attrData["dataType"] = (int)DataType.Float;
-
-                        binaryInfo["normalsAttrDesc"] = attrData;
-
-                        for (int x = 0; x < meshObj.normals.Count; x++)
-                            writer.Write((float)meshObj.normals[x]);
-
-                        meshObj.normals = null;
-                    }
-
-
-                    if (meshObj.uvs != null && meshObj.uvs.Count > 0)
-                    {
-                        var attrData = new JObject();
-                        attrData["count"] = meshObj.uvs.Count;
-                        attrData["stride"] = 2;
-                        attrData["offset"] = stream.Length;
-                        attrData["dataType"] = (int)DataType.Float;
-
-                        binaryInfo["uvsAttrDesc"] = attrData;
-
-                        for (int x = 0; x < meshObj.uvs.Count; x++)
-                            writer.Write((float)meshObj.uvs[x]);
-
-                        meshObj["hasUVs"] = true;
-                        meshObj.uvs = null;
-                    }
-
-
-                    if (meshObj.uvs2 != null && meshObj.uvs2.Count > 0)
-                    {
-                        var attrData = new JObject();
-                        attrData["count"] = meshObj.uvs2.Count;
-                        attrData["stride"] = 2;
-                        attrData["offset"] = stream.Length;
-                        attrData["dataType"] = (int)DataType.Float;
-
-                        binaryInfo["uvs2AttrDesc"] = attrData;
-
-                        for (int x = 0; x < meshObj.uvs2.Count; x++)
-                            writer.Write((float)meshObj.uvs2[x]);
-
-                        meshObj["hasUVs2"] = true;
-                        meshObj.uvs2 = null;
-                    }
-
-
-                    if (meshObj.indices != null && meshObj.indices.Count > 0)
-                    {
-                        var attrData = new JObject();
-                        attrData["count"] = meshObj.indices.Count;
-                        attrData["stride"] = 1;
-                        attrData["offset"] = stream.Length;
-                        attrData["dataType"] = (int)DataType.Int32;
-
-                        binaryInfo["indicesAttrDesc"] = attrData;
-
-                        for (int x = 0; x < meshObj.indices.Count; x++)
-                            writer.Write((int)meshObj.indices[x]);
-
-                        meshObj.indices = null;
-                    }
-
-
-                    if (meshObj.matricesIndices != null && meshObj.matricesIndices.Count > 0)
-                    {
-                        var attrData = new JObject();
-                        attrData["count"] = meshObj.matricesIndices.Count;
-                        attrData["stride"] = 1;
-                        attrData["offset"] = stream.Length;
-                        attrData["dataType"] = (int)DataType.Int32;
-
-                        binaryInfo["matricesIndicesAttrDesc"] = attrData;
-
-                        for (int x = 0; x < meshObj.matricesIndices.Count; x++)
-                            writer.Write((int)meshObj.matricesIndices[x]);
-
-                        meshObj["hasMatricesIndices"] = true;
-                        meshObj.matricesIndices = null;
-                    }
-
-
-                    if (meshObj.matricesWeights != null && meshObj.matricesWeights.Count > 0)
-                    {
-                        var attrData = new JObject();
-                        attrData["count"] = meshObj.matricesWeights.Count;
-                        attrData["stride"] = 2;
-                        attrData["offset"] = stream.Length;
-                        attrData["dataType"] = (int)DataType.Float;
-
-                        binaryInfo["matricesWeightsAttrDesc"] = attrData;
-
-                        for (int x = 0; x < meshObj.matricesWeights.Count; x++)
-                            writer.Write((float)meshObj.matricesWeights[x]);
-
-                        meshObj["hasMatricesWeights"] = true;
-                        meshObj.matricesWeights = null;
-                    }
-
-
-                    if (isMesh && meshObj.subMeshes != null && meshObj.subMeshes.Count > 0)
-                    {
-                        var attrData = new JObject();
-                        attrData["count"] = meshObj.subMeshes.Count;
-                        attrData["stride"] = 5;
-                        attrData["offset"] = stream.Length;
-                        attrData["dataType"] = (int)DataType.Int32;
-
-                        binaryInfo["subMeshesAttrDesc"] = attrData;
-
-                        int[] smData = new int[5];
-
-                        for (int x = 0; x < meshObj.subMeshes.Count; x++)
-                        {
-                            smData[0] = meshObj.subMeshes[x].materialIndex;
-                            smData[1] = meshObj.subMeshes[x].verticesStart;
-                            smData[2] = meshObj.subMeshes[x].verticesCount;
-                            smData[3] = meshObj.subMeshes[x].indexStart;
-                            smData[4] = meshObj.subMeshes[x].indexCount;
-
-                            for (int y = 0; y < smData.Length; y++)
-                                writer.Write((int)smData[y]);
-                        }
-
-                        meshObj.subMeshes = null;
-                    }
-                }
-
-                meshObj["_binaryInfo"] = binaryInfo;
-            }
-            catch (Exception ex)
-            {
-                Console.ForegroundColor = ConsoleColor.Red;
-                Console.WriteLine();
-                Console.WriteLine(ex.Message);
-                Console.ForegroundColor = ConsoleColor.DarkCyan;
-                Console.WriteLine(ex);
-                Console.ResetColor();
-            }
-        }
-        
-        
-        static void ComputeBoundingBox(dynamic meshOrGeometry)
-        {
-            // Compute bounding boxes
-            var positions = ((JArray)meshOrGeometry.positions).Select(v => v.Value<float>()).ToArray();
-            var minimum = new[] { float.MaxValue, float.MaxValue, float.MaxValue };
-            var maximum = new[] { float.MinValue, float.MinValue, float.MinValue };
-
-            for (var index = 0; index < positions.Length; index += 3)
-            {
-                var x = positions[index];
-                var y = positions[index + 1];
-                var z = positions[index + 2];
-
-                if (x < minimum[0])
-                {
-                    minimum[0] = x;
-                }
-                if (x > maximum[0])
-                {
-                    maximum[0] = x;
-                }
-
-                if (y < minimum[1])
-                {
-                    minimum[1] = y;
-                }
-                if (y > maximum[1])
-                {
-                    maximum[1] = y;
-                }
-
-                if (z < minimum[2])
-                {
-                    minimum[2] = z;
-                }
-                if (z > maximum[2])
-                {
-                    maximum[2] = z;
-                }
-            }
-
-            meshOrGeometry["boundingBoxMinimum"] = new JArray(minimum);
-            meshOrGeometry["boundingBoxMaximum"] = new JArray(maximum);
-        }
-
-
-        static void DisplayUsage()
-        {
-            Console.WriteLine("ConvertToBinary usage: ConvertToBinary.exe /i:\"sourceFilename\" /o:\"dstinationFolder\"");
-        }
-    }
-}

+ 0 - 36
Tools/ConvertToBinary/Properties/AssemblyInfo.cs

@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("ConvertToBinary")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("ConvertToBinary")]
-[assembly: AssemblyCopyright("Copyright ©  2014")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible 
-// to COM components.  If you need to access a type in this assembly from 
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("4e8c456c-1bd6-43fb-b67b-0dfbee0c468d")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]

+ 1 - 22
Tools/Gulp/config.json

@@ -67,8 +67,6 @@
             "optimizations",
             "highlights",
             "assetsManager",
-            "mapTexture",
-            "dynamicFloatArray",
             "serialization",
             "probes",
             "layer",
@@ -143,8 +141,6 @@
             "optimizations",
             "highlights",
             "assetsManager",
-            "mapTexture",
-            "dynamicFloatArray",
             "serialization",
             "probes",
             "layer",
@@ -160,6 +156,7 @@
     "workloads": {
         "core": {
             "files": [
+                "../../src/babylon.types.js",
                 "../../src/Events/babylon.keyboardEvents.js",
                 "../../src/Events/babylon.pointerEvents.js",
                 "../../src/Math/babylon.math.js",
@@ -923,7 +920,6 @@
                 "additionalMeshes",
                 "standardMaterial",
                 "stringDictionary",
-                "dynamicFloatArray",
                 "actions"
             ],
             "shaders": [
@@ -1029,23 +1025,6 @@
                 "core"
             ]
         },
-        "mapTexture": {
-            "files": [
-                "../../src/Materials/Textures/babylon.mapTexture.js",
-                "../../src/Tools/babylon.rectPackingMap.js"
-            ],
-            "dependUpon": [
-                "core"
-            ]
-        },
-        "dynamicFloatArray": {
-            "files": [
-                "../../src/Tools/babylon.dynamicFloatArray.js"
-            ],
-            "dependUpon": [
-                "core"
-            ]
-        },
         "serialization": {
             "files": [
                 "../../src/Tools/babylon.sceneSerializer.js"

+ 0 - 9
Tools/Gulp/gulpfile.js

@@ -21,8 +21,6 @@ var path = require('path');
 var sass = require('gulp-sass');
 var webpack = require('webpack-stream');
 
-var zip = require('gulp-zip');
-
 var config = require("./config.json");
 
 var del = require('del');
@@ -518,13 +516,6 @@ gulp.task('webserver', function () {
 gulp.task('run', ['watch', 'webserver'], function () {
 });
 
-
-gulp.task("zip-blender", function () {
-    return gulp.src('../../Exporters/Blender/src/**')
-        .pipe(zip('Blender2Babylon-5.4.zip'))
-        .pipe(gulp.dest('../../Exporters/Blender'));
-});
-
 gulp.task('clean-JS-MAP', function () {
     return del([
         '../../src/**/*.js.map', '../../src/**/*.js'

+ 0 - 1
Tools/Gulp/package.json

@@ -32,7 +32,6 @@
     "style-loader": "^0.13.1",
     "exports-loader": "^0.6.3",
     "imports-loader": "^0.7.0",
-    "gulp-zip": "~3.2.0",
     "del": "2.2.2"
   },
   "scripts": {

+ 0 - 6
Tools/MakeIncremental/App.config

@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<configuration>
-    <startup> 
-        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
-    </startup>
-</configuration>

+ 0 - 105
Tools/MakeIncremental/MakeIncremental.csproj

@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{E0855FC6-7205-4621-A975-7A8F2886B738}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>MakeIncremental</RootNamespace>
-    <AssemblyName>MakeIncremental</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <SccProjectName>SAK</SccProjectName>
-    <SccLocalPath>SAK</SccLocalPath>
-    <SccAuxPath>SAK</SccAuxPath>
-    <SccProvider>SAK</SccProvider>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
-    <DebugSymbols>true</DebugSymbols>
-    <OutputPath>bin\x64\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <DebugType>full</DebugType>
-    <PlatformTarget>x64</PlatformTarget>
-    <ErrorReport>prompt</ErrorReport>
-    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
-    <Prefer32Bit>true</Prefer32Bit>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
-    <OutputPath>bin\x64\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <Optimize>true</Optimize>
-    <DebugType>pdbonly</DebugType>
-    <PlatformTarget>x64</PlatformTarget>
-    <ErrorReport>prompt</ErrorReport>
-    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
-    <Prefer32Bit>true</Prefer32Bit>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
-    <DebugSymbols>true</DebugSymbols>
-    <OutputPath>bin\x86\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <DebugType>full</DebugType>
-    <PlatformTarget>x86</PlatformTarget>
-    <ErrorReport>prompt</ErrorReport>
-    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
-    <Prefer32Bit>true</Prefer32Bit>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
-    <OutputPath>bin\x86\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <Optimize>true</Optimize>
-    <DebugType>pdbonly</DebugType>
-    <PlatformTarget>x86</PlatformTarget>
-    <ErrorReport>prompt</ErrorReport>
-    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
-    <Prefer32Bit>true</Prefer32Bit>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL" />
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Web" />
-    <Reference Include="System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="App.config" />
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>

+ 0 - 282
Tools/MakeIncremental/Program.cs

@@ -1,282 +0,0 @@
-using System;
-using System.IO;
-using System.Linq;
-using System.Web;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using System.Collections.Generic;
-
-namespace MakeIncremental
-{
-    class Program
-    {
-        static void Main(string[] args)
-        {
-            if (args.Length < 1)
-            {
-                DisplayUsage();
-                return;
-            }
-
-            // Parsing arguments
-            string input = "";
-            foreach (var arg in args)
-            {
-                var order = arg.Substring(0, 3);
-
-                switch (order)
-                {
-                    case "/i:":
-                        input = arg.Substring(3);
-                        break;
-                    default:
-                        DisplayUsage();
-                        return;
-                }
-            }
-
-            if (string.IsNullOrEmpty(input))
-            {
-                DisplayUsage();
-                return;
-            }
-
-            ProcessSourceFile(input);
-        }
-
-        static void Extract(dynamic meshOrGeometry, string outputDir, string rootFilename, bool mesh = true)
-        {
-            Console.WriteLine("Extracting " + (mesh ? meshOrGeometry.name : meshOrGeometry.id));
-
-            if (meshOrGeometry.positions != null && meshOrGeometry.normals != null && meshOrGeometry.indices != null)
-            {
-                meshOrGeometry.delayLoadingFile = CreateDelayLoadingFile(meshOrGeometry, outputDir, rootFilename, mesh);
-                Console.WriteLine("Delay loading file: " + meshOrGeometry.delayLoadingFile);
-
-                // Compute bounding boxes
-                var positions = ((JArray)meshOrGeometry.positions).Select(v => v.Value<float>()).ToArray();
-                var minimum = new[] { float.MaxValue, float.MaxValue, float.MaxValue };
-                var maximum = new[] { float.MinValue, float.MinValue, float.MinValue };
-
-                for (var index = 0; index < positions.Length; index += 3)
-                {
-                    var x = positions[index];
-                    var y = positions[index + 1];
-                    var z = positions[index + 2];
-
-                    if (x < minimum[0])
-                    {
-                        minimum[0] = x;
-                    }
-                    if (x > maximum[0])
-                    {
-                        maximum[0] = x;
-                    }
-
-                    if (y < minimum[1])
-                    {
-                        minimum[1] = y;
-                    }
-                    if (y > maximum[1])
-                    {
-                        maximum[1] = y;
-                    }
-
-                    if (z < minimum[2])
-                    {
-                        minimum[2] = z;
-                    }
-                    if (z > maximum[2])
-                    {
-                        maximum[2] = z;
-                    }
-                }
-
-                meshOrGeometry["boundingBoxMinimum"] = new JArray(minimum);
-                meshOrGeometry["boundingBoxMaximum"] = new JArray(maximum);
-
-                // Erasing infos
-                meshOrGeometry.positions = null;
-                meshOrGeometry.normals = null;
-                meshOrGeometry.indices = null;
-
-                if (meshOrGeometry.uvs != null)
-                {
-                    meshOrGeometry["hasUVs"] = true;
-                    meshOrGeometry.uvs = null;
-                }
-
-                if (meshOrGeometry.uvs2 != null)
-                {
-                    meshOrGeometry["hasUVs2"] = true;
-                    meshOrGeometry.uvs2 = null;
-                }
-
-                if (meshOrGeometry.colors != null)
-                {
-                    meshOrGeometry["hasColors"] = true;
-                    meshOrGeometry.colors = null;
-                }
-
-                if (meshOrGeometry.matricesIndices != null)
-                {
-                    meshOrGeometry["hasMatricesIndices"] = true;
-                    meshOrGeometry.matricesIndices = null;
-                }
-
-                if (meshOrGeometry.matricesWeights != null)
-                {
-                    meshOrGeometry["hasMatricesWeights"] = true;
-                    meshOrGeometry.matricesWeights = null;
-                }
-
-                if (mesh && meshOrGeometry.subMeshes != null)
-                {
-                    meshOrGeometry.subMeshes = null;
-                }
-            }
-        }
-
-        static string CreateDelayLoadingFile(dynamic meshOrGeometry, string outputDir, string rootFilename, bool mesh = true)
-        {
-            string encodedName;
-            if(mesh)
-                encodedName = meshOrGeometry.name.ToString();
-            else
-                encodedName = meshOrGeometry.id.ToString();
-
-            encodedName = encodedName.Replace("+", "_").Replace(" ", "_");
-            var outputPath = Path.Combine(outputDir, rootFilename + "." + encodedName + (mesh ? ".babylonmeshdata" : ".babylongeometrydata"));
-
-            var result = new JObject();
-            result["positions"] = meshOrGeometry.positions;
-            result["indices"] = meshOrGeometry.indices;
-            result["normals"] = meshOrGeometry.normals;
-
-            if (meshOrGeometry.uvs != null)
-            {
-                result["uvs"] = meshOrGeometry.uvs;
-            }
-
-            if (meshOrGeometry.uvs2 != null)
-            {
-                result["uvs2"] = meshOrGeometry.uvs2;
-            }
-
-            if (meshOrGeometry.colors != null)
-            {
-                result["colors"] = meshOrGeometry.colors;
-            }
-
-            if (meshOrGeometry.matricesIndices != null)
-            {
-                result["matricesIndices"] = meshOrGeometry.matricesIndices;
-            }
-
-            if (meshOrGeometry.matricesWeights != null)
-            {
-                result["matricesWeights"] = meshOrGeometry.matricesWeights;
-            }
-
-            if (mesh && meshOrGeometry.subMeshes != null)
-            {
-                result["subMeshes"] = meshOrGeometry.subMeshes;
-            }
-
-            string json = result.ToString(Formatting.None);
-
-            using (var writer = new StreamWriter(outputPath))
-            {
-                writer.Write(json);
-            }
-
-            return HttpUtility.UrlEncode(Path.GetFileName(outputPath));
-        }
-
-        static void ProcessSourceFile(string input)
-        {
-            try
-            {
-                dynamic scene;
-                var outputDir = Path.GetDirectoryName(input);
-                var rootFilename = Path.GetFileNameWithoutExtension(input);
-
-                // Loading
-                Console.ForegroundColor = ConsoleColor.Green;
-                Console.WriteLine("Loading " + input);
-                Console.WriteLine();
-                Console.ResetColor();
-                using (var streamReader = new StreamReader(input))
-                {
-                    using (var reader = new JsonTextReader(streamReader))
-                    {
-                        scene = JObject.Load(reader);
-                    }
-                }
-
-                // Marking scene
-                scene["autoClear"] = true;
-                scene["useDelayedTextureLoading"] = true;
-
-                var doNotDelayLoadingForGeometries = new List<string>();
-
-                // Parsing meshes
-                var meshes = (JArray)scene.meshes;
-                foreach (dynamic mesh in meshes)
-                {
-                    if (mesh.checkCollisions.Value) // Do not delay load collisions object
-                    {
-                        if (mesh.geometryId != null)
-                            doNotDelayLoadingForGeometries.Add(mesh.geometryId.Value);
-                        continue;
-                    }
-
-                    Extract(mesh, outputDir, rootFilename);
-                }
-
-                // Parsing vertexData
-                var geometries = scene.geometries;
-                if (geometries != null)
-                {
-                    var vertexData = (JArray)geometries.vertexData;
-                    foreach (dynamic geometry in vertexData)
-                    {
-                        var id = geometry.id.Value;
-
-                        if (doNotDelayLoadingForGeometries.Any(g => g == id))
-                            continue;
-
-                        Extract(geometry, outputDir, rootFilename, false);
-                    }
-                }
-
-                // Saving
-                var outputPath = Path.Combine(outputDir, rootFilename + ".incremental.babylon");
-                Console.ForegroundColor = ConsoleColor.Green;
-                Console.WriteLine("Saving " + outputPath);
-                string json = scene.ToString(Formatting.None);
-
-                using (var writer = new StreamWriter(outputPath))
-                {
-                    writer.Write(json);
-                }
-
-                Console.WriteLine();
-                Console.ResetColor();
-
-            }
-            catch (Exception ex)
-            {
-                Console.ForegroundColor = ConsoleColor.Red;
-                Console.WriteLine("Fatal error encountered:");
-                Console.WriteLine(ex.Message);
-                Console.ResetColor();
-            }
-        }
-
-        static void DisplayUsage()
-        {
-            Console.WriteLine("MakeIncremental usage: MakeIncremental.exe /i:\"source file\" [/textures]");
-        }
-    }
-}

+ 0 - 36
Tools/MakeIncremental/Properties/AssemblyInfo.cs

@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("MakeIncremental")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("MakeIncremental")]
-[assembly: AssemblyCopyright("Copyright ©  2013")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible 
-// to COM components.  If you need to access a type in this assembly from 
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("863a000d-e69f-4e3b-a150-1e75094c9024")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]

+ 35 - 0
Viewer/README.md

@@ -0,0 +1,35 @@
+# BabylonJS Viewer
+
+This project is a 3d model viewer using babylonjs.
+
+Please note that this is an *initial release*. The API and project structure could (and probably SHOULD) be changed, so please don't rely on this yet in a productive environment.
+
+The viewer is using the latest Babylon from npm (3.1 alpha).
+
+This documentation is also not full. I will slowly add more and more exmplanations.
+
+## Basic usage
+
+See `basicExample.html` in `/dist`.
+
+Basically, all that is needed is an html tag, and the viewer.js, which includes everything needed to render a Scene:
+
+```html
+<babylon model="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/BoomBox/glTF/BoomBox.gltf" default-viewer="true"></babylon>
+<script src="viewer.js"></script>
+``` 
+
+This will create a (default) viewer and will load the model in this URL using the gltf loader.
+
+The `babylon` tag will be automatically initialized. 
+
+## Configuration
+
+Configuration can be provided using html attributes or a JSON (at the moment). A configuration Mapper can be registered to create new configuration readers. 
+
+Before I finish a full documentation, take a look at `configuration.ts`
+
+## Templating
+
+The default templates are integrated in the viewer.js file. The current templates are located in `/assets/templates/default/` . Those templates can be extended and registered using the configuration file.
+

BIN
Viewer/assets/img/fullscreen.png


BIN
Viewer/assets/img/loading.png


+ 30 - 0
Viewer/assets/templates/default/defaultTemplate.html

@@ -0,0 +1,30 @@
+<style>
+    loading-screen {
+        position: absolute;
+        z-index: 100;
+        opacity: 1;
+        pointer-events: none;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        -webkit-transition: opacity 1.5s ease;
+        -moz-transition: opacity 1.5s ease;
+        transition: opacity 1.5s ease;
+    }
+
+    viewer {
+        position: relative;
+        overflow: hidden;
+        /* Start stage */
+        flex: 1;
+        z-index: 1;
+        justify-content: center;
+        align-items: center;
+
+        width: 100%;
+        height: 100%;
+    }
+</style>
+
+<viewer></viewer>
+<loading-screen></loading-screen>

+ 39 - 0
Viewer/assets/templates/default/defaultViewer.html

@@ -0,0 +1,39 @@
+<style>
+    .babylonjs-canvas {
+        flex: 1;
+        width: 100%;
+        height: 100%;
+        touch-action: none;
+    }
+
+    nav-bar {
+        position: absolute;
+        height: 160px;
+        width: 100%;
+        bottom: 0;
+        background-color: rgba(0, 0, 0, 0.3);
+        color: white;
+        transition: 1s;
+
+        align-items: center;
+        justify-content: center;
+        display: flex;
+
+        flex-direction: column;
+    }
+
+    /* Big screens have room for the entire navbar */
+
+    @media screen and (min-width: 768px) {
+        nav-bar {
+            flex-direction: row;
+            justify-content: space-between;
+            height: 80px;
+        }
+    }
+</style>
+
+<canvas class="babylonjs-canvas" id="{{canvasId}}">
+</canvas>
+
+<nav-bar></nav-bar>

+ 26 - 0
Viewer/assets/templates/default/loadingScreen.html

@@ -0,0 +1,26 @@
+<style>
+    img.loading-image {
+        -webkit-animation: spin 2s linear infinite;
+        animation: spin 2s linear infinite;
+    }
+
+    @-webkit-keyframes spin {
+        0% {
+            -webkit-transform: rotate(0deg);
+        }
+        100% {
+            -webkit-transform: rotate(360deg);
+        }
+    }
+
+    @keyframes spin {
+        0% {
+            transform: rotate(0deg);
+        }
+        100% {
+            transform: rotate(360deg);
+        }
+    }
+</style>
+
+<img class="loading-image" src="{{loadingImage}}">

+ 69 - 0
Viewer/assets/templates/default/navbar.html

@@ -0,0 +1,69 @@
+<style>
+    div.flex-container {
+        display: flex;
+    }
+
+    div.thumbnail {
+        position: relative;
+        overflow: hidden;
+        display: block;
+        width: 40px;
+        height: 40px;
+        background-size: cover;
+        background-position: center;
+        border-radius: 20px;
+        margin: 0 10px;
+    }
+
+    div.title-container {
+        flex-direction: column;
+        display: flex;
+        justify-content: space-between;
+    }
+
+    span.model-title {
+        font-size: 125%;
+    }
+
+    span.model-subtitle {
+        font-size: 90%;
+    }
+
+    div.button-container {
+        align-items: center;
+        display: flex;
+    }
+
+    div.button {
+        cursor: pointer;
+        height: 30px;
+        margin: 0 10px;
+    }
+
+    div.button img {
+        height: 100%;
+    }
+</style>
+
+<div class="flex-container" id="model-metadata">
+    <!-- holding the description -->
+    <div class="thumbnail">
+        <!-- holding the thumbnail 
+        <img src="{{thumbnail}}" alt="{{title}}">-->
+    </div>
+    <div class="title-container">
+
+        <span class="model-title">{{#if title}}{{title}}{{/if}}</span>
+        <span class="model-subtitle"> {{#if subtitle}}{{subtitle}} {{/if}}</span>
+    </div>
+</div>
+<div class="button-container">
+    <!-- holding the buttons -->
+    {{#each buttons}}
+    <div id="{{id}}" class="button">
+        {{#if text}}
+        <span>{{text}}</span>> {{/if}} {{#if image}}
+        <img src="{{image}}" alt="{{altText}}"> {{/if}}
+    </div>
+    {{/each}}
+</div>

+ 26 - 0
Viewer/dist/basicExample.html

@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html lang="en">
+
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+        <meta http-equiv="X-UA-Compatible" content="ie=edge">
+        <title>BabylonJS Viewer - Basic usage</title>
+        <style>
+            babylon {
+                width: 800px;
+                height: 500px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <babylon model.title="Amazing Rabbit" model.subtitle="BabylonJS" model.thumbnail="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png"
+            model.url="https://playground.babylonjs.com/scenes/Rabbit.babylon" default-viewer="true"></babylon>
+        <script src="viewer.js"></script>
+    </body>
+
+</html>
+<html>
+
+</html>

+ 41 - 0
Viewer/dist/domExample.html

@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html lang="en">
+
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+        <meta http-equiv="X-UA-Compatible" content="ie=edge">
+        <title>BabylonJS Viewer - DOM usage</title>
+        <style>
+            babylon {
+                width: 800px;
+                height: 500px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <babylon default-viewer="true">
+            <model url="https://ugcorigin.s-microsoft.com/12/2e77b8e3-0000-0000-7a48-6505db2f0ef9/952/1508427934473.gltf" title="The Bus!"
+                subtitle="Remix3D" thumbnail="http://d33wubrfki0l68.cloudfront.net/7e08139ddee0ec38005f4232346c7f7386831300/fd934/githubuniverse/remix3d.png">
+            </model>
+            <camera>
+                <behaviors array="true">
+                    <behavior type="0"></behavior>
+                </behaviors>
+            </camera>
+            <lights array="true">
+                <light type="1" shadow-enabled="true" position.y="0.5" direction.y="-1" intensity="4.5">
+                    <shadow-config use-blur-exponential-shadow-map="true" use-kernel-blur="true" blur-kernel="64" blur-scale="4">
+
+                    </shadow-config>
+                </light>
+            </lights>
+        </babylon>
+        <script src="viewer.js"></script>
+    </body>
+
+</html>
+<html>
+
+</html>

BIN
Viewer/dist/environment.dds


File diff suppressed because it is too large
+ 104839 - 0
Viewer/dist/viewer.js


+ 48 - 0
Viewer/package.json

@@ -0,0 +1,48 @@
+{
+    "name": "babylonjs-viewer",
+    "version": "0.1.0",
+    "description": "A viewer using BabylonJS to display 3D elements natively",
+    "scripts": {
+        "start:server": "webpack-dev-server",
+        "build": "webpack",
+        "test": "echo \"Error: no test specified\" && exit 1"
+    },
+    "repository": {
+        "type": "git",
+        "url": "git+https://github.com/BabylonJS/Babylon.js.git"
+    },
+    "keywords": [
+        "3d",
+        "webgl",
+        "viewer"
+    ],
+    "author": "Raanan Weber",
+    "license": "Apache2",
+    "bugs": {
+        "url": "https://github.com/BabylonJS/Babylon.js/issues"
+    },
+    "homepage": "https://github.com/BabylonJS/Babylon.js#readme",
+    "devDependencies": {
+        "@types/node": "^8.0.44",
+        "base64-image-loader": "^1.2.0",
+        "html-loader": "^0.5.1",
+        "json-loader": "^0.5.7",
+        "ts-loader": "^2.3.7",
+        "typescript": "^2.5.3",
+        "uglifyjs-webpack-plugin": "^1.0.0-beta.3",
+        "webpack": "^3.8.1",
+        "webpack-dev-server": "^2.9.2"
+    },
+    "dependencies": {
+        "babylonjs": "^3.1.0-alpha3.6",
+        "babylonjs-loaders": "^3.1.0-alpha3.6",
+        "babylonjs-materials": "^3.1.0-alpha3.6",
+        "babylonjs-post-process": "^3.1.0-alpha3.6",
+        "babylonjs-procedural-textures": "^3.1.0-alpha3.6",
+        "es6-promise": "^4.1.1",
+        "handlebars": "^4.0.11",
+        "lodash": "^4.17.4",
+        "lodash.merge": "^4.6.0",
+        "promise-polyfill": "^6.0.2"
+    }
+}

File diff suppressed because it is too large
+ 269 - 0
Viewer/src/configuration/configuration.ts


+ 0 - 0
Viewer/src/configuration/index.ts


+ 76 - 0
Viewer/src/configuration/loader.ts

@@ -0,0 +1,76 @@
+import { mapperManager } from './mappers';
+import { ViewerConfiguration, defaultConfiguration } from './configuration';
+
+import * as merge from 'lodash.merge';
+
+export class ConfigurationLoader {
+
+    private configurationCache: { (url: string): any };
+
+    public loadConfiguration(initConfig: ViewerConfiguration = {}): Promise<ViewerConfiguration> {
+
+        let loadedConfig = merge({}, initConfig);
+
+        if (loadedConfig.defaultViewer) {
+            loadedConfig = merge(loadedConfig, defaultConfiguration);
+        } else {
+            loadedConfig = merge(defaultConfiguration, loadedConfig);
+        }
+
+        if (loadedConfig.configuration) {
+
+            let mapperType = "json";
+            let url = loadedConfig.configuration;
+
+            // if configuration is an object
+            if (loadedConfig.configuration.url) {
+                url = loadedConfig.configuration.url;
+                mapperType = loadedConfig.configuration.mapper;
+                if (!mapperType) {
+                    // load mapper type from filename / url
+                    mapperType = loadedConfig.configuration.url.split('.').pop();
+                }
+            }
+
+            let mapper = mapperManager.getMapper(mapperType);
+            return this.loadFile(url).then((data: any) => {
+                let parsed = mapper.map(data);
+                return merge(loadedConfig, parsed);
+            });
+        } else {
+            return Promise.resolve(loadedConfig);
+        }
+    }
+
+    private loadFile(url: string): Promise<any> {
+        let cacheReference = this.configurationCache;
+        if (cacheReference[url]) {
+            return Promise.resolve(cacheReference[url]);
+        }
+
+        return new Promise(function (resolve, reject) {
+            var xhr = new XMLHttpRequest();
+            xhr.open('GET', url);
+            xhr.send();
+            xhr.onreadystatechange = function () {
+                var DONE = 4;
+                var OK = 200;
+                if (xhr.readyState === DONE) {
+                    if (xhr.status === OK) {
+                        cacheReference[url] = xhr.responseText;
+                        resolve(xhr.responseText); // 'This is the returned text.'
+                    }
+                } else {
+                    console.log('Error: ' + xhr.status, url);
+                    reject('Error: ' + xhr.status); // An error occurred during the request.
+                }
+            }
+        });
+    }
+
+
+}
+
+export let configurationLoader = new ConfigurationLoader();
+
+export default configurationLoader;

+ 123 - 0
Viewer/src/configuration/mappers.ts

@@ -0,0 +1,123 @@
+import { Tools } from 'babylonjs';
+import { ViewerConfiguration } from './configuration';
+
+import { kebabToCamel } from '../helper';
+
+import * as merge from 'lodash.merge';
+
+export interface IMapper {
+    map(rawSource: any): ViewerConfiguration;
+}
+
+class HTMLMapper implements IMapper {
+
+    map(element: HTMLElement): ViewerConfiguration {
+
+        let config = {};
+        for (let attrIdx = 0; attrIdx < element.attributes.length; ++attrIdx) {
+            let attr = element.attributes.item(attrIdx);
+            // map "object.property" to the right configuration place.
+            let split = attr.nodeName.split('.');
+            split.reduce((currentConfig, key, idx) => {
+                //convert html-style to json-style
+                let camelKey = kebabToCamel(key);
+                if (idx === split.length - 1) {
+                    let val: any = attr.nodeValue;
+                    if (val === "true") {
+                        val = true;
+                    } else if (val === "false") {
+                        val = false;
+                    } else {
+                        let number = parseFloat(val);
+                        if (!isNaN(number)) {
+                            val = number;
+                        }
+                    }
+                    currentConfig[camelKey] = val;
+                } else {
+                    currentConfig[camelKey] = currentConfig[camelKey] || {};
+                }
+                return currentConfig[camelKey];
+            }, config);
+        }
+
+        return config;
+    }
+}
+
+class JSONMapper implements IMapper {
+    map(rawSource: any) {
+        return JSON.parse(rawSource);
+    }
+}
+
+// TODO - Dom configuration mapper.
+class DOMMapper implements IMapper {
+
+    map(baseElement: HTMLElement): ViewerConfiguration {
+        let htmlMapper = new HTMLMapper();
+        let config = htmlMapper.map(baseElement);
+
+        let traverseChildren = function (element: HTMLElement, partConfig) {
+            let children = element.children;
+            if (children.length) {
+                for (let i = 0; i < children.length; ++i) {
+                    let item = <HTMLElement>children.item(i);
+                    let configMapped = htmlMapper.map(item);
+                    let key = kebabToCamel(item.nodeName.toLowerCase());
+                    if (item.attributes.getNamedItem('array') && item.attributes.getNamedItem('array').nodeValue === 'true') {
+                        partConfig[key] = [];
+                    } else {
+                        if (element.attributes.getNamedItem('array') && element.attributes.getNamedItem('array').nodeValue === 'true') {
+                            partConfig.push(configMapped)
+                        } else if (partConfig[key]) {
+                            //exists already! problem... probably an array
+                            element.setAttribute('array', 'true');
+                            let oldItem = partConfig[key];
+                            partConfig = [oldItem, configMapped]
+                        } else {
+                            partConfig[key] = configMapped;
+                        }
+                    }
+                    traverseChildren(item, partConfig[key] || configMapped);
+                }
+            }
+            return partConfig;
+        }
+
+        traverseChildren(baseElement, config);
+
+
+        return config;
+    }
+
+}
+
+export class MapperManager {
+
+    private mappers: { [key: string]: IMapper };
+    public static DefaultMapper = 'json';
+
+    constructor() {
+        this.mappers = {
+            "html": new HTMLMapper(),
+            "json": new JSONMapper(),
+            "dom": new DOMMapper()
+        }
+    }
+
+    public getMapper(type: string) {
+        if (!this.mappers[type]) {
+            Tools.Error("No mapper defined for " + type);
+        }
+        return this.mappers[type] || this.mappers[MapperManager.DefaultMapper];
+    }
+
+    public registerMapper(type: string, mapper: IMapper) {
+        this.mappers[type] = mapper;
+    }
+
+}
+
+export let mapperManager = new MapperManager();
+export default mapperManager;

+ 41 - 0
Viewer/src/helper.ts

@@ -0,0 +1,41 @@
+export function isUrl(urlToCheck: string): boolean {
+    if (urlToCheck.indexOf('http') === 0 || urlToCheck.indexOf('/') === 0 || urlToCheck.indexOf('./') === 0 || urlToCheck.indexOf('../') === 0) {
+        return true;
+    }
+    return false;
+}
+
+export function loadFile(url: string): Promise<any> {
+    /*let cacheReference = this.configurationCache;
+    if (cacheReference[url]) {
+        return Promise.resolve(cacheReference[url]);
+    }*/
+
+    return new Promise(function (resolve, reject) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url);
+        xhr.send();
+        xhr.onreadystatechange = function () {
+            var DONE = 4;
+            var OK = 200;
+            if (xhr.readyState === DONE) {
+                if (xhr.status === OK) {
+                    //cacheReference[url] = xhr.responseText;
+                    resolve(xhr.responseText); // 'This is the returned text.'
+                }
+            } else {
+                console.log('Error: ' + xhr.status, url);
+                reject('Error: ' + xhr.status); // An error occurred during the request.
+            }
+        }
+    });
+}
+
+export function kebabToCamel(s) {
+    return s.replace(/(\-\w)/g, function (m) { return m[1].toUpperCase(); });
+}
+
+//https://gist.github.com/youssman/745578062609e8acac9f
+export function camelToKebab(str) {
+    return !str ? null : str.replace(/([A-Z])/g, function (g) { return '-' + g[0].toLowerCase() });
+}

+ 23 - 0
Viewer/src/index.ts

@@ -0,0 +1,23 @@
+import { AbstractViewer } from './viewer/viewer';
+
+/**
+ * BabylonJS Viewer
+ * 
+ * An HTML-Based viewer for 3D models, based on BabylonJS and its extensions.
+ */
+
+
+// load babylon and needed modules.
+import 'babylonjs';
+import 'babylonjs-loaders';
+import 'babylonjs-materials';
+
+import { InitTags } from './initializer';
+
+// promise polyfill
+global.Promise = require('es6-promise').Promise;
+
+InitTags();
+
+// public API for initialization
+export { AbstractViewer, InitTags };

+ 15 - 0
Viewer/src/initializer.ts

@@ -0,0 +1,15 @@
+import { DefaultViewer } from './viewer/defaultViewer';
+import { mapperManager } from './configuration/mappers';
+
+export function InitTags(selector: string = 'babylon') {
+    let elements = document.querySelectorAll(selector);
+    for (let i = 0; i < elements.length; ++i) {
+        let element: HTMLElement = <HTMLElement>elements.item(i);
+
+        // get the html configuration
+        let configMapper = mapperManager.getMapper('dom');
+        let config = configMapper.map(element);
+
+        let viewer = new DefaultViewer(element, config);
+    }
+}

+ 5 - 0
Viewer/src/interfaces.ts

@@ -0,0 +1,5 @@
+export const enum CameraBehavior {
+    AUTOROTATION,
+    BOUNCING,
+    FRAMING
+}

+ 248 - 0
Viewer/src/templateManager.ts

@@ -0,0 +1,248 @@
+
+import { Observable } from 'babylonjs';
+import { isUrl, loadFile, camelToKebab } from './helper';
+
+
+export interface TemplateConfiguration {
+    location?: string; // #template-id OR http://example.com/loading.html
+    html?: string; // raw html string
+    id?: string;
+    config?: { [key: string]: string | number | boolean | object };
+    events?: {
+        // pointer events
+        pointerdown?: boolean | Array<string>;
+        pointerup?: boolean | Array<string>;
+        pointermove?: boolean | Array<string>;
+        pointerover?: boolean | Array<string>;
+        pointerout?: boolean | Array<string>;
+        pointerenter?: boolean | Array<string>;
+        pointerleave?: boolean | Array<string>;
+        pointercancel?: boolean | Array<string>;
+        //click, just in case
+        click?: boolean | Array<string>;
+        // drag and drop
+        dragstart?: boolean | Array<string>;
+        drop?: boolean | Array<string>;
+
+        [key: string]: boolean | Array<string>;
+    }
+    children?: { [name: string]: TemplateConfiguration };
+}
+
+export interface EventCallback {
+    event: Event;
+    template: Template;
+    selector: string;
+    payload?: any;
+}
+
+export class TemplateManager {
+
+    public onInit: Observable<Template>;
+    public onLoaded: Observable<Template>;
+    public onStateChange: Observable<Template>;
+    public onAllLoaded: Observable<TemplateManager>;
+
+    private templates: { [name: string]: Template };
+
+    constructor(public containerElement: HTMLElement) {
+        this.templates = {};
+
+        this.onInit = new Observable<Template>();
+        this.onLoaded = new Observable<Template>();
+        this.onStateChange = new Observable<Template>();
+        this.onAllLoaded = new Observable<TemplateManager>();
+    }
+
+    public initTemplate(configuration: TemplateConfiguration, name: string = 'main', parentTemplate?: Template) {
+        //init template
+        let template = new Template(name, configuration);
+        this.templates[name] = template;
+
+        let childrenMap = configuration.children || {};
+        let childrenTemplates = Object.keys(childrenMap).map(name => {
+            return this.initTemplate(configuration.children[name], name, template);
+        });
+
+        // register the observers
+        template.onLoaded.add(() => {
+            let addToParent = () => {
+                let containingElement = parentTemplate && parentTemplate.parent.querySelector(camelToKebab(name)) || this.containerElement;
+                template.appendTo(containingElement);
+                this.checkLoadedState();
+            }
+
+            if (parentTemplate && !parentTemplate.parent) {
+                parentTemplate.onAppended.add(() => {
+                    addToParent();
+                });
+            } else {
+                addToParent();
+            }
+        });
+
+        return template;
+    }
+
+    // assumiung only ONE(!) canvas
+    public getCanvas(): HTMLCanvasElement {
+        return this.containerElement.querySelector('canvas');
+    }
+
+    public getTemplate(name: string) {
+        return this.templates[name];
+    }
+
+    private checkLoadedState() {
+        let done = Object.keys(this.templates).every((key) => {
+            return this.templates[key].isLoaded && !!this.templates[key].parent;
+        });
+
+        if (done) {
+            this.onAllLoaded.notifyObservers(this);
+        }
+    }
+
+}
+
+
+import * as Handlebars from 'handlebars/dist/handlebars.min.js';
+
+export class Template {
+
+    public onInit: Observable<Template>;
+    public onLoaded: Observable<Template>;
+    public onAppended: Observable<Template>;
+    public onStateChange: Observable<Template>;
+    public onEventTriggered: Observable<EventCallback>;
+
+    public isLoaded: boolean;
+
+    public parent: HTMLElement;
+
+    private fragment: DocumentFragment;
+
+    constructor(public name: string, private configuration: TemplateConfiguration) {
+        this.onInit = new Observable<Template>();
+        this.onLoaded = new Observable<Template>();
+        this.onAppended = new Observable<Template>();
+        this.onStateChange = new Observable<Template>();
+        this.onEventTriggered = new Observable<EventCallback>();
+
+        this.isLoaded = false;
+        /*
+        if (configuration.id) {
+            this.parent.id = configuration.id;
+        }
+        */
+        this.onInit.notifyObservers(this);
+
+        let htmlContentPromise = getTemplateAsHtml(configuration);
+
+        htmlContentPromise.then(htmlTemplate => {
+            if (htmlTemplate) {
+                let compiledTemplate = Handlebars.compile(htmlTemplate);
+                let config = this.configuration.config || {};
+                let rawHtml = compiledTemplate(config);
+                this.fragment = document.createRange().createContextualFragment(rawHtml);
+                this.isLoaded = true;
+                this.onLoaded.notifyObservers(this);
+            }
+        });
+    }
+
+    public appendTo(parent: HTMLElement) {
+        if (this.parent) {
+            console.error('Alread appanded to ', this.parent);
+        } else {
+            this.parent = parent;
+
+            if (this.configuration.id) {
+                this.parent.id = this.configuration.id;
+            }
+            this.parent.appendChild(this.fragment);
+            // appended only one frame after.
+            setTimeout(() => {
+                this.registerEvents();
+                this.onAppended.notifyObservers(this);
+            });
+        }
+
+    }
+
+    public show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
+        if (visibilityFunction) {
+            return visibilityFunction(this).then(() => {
+                this.onStateChange.notifyObservers(this);
+                return this;
+            });
+        } else {
+            // flex? box? should this be configurable easier than the visibilityFunction?
+            this.parent.style.display = 'flex';
+            this.onStateChange.notifyObservers(this);
+            return Promise.resolve(this);
+        }
+    }
+
+    public hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
+        if (visibilityFunction) {
+            return visibilityFunction(this).then(() => {
+                this.onStateChange.notifyObservers(this);
+                return this;
+            });
+        } else {
+            this.parent.style.display = 'none';
+            this.onStateChange.notifyObservers(this);
+            return Promise.resolve(this);
+        }
+    }
+
+    // TODO - Should events be removed as well? when are templates disposed?
+    private registerEvents() {
+        if (this.configuration.events) {
+            Object.keys(this.configuration.events).forEach(eventName => {
+                if (this.configuration.events[eventName]) {
+                    let functionToFire = (selector, event) => {
+                        this.onEventTriggered.notifyObservers({ event: event, template: this, selector: selector });
+                    }
+
+                    // if boolean, set the parent as the event listener
+                    if (typeof this.configuration.events[eventName] === 'boolean') {
+                        this.parent.addEventListener(eventName, functionToFire.bind(this, '#' + this.parent.id), false);
+                    } else {
+                        let selectorsArray: Array<string> = <Array<string>>this.configuration.events[eventName];
+                        selectorsArray.forEach(selector => {
+                            let htmlElement = <HTMLElement>this.parent.querySelector(selector);
+                            htmlElement && htmlElement.addEventListener(eventName, functionToFire.bind(this, selector), false)
+                        });
+                    }
+                }
+            });
+        }
+    }
+
+}
+
+export function getTemplateAsHtml(templateConfig: TemplateConfiguration): Promise<string> {
+    if (!templateConfig) {
+        return Promise.resolve(undefined);
+    } else if (templateConfig.html) {
+        return Promise.resolve(templateConfig.html);
+    } else {
+        let location = getTemplateLocation(templateConfig);
+        if (isUrl(location)) {
+            return loadFile(location);
+        } else {
+            location = location.replace('#', '');
+            document.getElementById('#' + location);
+        }
+    }
+}
+
+export function getTemplateLocation(templateConfig): string {
+    if (!templateConfig || typeof templateConfig === 'string') {
+        return templateConfig;
+    } else {
+        return templateConfig.location;
+    }
+}

+ 333 - 0
Viewer/src/viewer/defaultViewer.ts

@@ -0,0 +1,333 @@
+import { Template } from './../templateManager';
+import { AbstractViewer } from './viewer';
+import { Observable, ShadowLight, CubeTexture, BouncingBehavior, FramingBehavior, Behavior, Light, Engine, Scene, AutoRotationBehavior, AbstractMesh, Quaternion, StandardMaterial, ShadowOnlyMaterial, ArcRotateCamera, ImageProcessingConfiguration, Color3, Vector3, SceneLoader, Mesh, HemisphericLight } from 'babylonjs';
+import { CameraBehavior } from '../interfaces';
+
+// A small hack for the inspector. to be removed!
+import * as BABYLON from 'babylonjs';
+window['BABYLON'] = BABYLON;
+
+export class DefaultViewer extends AbstractViewer {
+
+    private camera: ArcRotateCamera;
+
+    public initScene(): Promise<Scene> {
+        return super.initScene().then(() => {
+            this.extendClassWithConfig(this.scene, this.configuration.scene);
+            return this.scene;
+        })
+    }
+
+    protected onTemplatesLoaded() {
+
+        this.showLoadingScreen();
+
+        // navbar
+        let viewerElement = this.templateManager.getTemplate('viewer');
+        let navbar = this.templateManager.getTemplate('navBar');
+
+        let nextHeight: string = '0px';
+
+        viewerElement.parent.addEventListener('pointerover', () => {
+            let currentHeight = navbar.parent.clientHeight + 'px';
+            navbar.parent.style.bottom = nextHeight;
+            nextHeight = '-' + currentHeight;
+            console.log(nextHeight, currentHeight);
+        });
+
+        viewerElement.parent.addEventListener('pointerout', () => {
+            navbar.parent.style.bottom = nextHeight;
+            nextHeight = '0px';
+        });
+
+        // events registration
+        this.registerFullscreenMode();
+
+        return super.onTemplatesLoaded();
+    }
+
+    private registerFullscreenMode() {
+        let isFullscreen = false;
+
+        let navbar = this.templateManager.getTemplate('navBar');
+        let viewerElement = this.templateManager.getTemplate('viewer').parent;
+
+        navbar.onEventTriggered.add((data) => {
+            switch (data.event.type) {
+                case 'pointerdown':
+                    let event: PointerEvent = <PointerEvent>data.event;
+                    if (event.button === 0) {
+                        if (data.selector === '#fullscreen-button') {
+                            //this.engine.switchFullscreen(false);
+                            if (!isFullscreen) {
+                                let requestFullScreen = viewerElement.requestFullscreen || /*viewerElement.parent.msRequestFullscreen || viewerElement.parent.mozRequestFullScreen ||*/ viewerElement.webkitRequestFullscreen;
+                                requestFullScreen.call(viewerElement);
+                            } else {
+                                let exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
+                                exitFullscreen.call(document);
+                            }
+
+                            isFullscreen = !isFullscreen;
+
+                        }
+
+                    }
+                    break;
+            }
+        });
+
+    }
+
+    protected prepareContainerElement() {
+        this.containerElement.style.position = 'relative';
+        this.containerElement.style.display = 'flex';
+    }
+
+    public loadModel(model: any = this.configuration.model): Promise<Scene> {
+        this.showLoadingScreen();
+        return super.loadModel(model, true);
+    }
+
+    public onModelLoaded(meshes: Array<AbstractMesh>) {
+
+        // here we could set the navbar's model information:
+        this.setModelMetaData();
+
+        this.hideLoadingScreen();
+
+        // recreate the camera
+        this.scene.createDefaultCameraOrLight(true, true, true);
+        this.camera = <ArcRotateCamera>this.scene.activeCamera;
+
+        meshes[0].rotation.y += Math.PI;
+
+        this.setupCamera(meshes);
+        this.setupLights(meshes);
+
+        return this.initEnvironment();
+    }
+
+    private setModelMetaData() {
+        let navbar = this.templateManager.getTemplate('navBar');
+
+        let metadataContainer = navbar.parent.querySelector('#model-metadata');
+
+        //title
+        if (typeof this.configuration.model === 'object') {
+            if (this.configuration.model.title) {
+                metadataContainer.querySelector('span.model-title').innerHTML = this.configuration.model.title;
+            }
+
+            if (this.configuration.model.subtitle) {
+                metadataContainer.querySelector('span.model-subtitle').innerHTML = this.configuration.model.subtitle;
+            }
+
+            if (this.configuration.model.thumbnail) {
+                (<HTMLDivElement>metadataContainer.querySelector('.thumbnail')).style.backgroundImage = `url('${this.configuration.model.thumbnail}')`;
+            }
+        }
+
+    }
+
+    public initEnvironment(): Promise<Scene> {
+        if (this.configuration.skybox) {
+            // Define a general environment textue
+            let texture;
+            // this is obligatory, but still - making sure it is there.
+            if (this.configuration.skybox.cubeTexture) {
+                if (typeof this.configuration.skybox.cubeTexture.url === 'string') {
+                    texture = CubeTexture.CreateFromPrefilteredData(this.configuration.skybox.cubeTexture.url, this.scene);
+                } else {
+                    texture = CubeTexture.CreateFromImages(this.configuration.skybox.cubeTexture.url, this.scene, this.configuration.skybox.cubeTexture.noMipMap);
+                }
+            }
+            if (texture) {
+                this.extendClassWithConfig(texture, this.configuration.skybox.cubeTexture);
+
+                let scale = this.configuration.skybox.scale || (this.scene.activeCamera.maxZ - this.scene.activeCamera.minZ) / 2;
+
+                let box = this.scene.createDefaultSkybox(texture, this.configuration.skybox.pbr, scale, this.configuration.skybox.blur);
+
+                // before extending, set the material's imageprocessing configuration object, if needed:
+                if (this.configuration.skybox.material && this.configuration.skybox.material.imageProcessingConfiguration) {
+                    (<StandardMaterial>box.material).imageProcessingConfiguration = new ImageProcessingConfiguration();
+                }
+
+                this.extendClassWithConfig(box, this.configuration.skybox);
+            }
+        }
+
+        if (this.configuration.ground) {
+            let groundConfig = (typeof this.configuration.ground === 'boolean') ? {} : this.configuration.ground;
+
+            var ground = Mesh.CreateGround('ground', groundConfig.size || 1000, groundConfig.size || 1000, 8, this.scene);
+            if (this.configuration.ground === true || groundConfig.shadowOnly) {
+                ground.material = new ShadowOnlyMaterial('groundmat', this.scene);
+            } else {
+                ground.material = new StandardMaterial('groundmat', this.scene);
+            }
+            //default configuration
+            if (this.configuration.ground === true) {
+                ground.receiveShadows = true;
+                ground.material.alpha = 0.4;
+            }
+
+
+            this.extendClassWithConfig(ground, groundConfig);
+        }
+
+        return Promise.resolve(this.scene);
+    }
+
+    public showLoadingScreen() {
+        return this.templateManager.getTemplate('loadingScreen').show((template => {
+
+            var canvasRect = this.containerElement.getBoundingClientRect();
+            var canvasPositioning = window.getComputedStyle(this.containerElement).position;
+
+            template.parent.style.display = 'flex';
+            template.parent.style.width = canvasRect.width + "px";
+            template.parent.style.height = canvasRect.height + "px";
+            template.parent.style.opacity = "1";
+            // from the configuration!!!
+            template.parent.style.backgroundColor = "black";
+            return Promise.resolve(template);
+        }));
+    }
+
+    public hideLoadingScreen() {
+        return this.templateManager.getTemplate('loadingScreen').hide((template => {
+            template.parent.style.opacity = "0";
+            let onTransitionEnd = () => {
+                template.parent.removeEventListener("transitionend", onTransitionEnd);
+                template.parent.style.display = 'none';
+            }
+            template.parent.addEventListener("transitionend", onTransitionEnd);
+            return Promise.resolve(template);
+        }));
+    }
+
+    private setupLights(focusMeshes: Array<AbstractMesh> = []) {
+        if (!this.configuration.scene.defaultLight && (this.configuration.lights && this.configuration.lights.length)) {
+            // remove old lights
+            this.scene.lights.forEach(l => {
+                l.dispose();
+            });
+
+            this.configuration.lights.forEach((lightConfig, idx) => {
+                lightConfig.name = lightConfig.name || 'light-' + idx;
+                let constructor = Light.GetConstructorFromName(lightConfig.type, lightConfig.name, this.scene);
+                let light = constructor();
+
+                //enabled
+                if (light.isEnabled() !== !lightConfig.disabled) {
+                    light.setEnabled(!lightConfig.disabled);
+                }
+
+                this.extendClassWithConfig(light, lightConfig);
+
+                //position. Some lights don't support shadows
+                if (light instanceof ShadowLight) {
+                    if (lightConfig.shadowEnabled) {
+                        var shadowGenerator = new BABYLON.ShadowGenerator(512, light)
+                        this.extendClassWithConfig(shadowGenerator, lightConfig.shadowConfig || {});
+                        // add the focues meshes to the shadow list
+                        for (var index = 0; index < focusMeshes.length; index++) {
+                            shadowGenerator.getShadowMap().renderList.push(focusMeshes[index]);
+                        }
+                    }
+                }
+            });
+        }
+    }
+
+    private setupCamera(focusMeshes: Array<AbstractMesh> = []) {
+        if (this.configuration.scene.defaultCamera) {
+            return;
+        }
+
+        let cameraConfig = this.configuration.camera || {};
+
+        if (cameraConfig.position) {
+            this.camera.position.copyFromFloats(cameraConfig.position.x || 0, cameraConfig.position.y || 0, cameraConfig.position.z || 0);
+        }
+
+        if (cameraConfig.rotation) {
+            this.camera.rotationQuaternion = new Quaternion(cameraConfig.rotation.x || 0, cameraConfig.rotation.y || 0, cameraConfig.rotation.z || 0, cameraConfig.rotation.w || 0)
+        }
+
+        this.camera.minZ = cameraConfig.minZ || this.camera.minZ;
+        this.camera.maxZ = cameraConfig.maxZ || this.camera.maxZ;
+
+        if (cameraConfig.behaviors) {
+            cameraConfig.behaviors.forEach((behaviorConfig) => {
+                this.setCameraBehavior(behaviorConfig, focusMeshes);
+            });
+        };
+
+        if (this.configuration.scene.autoRotate) {
+            this.camera.useAutoRotationBehavior = true;
+        }
+    }
+
+    private setCameraBehavior(behaviorConfig: number | {
+        type: number;
+        [propName: string]: any;
+    }, payload: any) {
+
+        let behavior: Behavior<ArcRotateCamera>;
+        let type = (typeof behaviorConfig !== "object") ? behaviorConfig : behaviorConfig.type;
+
+        let config: { [propName: string]: any } = (typeof behaviorConfig === "object") ? behaviorConfig : {};
+
+        // constructing behavior
+        switch (type) {
+            case CameraBehavior.AUTOROTATION:
+                behavior = new AutoRotationBehavior();
+                break;
+            case CameraBehavior.BOUNCING:
+                behavior = new BouncingBehavior();
+                break;
+            case CameraBehavior.FRAMING:
+                behavior = new FramingBehavior();
+                break;
+        }
+
+        if (behavior) {
+            if (typeof behaviorConfig === "object") {
+                this.extendClassWithConfig(behavior, behaviorConfig);
+            }
+            this.camera.addBehavior(behavior);
+        }
+
+        // post attach configuration. Some functionalities require the attached camera.
+        switch (type) {
+            case CameraBehavior.AUTOROTATION:
+                break;
+            case CameraBehavior.BOUNCING:
+                break;
+            case CameraBehavior.FRAMING:
+                if (config.zoomOnBoundingInfo) {
+                    //payload is an array of meshes
+                    let meshes = <Array<AbstractMesh>>payload;
+                    let bounding = meshes[0].getHierarchyBoundingVectors();
+                    (<FramingBehavior>behavior).zoomOnBoundingInfo(bounding.min, bounding.max);
+                }
+                break;
+        }
+    }
+
+    private extendClassWithConfig(object: any, config: any) {
+        Object.keys(config).forEach(key => {
+            if (key in object && typeof object[key] !== 'function') {
+                if (typeof object[key] === 'function') return;
+                // if it is an object, iterate internally until reaching basic types
+                if (typeof object[key] === 'object') {
+                    this.extendClassWithConfig(object[key], config[key]);
+                } else {
+                    object[key] = config[key];
+                }
+            }
+        });
+    }
+}

+ 134 - 0
Viewer/src/viewer/viewer.ts

@@ -0,0 +1,134 @@
+import { TemplateManager } from './../templateManager';
+import configurationLoader from './../configuration/loader';
+import { Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight } from 'babylonjs';
+import { ViewerConfiguration } from '../configuration/configuration';
+
+export abstract class AbstractViewer {
+
+    public templateManager: TemplateManager;
+
+    public engine: Engine;
+    public scene: Scene;
+    public baseId: string;
+
+    protected configuration: ViewerConfiguration;
+
+    constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = { defaultViewer: true }) {
+        // if exists, use the container id. otherwise, generate a random string.
+        if (containerElement.id) {
+            this.baseId = containerElement.id;
+        } else {
+            this.baseId = containerElement.id = 'bjs' + Math.random().toString(32).substr(2, 8);
+        }
+
+        this.templateManager = new TemplateManager(containerElement);
+
+        this.prepareContainerElement();
+
+        // extend the configuration
+        configurationLoader.loadConfiguration(initialConfiguration).then((configuration) => {
+            this.configuration = configuration;
+            // initialize the templates
+            this.templateManager.initTemplate(this.configuration.template);
+            // when done, execute onTemplatesLoaded()
+            this.templateManager.onAllLoaded.add(() => {
+                this.onTemplatesLoaded();
+            })
+        });
+
+    }
+
+    public getBaseId(): string {
+        return this.baseId;
+    }
+
+    protected abstract prepareContainerElement();
+
+    /**
+     * This function will execute when the HTML templates finished initializing.
+     * It should initialize the engine and continue execution.
+     * 
+     * @protected
+     * @returns {Promise<AbstractViewer>} The viewer object will be returned after the object was loaded.
+     * @memberof AbstractViewer
+     */
+    protected onTemplatesLoaded(): Promise<AbstractViewer> {
+        return this.initEngine().then(() => {
+            return this.loadModel();
+        }).then(() => {
+            return this;
+        });
+    }
+
+    /**
+     * Initialize the engine. Retruns a promise in case async calls are needed.
+     * 
+     * @protected
+     * @returns {Promise<Engine>} 
+     * @memberof Viewer
+     */
+    protected initEngine(): Promise<Engine> {
+        let canvasElement = this.templateManager.getCanvas();
+        let config = this.configuration.engine || {};
+        // TDO enable further configuration
+        this.engine = new Engine(canvasElement, !!config.antialiasing);
+
+        window.addEventListener('resize', () => {
+            this.engine.resize();
+        });
+
+        this.engine.runRenderLoop(() => {
+            this.scene && this.scene.render();
+        });
+
+        var scale = Math.max(0.5, 1 / (window.devicePixelRatio || 2));
+        this.engine.setHardwareScalingLevel(scale);
+
+        return Promise.resolve(this.engine);
+    }
+
+    protected initScene(): Promise<Scene> {
+
+        // if the scen exists, dispose it.
+        if (this.scene) {
+            this.scene.dispose();
+        }
+
+        // create a new scene
+        this.scene = new Scene(this.engine);
+        // make sure there is a default camera and light.
+        this.scene.createDefaultCameraOrLight(true, true, true);
+        return Promise.resolve(this.scene);
+    }
+
+    public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
+        let modelUrl = (typeof model === 'string') ? model : model.url;
+        let parts = modelUrl.split('/');
+        let filename = parts.pop();
+        let base = parts.join('/') + '/';
+
+        return Promise.resolve().then(() => {
+            if (!this.scene || clearScene) return this.initScene();
+            else return this.scene;
+        }).then(() => {
+            return new Promise<Array<AbstractMesh>>((resolve, reject) => {
+                SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
+                    resolve(meshes);
+                }, undefined, (e, m, exception) => {
+                    console.log(m, exception);
+                    reject(m);
+                });
+            });
+        }).then((meshes: Array<AbstractMesh>) => {
+            return this.onModelLoaded(meshes);
+        });
+    }
+
+    protected onModelLoaded(meshes: Array<AbstractMesh>): Promise<Scene> {
+        console.log("model loaded");
+        return Promise.resolve(this.scene);
+    }
+
+    public abstract initEnvironment(): Promise<Scene>;
+
+}

+ 26 - 0
Viewer/tsconfig.json

@@ -0,0 +1,26 @@
+{
+    "compilerOptions": {
+        "target": "es5",
+        "module": "commonjs",
+        "noResolve": true,
+        "noImplicitAny": false, //mainly due to usage of external libs without typings.
+        "removeComments": true,
+        "preserveConstEnums": true,
+        "sourceMap": true,
+        "experimentalDecorators": true,
+        "isolatedModules": false,
+        "lib": [
+            "dom",
+            "es2015.promise",
+            "es5"
+        ],
+        //"declaration": true,
+        "outDir": "./temp/",
+        "types": [
+            "node",
+            "babylonjs",
+            "babylonjs-loaders",
+            "babylonjs-materials"
+        ]
+    }
+}

+ 63 - 0
Viewer/webpack.config.js

@@ -0,0 +1,63 @@
+const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
+const path = require('path');
+const webpack = require('webpack');
+
+module.exports = {
+    entry: {
+        'viewer': './src/index.ts',
+        //'viewer.min': './src/index.ts',
+    },
+    output: {
+        path: path.resolve(__dirname, 'dist'),
+        filename: '[name].js',
+        libraryTarget: 'umd',
+        library: 'Viewer3D',
+        umdNamedDefine: true,
+        devtoolModuleFilenameTemplate: '[absolute-resource-path]'
+    },
+    resolve: {
+        extensions: ['.ts', '.tsx', '.js']
+    },
+    devtool: 'source-map',
+    plugins: [
+        new webpack.WatchIgnorePlugin([
+            /\.d\.ts$/
+        ]),
+        /*new UglifyJSPlugin({
+
+            uglifyOptions: {
+                compress: {
+                    warnings: false,
+                },
+                output: {
+                    comments: false
+                }
+            },
+            sourceMap: true,
+            include: /\.min/,
+        })*/
+    ],
+    module: {
+        loaders: [{
+            test: /\.tsx?$/,
+            loader: 'ts-loader',
+            exclude: /node_modules/
+        },
+        {
+            test: /\.(html)$/,
+            use: {
+                loader: 'html-loader'
+            }
+        },
+        {
+            test: /\.(jpe?g|png|ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
+            use: 'base64-image-loader?limit=1000&name=[name].[ext]'
+        }]
+    },
+    devServer: {
+        contentBase: path.join(__dirname, "dist"),
+        compress: true,
+        //open: true,
+        port: 9000
+    }
+}

BIN
assets/meshes/controllers/microsoft/045E-065D/left.glb


BIN
assets/meshes/controllers/microsoft/045E-065D/right.glb


File diff suppressed because it is too large
+ 2048 - 2216
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 48 - 47
dist/preview release/babylon.js


File diff suppressed because it is too large
+ 2201 - 1594
dist/preview release/babylon.max.js


File diff suppressed because it is too large
+ 2048 - 2216
dist/preview release/babylon.module.d.ts


File diff suppressed because it is too large
+ 49 - 48
dist/preview release/babylon.worker.js


File diff suppressed because it is too large
+ 7469 - 7637
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


File diff suppressed because it is too large
+ 50 - 49
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


File diff suppressed because it is too large
+ 2435 - 1783
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


File diff suppressed because it is too large
+ 7469 - 7637
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


+ 1 - 1
dist/preview release/gui/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "3.1.0-alpha3.4",
+    "version": "3.1.0-alpha3.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

File diff suppressed because it is too large
+ 3 - 4
dist/preview release/inspector/babylon.inspector.bundle.js


+ 0 - 3
dist/preview release/inspector/babylon.inspector.d.ts

@@ -139,9 +139,6 @@ declare module INSPECTOR {
             properties: string[];
             format: (tex: BABYLON.Texture) => string;
         };
-        'MapTexture': {
-            type: typeof BABYLON.MapTexture;
-        };
         'RenderTargetTexture': {
             type: typeof BABYLON.RenderTargetTexture;
         };

+ 1 - 10
dist/preview release/inspector/babylon.inspector.js

@@ -406,9 +406,6 @@ var INSPECTOR;
             ],
             format: function (tex) { return tex.name; }
         },
-        'MapTexture': {
-            type: BABYLON.MapTexture
-        },
         'RenderTargetTexture': {
             type: BABYLON.RenderTargetTexture
         },
@@ -3054,13 +3051,7 @@ var INSPECTOR;
             for (var i = 0; i < 5; i++) {
                 imgs.push(INSPECTOR.Helpers.CreateElement('img', 'texture-image', this._imagePanel));
             }
-            if (texture instanceof BABYLON.MapTexture) {
-                // instance of Map texture
-                texture.bindTextureForPosSize(new BABYLON.Vector2(0, 0), new BABYLON.Size(texture.getSize().width, texture.getSize().height), false);
-                BABYLON.Tools.DumpFramebuffer(texture.getSize().width, texture.getSize().height, this._inspector.scene.getEngine(), function (data) { return img.src = data; });
-                texture.unbindTexture();
-            }
-            else if (texture instanceof BABYLON.RenderTargetTexture) {
+            if (texture instanceof BABYLON.RenderTargetTexture) {
                 // RenderTarget textures
                 var scene = this._inspector.scene;
                 var engine_1 = scene.getEngine();

File diff suppressed because it is too large
+ 3 - 4
dist/preview release/inspector/babylon.inspector.min.js


+ 6 - 9
dist/preview release/loaders/babylon.glTF1FileLoader.d.ts

@@ -9,11 +9,11 @@ declare module BABYLON {
         json: Object;
         bin: ArrayBufferView;
     }
-    interface IGLTFLoader {
+    interface IGLTFLoader extends IDisposable {
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
     }
-    class GLTFFileLoader implements ISceneLoaderPluginAsync {
+    class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
         onParsed: (data: IGLTFLoaderData) => void;
@@ -27,19 +27,15 @@ declare module BABYLON {
          */
         onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
         /**
-         * Raised when the visible components (geometry, materials, textures, etc.) are first ready to be rendered.
-         * For assets with LODs, raised when the first LOD is complete.
-         * For assets without LODs, raised when the model is complete just before onComplete.
-         */
-        onReady: () => void;
-        /**
          * Raised when the asset is completely loaded, just before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete just after onReady.
+         * For assets without LODs, raised when the model is complete just after onSuccess.
          */
         onComplete: () => void;
+        private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         canDirectLoad(data: string): boolean;
@@ -447,6 +443,7 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): boolean;
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         private _loadShadersAsync(gltfRuntime, onload);

+ 21 - 12
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -21,6 +21,12 @@ var BABYLON;
                 ".glb": { isBinary: true }
             };
         }
+        GLTFFileLoader.prototype.dispose = function () {
+            if (this._loader) {
+                this._loader.dispose();
+                this._loader = null;
+            }
+        };
         GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
             var loaderData = GLTFFileLoader._parse(data, onError);
             if (!loaderData) {
@@ -29,11 +35,11 @@ var BABYLON;
             if (this.onParsed) {
                 this.onParsed(loaderData);
             }
-            var loader = this._getLoader(loaderData, onError);
-            if (!loader) {
+            this._loader = this._getLoader(loaderData, onError);
+            if (!this._loader) {
                 return;
             }
-            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
             var loaderData = GLTFFileLoader._parse(data, onError);
@@ -43,11 +49,11 @@ var BABYLON;
             if (this.onParsed) {
                 this.onParsed(loaderData);
             }
-            var loader = this._getLoader(loaderData, onError);
-            if (!loader) {
+            this._loader = this._getLoader(loaderData, onError);
+            if (!this._loader) {
                 return;
             }
-            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            return this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
@@ -163,18 +169,18 @@ var BABYLON;
             // Look for BIN chunk
             var bin = null;
             while (binaryReader.getPosition() < binaryReader.getLength()) {
-                chunkLength = binaryReader.readUint32();
-                chunkFormat = binaryReader.readUint32();
-                switch (chunkFormat) {
+                var chunkLength_1 = binaryReader.readUint32();
+                var chunkFormat_1 = binaryReader.readUint32();
+                switch (chunkFormat_1) {
                     case ChunkFormat.JSON:
                         onError("Unexpected JSON chunk");
                         return null;
                     case ChunkFormat.BIN:
-                        bin = binaryReader.readUint8Array(chunkLength);
+                        bin = binaryReader.readUint8Array(chunkLength_1);
                         break;
                     default:
                         // ignore unrecognized chunkFormat
-                        binaryReader.skipBytes(chunkLength);
+                        binaryReader.skipBytes(chunkLength_1);
                         break;
                 }
             }
@@ -207,7 +213,7 @@ var BABYLON;
         GLTFFileLoader._decodeBufferToText = function (buffer) {
             var result = "";
             var length = buffer.byteLength;
-            for (var i = 0; i < length; ++i) {
+            for (var i = 0; i < length; i++) {
                 result += String.fromCharCode(buffer[i]);
             }
             return result;
@@ -1597,6 +1603,9 @@ var BABYLON;
                 }
                 GLTFLoader.Extensions[extension.name] = extension;
             };
+            GLTFLoader.prototype.dispose = function () {
+                // do nothing
+            };
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;

File diff suppressed because it is too large
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 10 - 12
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -9,11 +9,11 @@ declare module BABYLON {
         json: Object;
         bin: ArrayBufferView;
     }
-    interface IGLTFLoader {
+    interface IGLTFLoader extends IDisposable {
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
     }
-    class GLTFFileLoader implements ISceneLoaderPluginAsync {
+    class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
         onParsed: (data: IGLTFLoaderData) => void;
@@ -27,19 +27,15 @@ declare module BABYLON {
          */
         onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
         /**
-         * Raised when the visible components (geometry, materials, textures, etc.) are first ready to be rendered.
-         * For assets with LODs, raised when the first LOD is complete.
-         * For assets without LODs, raised when the model is complete just before onComplete.
-         */
-        onReady: () => void;
-        /**
          * Raised when the asset is completely loaded, just before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete just after onReady.
+         * For assets without LODs, raised when the model is complete just after onSuccess.
          */
         onComplete: () => void;
+        private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         canDirectLoad(data: string): boolean;
@@ -305,9 +301,10 @@ declare module BABYLON.GLTF2 {
 
 
 declare module BABYLON.GLTF2 {
-    class GLTFLoader implements IGLTFLoader, IDisposable {
+    class GLTFLoader implements IGLTFLoader {
         _gltf: IGLTF;
         _babylonScene: Scene;
+        private _disposed;
         private _parent;
         private _rootUrl;
         private _defaultMaterial;
@@ -316,7 +313,7 @@ declare module BABYLON.GLTF2 {
         private _progressCallback;
         private _errorCallback;
         private _renderReady;
-        private _disposed;
+        private _requests;
         private _renderReadyObservable;
         private _renderPendingCount;
         private _loaderPendingCount;
@@ -364,7 +361,7 @@ declare module BABYLON.GLTF2 {
         private _loadBufferViewAsync(context, bufferView, onSuccess);
         private _loadAccessorAsync(context, accessor, onSuccess);
         private _getNumComponentsOfType(type);
-        private _buildArrayBuffer<T>(typedArray, context, data, byteOffset, count, numComponents, byteStride);
+        private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride);
         _addPendingData(data: any): void;
         _removePendingData(data: any): void;
         _addLoaderPendingData(data: any): void;
@@ -378,6 +375,7 @@ declare module BABYLON.GLTF2 {
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
         _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex: number): Texture;
         private _loadImage(context, image, onSuccess);
+        _loadUri(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _tryCatchOnError(handler: () => void): void;
     }
 }

+ 235 - 191
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -21,6 +21,12 @@ var BABYLON;
                 ".glb": { isBinary: true }
             };
         }
+        GLTFFileLoader.prototype.dispose = function () {
+            if (this._loader) {
+                this._loader.dispose();
+                this._loader = null;
+            }
+        };
         GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
             var loaderData = GLTFFileLoader._parse(data, onError);
             if (!loaderData) {
@@ -29,11 +35,11 @@ var BABYLON;
             if (this.onParsed) {
                 this.onParsed(loaderData);
             }
-            var loader = this._getLoader(loaderData, onError);
-            if (!loader) {
+            this._loader = this._getLoader(loaderData, onError);
+            if (!this._loader) {
                 return;
             }
-            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
             var loaderData = GLTFFileLoader._parse(data, onError);
@@ -43,11 +49,11 @@ var BABYLON;
             if (this.onParsed) {
                 this.onParsed(loaderData);
             }
-            var loader = this._getLoader(loaderData, onError);
-            if (!loader) {
+            this._loader = this._getLoader(loaderData, onError);
+            if (!this._loader) {
                 return;
             }
-            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            return this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
@@ -163,18 +169,18 @@ var BABYLON;
             // Look for BIN chunk
             var bin = null;
             while (binaryReader.getPosition() < binaryReader.getLength()) {
-                chunkLength = binaryReader.readUint32();
-                chunkFormat = binaryReader.readUint32();
-                switch (chunkFormat) {
+                var chunkLength_1 = binaryReader.readUint32();
+                var chunkFormat_1 = binaryReader.readUint32();
+                switch (chunkFormat_1) {
                     case ChunkFormat.JSON:
                         onError("Unexpected JSON chunk");
                         return null;
                     case ChunkFormat.BIN:
-                        bin = binaryReader.readUint8Array(chunkLength);
+                        bin = binaryReader.readUint8Array(chunkLength_1);
                         break;
                     default:
                         // ignore unrecognized chunkFormat
-                        binaryReader.skipBytes(chunkLength);
+                        binaryReader.skipBytes(chunkLength_1);
                         break;
                 }
             }
@@ -207,7 +213,7 @@ var BABYLON;
         GLTFFileLoader._decodeBufferToText = function (buffer) {
             var result = "";
             var length = buffer.byteLength;
-            for (var i = 0; i < length; ++i) {
+            for (var i = 0; i < length; i++) {
                 result += String.fromCharCode(buffer[i]);
             }
             return result;
@@ -326,8 +332,9 @@ var BABYLON;
         }());
         var GLTFLoader = /** @class */ (function () {
             function GLTFLoader(parent) {
-                this._renderReady = false;
                 this._disposed = false;
+                this._renderReady = false;
+                this._requests = new Array();
                 this._renderReadyObservable = new BABYLON.Observable();
                 // Count of pending work that needs to complete before the asset is rendered.
                 this._renderPendingCount = 0;
@@ -350,24 +357,37 @@ var BABYLON;
                     return;
                 }
                 this._disposed = true;
+                // Abort requests that are not complete
+                for (var _i = 0, _a = this._requests; _i < _a.length; _i++) {
+                    var request = _a[_i];
+                    if (request.readyState !== (XMLHttpRequest.DONE || 4)) {
+                        request.abort();
+                    }
+                }
                 // Revoke object urls created during load
                 if (this._gltf.textures) {
-                    this._gltf.textures.forEach(function (texture) {
+                    for (var _b = 0, _c = this._gltf.textures; _b < _c.length; _b++) {
+                        var texture = _c[_b];
                         if (texture.url) {
                             URL.revokeObjectURL(texture.url);
                         }
-                    });
+                    }
                 }
                 this._gltf = undefined;
                 this._babylonScene = undefined;
+                this._parent = undefined;
                 this._rootUrl = undefined;
                 this._defaultMaterial = undefined;
+                this._rootNode = undefined;
                 this._successCallback = undefined;
+                this._progressCallback = undefined;
                 this._errorCallback = undefined;
                 this._renderReady = false;
-                this._renderReadyObservable.clear();
+                this._requests = undefined;
+                this._renderReadyObservable = undefined;
                 this._renderPendingCount = 0;
                 this._loaderPendingCount = 0;
+                this._loaderTrackers = undefined;
             };
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
@@ -435,9 +455,6 @@ var BABYLON;
                 this._startAnimations();
                 this._successCallback();
                 this._renderReadyObservable.notifyObservers(this);
-                if (this._parent.onReady) {
-                    this._parent.onReady();
-                }
             };
             GLTFLoader.prototype._onComplete = function () {
                 if (this._parent.onComplete) {
@@ -465,11 +482,12 @@ var BABYLON;
                 var meshes = [this._rootNode.babylonMesh];
                 var nodes = this._gltf.nodes;
                 if (nodes) {
-                    nodes.forEach(function (node) {
+                    for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
+                        var node = nodes_1[_i];
                         if (node.babylonMesh) {
                             meshes.push(node.babylonMesh);
                         }
-                    });
+                    }
                 }
                 return meshes;
             };
@@ -477,11 +495,12 @@ var BABYLON;
                 var skeletons = new Array();
                 var skins = this._gltf.skins;
                 if (skins) {
-                    skins.forEach(function (skin) {
+                    for (var _i = 0, skins_1 = skins; _i < skins_1.length; _i++) {
+                        var skin = skins_1[_i];
                         if (skin.babylonSkeleton instanceof BABYLON.Skeleton) {
                             skeletons.push(skin.babylonSkeleton);
                         }
-                    });
+                    }
                 }
                 return skeletons;
             };
@@ -489,15 +508,18 @@ var BABYLON;
                 var targets = new Array();
                 var animations = this._gltf.animations;
                 if (animations) {
-                    animations.forEach(function (animation) {
+                    for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
+                        var animation = animations_1[_i];
                         targets.push.apply(targets, animation.targets);
-                    });
+                    }
                 }
                 return targets;
             };
             GLTFLoader.prototype._startAnimations = function () {
-                var _this = this;
-                this._getAnimationTargets().forEach(function (target) { return _this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true); });
+                for (var _i = 0, _a = this._getAnimationTargets(); _i < _a.length; _i++) {
+                    var target = _a[_i];
+                    this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                }
             };
             GLTFLoader.prototype._loadDefaultScene = function (nodeNames) {
                 var scene = GLTF2.GLTFUtils.GetArrayItem(this._gltf.scenes, this._gltf.scene || 0);
@@ -534,22 +556,23 @@ var BABYLON;
                     if (!(nodeNames instanceof Array)) {
                         nodeNames = [nodeNames];
                     }
-                    var filteredNodeIndices = new Array();
+                    var filteredNodeIndices_1 = new Array();
                     this._traverseNodes(context, nodeIndices, function (node) {
                         if (nodeNames.indexOf(node.name) !== -1) {
-                            filteredNodeIndices.push(node.index);
+                            filteredNodeIndices_1.push(node.index);
                             return false;
                         }
                         return true;
                     }, this._rootNode);
-                    nodeIndices = filteredNodeIndices;
+                    nodeIndices = filteredNodeIndices_1;
                 }
-                for (var i = 0; i < nodeIndices.length; i++) {
-                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, nodeIndices[i]);
+                for (var _i = 0, nodeIndices_1 = nodeIndices; _i < nodeIndices_1.length; _i++) {
+                    var index = nodeIndices_1[_i];
+                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, index);
                     if (!node) {
-                        throw new Error(context + ": Failed to find node " + nodeIndices[i]);
+                        throw new Error(context + ": Failed to find node " + index);
                     }
-                    this._loadNode("#/nodes/" + nodeIndices[i], node);
+                    this._loadNode("#/nodes/" + index, node);
                 }
                 // Disable the root mesh until the asset is ready to render.
                 this._rootNode.babylonMesh.setEnabled(false);
@@ -581,25 +604,26 @@ var BABYLON;
                     // TODO: handle cameras
                 }
                 if (node.children) {
-                    for (var i = 0; i < node.children.length; i++) {
-                        var childNode = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, node.children[i]);
+                    for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
+                        var index = _a[_i];
+                        var childNode = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, index);
                         if (!childNode) {
-                            throw new Error(context + ": Failed to find child node " + node.children[i]);
+                            throw new Error(context + ": Failed to find child node " + index);
                         }
-                        this._loadNode("#/nodes/" + node.children[i], childNode);
+                        this._loadNode("#/nodes/" + index, childNode);
                     }
                 }
             };
             GLTFLoader.prototype._loadMesh = function (context, node, mesh) {
                 var _this = this;
                 node.babylonMesh.name = node.babylonMesh.name || mesh.name;
-                if (!mesh.primitives || mesh.primitives.length === 0) {
+                var primitives = mesh.primitives;
+                if (!primitives || primitives.length === 0) {
                     throw new Error(context + ": Primitives are missing");
                 }
                 this._createMorphTargets(context, node, mesh);
                 this._loadAllVertexDataAsync(context, mesh, function () {
                     _this._loadMorphTargets(context, node, mesh);
-                    var primitives = mesh.primitives;
                     var vertexData = new BABYLON.VertexData();
                     for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
                         var primitive = primitives_1[_i];
@@ -612,62 +636,68 @@ var BABYLON;
                     var verticesStart = 0;
                     var indicesStart = 0;
                     for (var index = 0; index < primitives.length; index++) {
-                        var vertexData = primitives[index].vertexData;
-                        var verticesCount = vertexData.positions.length;
-                        var indicesCount = vertexData.indices.length;
+                        var vertexData_1 = primitives[index].vertexData;
+                        var verticesCount = vertexData_1.positions.length;
+                        var indicesCount = vertexData_1.indices.length;
                         BABYLON.SubMesh.AddToMesh(index, verticesStart, verticesCount, indicesStart, indicesCount, node.babylonMesh);
                         verticesStart += verticesCount;
                         indicesStart += indicesCount;
                     }
                     ;
-                    var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, _this._babylonScene);
-                    node.babylonMesh.material = multiMaterial;
-                    var subMaterials = multiMaterial.subMaterials;
-                    for (var index = 0; index < primitives.length; index++) {
-                        var primitive = primitives[index];
-                        if (primitive.material == null) {
-                            subMaterials[index] = _this._getDefaultMaterial();
+                });
+                var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, this._babylonScene);
+                node.babylonMesh.material = multiMaterial;
+                var subMaterials = multiMaterial.subMaterials;
+                var _loop_1 = function (index) {
+                    var primitive = primitives[index];
+                    if (primitive.material == null) {
+                        subMaterials[index] = this_1._getDefaultMaterial();
+                    }
+                    else {
+                        var material_1 = GLTF2.GLTFUtils.GetArrayItem(this_1._gltf.materials, primitive.material);
+                        if (!material_1) {
+                            throw new Error(context + ": Failed to find material " + primitive.material);
                         }
-                        else {
-                            var material = GLTF2.GLTFUtils.GetArrayItem(_this._gltf.materials, primitive.material);
-                            if (!material) {
-                                throw new Error(context + ": Failed to find material " + primitive.material);
+                        this_1._loadMaterial("#/materials/" + material_1.index, material_1, function (babylonMaterial, isNew) {
+                            if (isNew && _this._parent.onMaterialLoaded) {
+                                _this._parent.onMaterialLoaded(babylonMaterial);
                             }
-                            _this._loadMaterial("#/materials/" + material.index, material, function (babylonMaterial, isNew) {
-                                if (isNew && _this._parent.onMaterialLoaded) {
-                                    _this._parent.onMaterialLoaded(babylonMaterial);
-                                }
-                                if (_this._parent.onBeforeMaterialReadyAsync) {
-                                    _this._addLoaderPendingData(material);
-                                    _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, subMaterials[index] != null, function () {
+                            if (_this._parent.onBeforeMaterialReadyAsync) {
+                                _this._addLoaderPendingData(material_1);
+                                _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, subMaterials[index] != null, function () {
+                                    _this._tryCatchOnError(function () {
                                         subMaterials[index] = babylonMaterial;
-                                        _this._removeLoaderPendingData(material);
+                                        _this._removeLoaderPendingData(material_1);
                                     });
-                                }
-                                else {
-                                    subMaterials[index] = babylonMaterial;
-                                }
-                            });
-                        }
+                                });
+                            }
+                            else {
+                                subMaterials[index] = babylonMaterial;
+                            }
+                        });
                     }
-                    ;
-                });
+                };
+                var this_1 = this;
+                for (var index = 0; index < primitives.length; index++) {
+                    _loop_1(index);
+                }
+                ;
             };
             GLTFLoader.prototype._loadAllVertexDataAsync = function (context, mesh, onSuccess) {
                 var primitives = mesh.primitives;
                 var numRemainingPrimitives = primitives.length;
-                var _loop_1 = function () {
+                var _loop_2 = function (index) {
                     var primitive = primitives[index];
-                    this_1._loadVertexDataAsync(context + "/primitive/" + index, mesh, primitive, function (vertexData) {
+                    this_2._loadVertexDataAsync(context + "/primitive/" + index, mesh, primitive, function (vertexData) {
                         primitive.vertexData = vertexData;
                         if (--numRemainingPrimitives === 0) {
                             onSuccess();
                         }
                     });
                 };
-                var this_1 = this;
+                var this_2 = this;
                 for (var index = 0; index < primitives.length; index++) {
-                    _loop_1();
+                    _loop_2(index);
                 }
             };
             GLTFLoader.prototype._loadVertexDataAsync = function (context, mesh, primitive, onSuccess) {
@@ -682,12 +712,12 @@ var BABYLON;
                 }
                 var vertexData = new BABYLON.VertexData();
                 var numRemainingAttributes = Object.keys(attributes).length;
-                var _loop_2 = function (attribute) {
-                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_2._gltf.accessors, attributes[attribute]);
+                var _loop_3 = function (attribute) {
+                    var accessor = GLTF2.GLTFUtils.GetArrayItem(this_3._gltf.accessors, attributes[attribute]);
                     if (!accessor) {
                         throw new Error(context + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
                     }
-                    this_2._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
+                    this_3._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
                         switch (attribute) {
                             case "NORMAL":
                                 vertexData.normals = data;
@@ -720,7 +750,9 @@ var BABYLON;
                         if (--numRemainingAttributes === 0) {
                             if (primitive.indices == null) {
                                 vertexData.indices = new Uint32Array(vertexData.positions.length / 3);
-                                vertexData.indices.forEach(function (v, i) { return vertexData.indices[i] = i; });
+                                for (var i = 0; i < vertexData.indices.length; i++) {
+                                    vertexData.indices[i] = i;
+                                }
                                 onSuccess(vertexData);
                             }
                             else {
@@ -736,9 +768,9 @@ var BABYLON;
                         }
                     });
                 };
-                var this_2 = this, accessor;
+                var this_3 = this;
                 for (var attribute in attributes) {
-                    _loop_2(attribute);
+                    _loop_3(attribute);
                 }
             };
             GLTFLoader.prototype._createMorphTargets = function (context, node, mesh) {
@@ -771,7 +803,7 @@ var BABYLON;
                         var vertexData = new BABYLON.VertexData();
                         for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
                             var primitive = _a[_i];
-                            vertexData.merge(primitive.targetsVertexData[index]);
+                            vertexData.merge(primitive.targetsVertexData[index], { tangentLength: 3 });
                         }
                         var target = morphTargetManager.getTarget(index);
                         target.setNormals(vertexData.normals);
@@ -782,33 +814,36 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadAllMorphTargetVertexDataAsync = function (context, node, mesh, onSuccess) {
                 var numRemainingTargets = mesh.primitives.length * node.babylonMesh.morphTargetManager.numTargets;
-                for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
-                    var primitive = _a[_i];
+                var _loop_4 = function (primitive) {
                     var targets = primitive.targets;
                     primitive.targetsVertexData = new Array(targets.length);
-                    var _loop_3 = function (index) {
-                        this_3._loadMorphTargetVertexDataAsync(context + "/targets/" + index, primitive.vertexData, targets[index], function (vertexData) {
+                    var _loop_5 = function (index) {
+                        this_4._loadMorphTargetVertexDataAsync(context + "/targets/" + index, primitive.vertexData, targets[index], function (vertexData) {
                             primitive.targetsVertexData[index] = vertexData;
                             if (--numRemainingTargets === 0) {
                                 onSuccess();
                             }
                         });
                     };
-                    var this_3 = this;
                     for (var index = 0; index < targets.length; index++) {
-                        _loop_3(index);
+                        _loop_5(index);
                     }
+                };
+                var this_4 = this;
+                for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
+                    var primitive = _a[_i];
+                    _loop_4(primitive);
                 }
             };
             GLTFLoader.prototype._loadMorphTargetVertexDataAsync = function (context, vertexData, attributes, onSuccess) {
                 var targetVertexData = new BABYLON.VertexData();
                 var numRemainingAttributes = Object.keys(attributes).length;
-                var _loop_4 = function (attribute) {
-                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_4._gltf.accessors, attributes[attribute]);
+                var _loop_6 = function (attribute) {
+                    var accessor = GLTF2.GLTFUtils.GetArrayItem(this_5._gltf.accessors, attributes[attribute]);
                     if (!accessor) {
                         throw new Error(context + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
                     }
-                    this_4._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
+                    this_5._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
                         // glTF stores morph target information as deltas while babylon.js expects the final data.
                         // As a result we have to add the original data to the delta to calculate the final data.
                         var values = data;
@@ -846,9 +881,9 @@ var BABYLON;
                         }
                     });
                 };
-                var this_4 = this, accessor;
+                var this_5 = this;
                 for (var attribute in attributes) {
-                    _loop_4(attribute);
+                    _loop_6(attribute);
                 }
             };
             GLTFLoader.prototype._loadTransform = function (node) {
@@ -856,8 +891,8 @@ var BABYLON;
                 var rotation = BABYLON.Quaternion.Identity();
                 var scaling = BABYLON.Vector3.One();
                 if (node.matrix) {
-                    var mat = BABYLON.Matrix.FromArray(node.matrix);
-                    mat.decompose(scaling, rotation, position);
+                    var matrix = BABYLON.Matrix.FromArray(node.matrix);
+                    matrix.decompose(scaling, rotation, position);
                 }
                 else {
                     if (node.translation)
@@ -899,10 +934,11 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadBones = function (context, skin, inverseBindMatrixData) {
                 var babylonBones = {};
-                for (var i = 0; i < skin.joints.length; i++) {
-                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, skin.joints[i]);
+                for (var _i = 0, _a = skin.joints; _i < _a.length; _i++) {
+                    var index = _a[_i];
+                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, index);
                     if (!node) {
-                        throw new Error(context + ": Failed to find joint " + skin.joints[i]);
+                        throw new Error(context + ": Failed to find joint " + index);
                     }
                     this._loadBone(node, skin, inverseBindMatrixData, babylonBones);
                 }
@@ -934,10 +970,11 @@ var BABYLON;
             };
             GLTFLoader.prototype._traverseNodes = function (context, indices, action, parentNode) {
                 if (parentNode === void 0) { parentNode = null; }
-                for (var i = 0; i < indices.length; i++) {
-                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, indices[i]);
+                for (var _i = 0, indices_1 = indices; _i < indices_1.length; _i++) {
+                    var index = indices_1[_i];
+                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, index);
                     if (!node) {
-                        throw new Error(context + ": Failed to find node " + indices[i]);
+                        throw new Error(context + ": Failed to find node " + index);
                     }
                     this._traverseNode(context, node, action, parentNode);
                 }
@@ -1070,7 +1107,7 @@ var BABYLON;
                     animation.targets = animation.targets || [];
                     if (targetPath === "influence") {
                         var morphTargetManager = targetNode.babylonMesh.morphTargetManager;
-                        for (var targetIndex = 0; targetIndex < morphTargetManager.numTargets; targetIndex++) {
+                        var _loop_7 = function (targetIndex) {
                             var morphTarget = morphTargetManager.getTarget(targetIndex);
                             var animationName = (animation.name || "anim" + animation.index) + "_" + targetIndex;
                             var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
@@ -1082,14 +1119,17 @@ var BABYLON;
                             }); }));
                             morphTarget.animations.push(babylonAnimation);
                             animation.targets.push(morphTarget);
+                        };
+                        for (var targetIndex = 0; targetIndex < morphTargetManager.numTargets; targetIndex++) {
+                            _loop_7(targetIndex);
                         }
                     }
                     else {
                         var animationName = animation.name || "anim" + animation.index;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
-                        for (var i = 0; i < targetNode.babylonAnimationTargets.length; i++) {
-                            var target = targetNode.babylonAnimationTargets[i];
+                        for (var _i = 0, _a = targetNode.babylonAnimationTargets; _i < _a.length; _i++) {
+                            var target = _a[_i];
                             target.animations.push(babylonAnimation.clone());
                             animation.targets.push(target);
                         }
@@ -1136,28 +1176,15 @@ var BABYLON;
                         this._removePendingData(buffer);
                     }
                     else {
-                        if (!GLTF2.GLTFUtils.ValidateUri(buffer.uri)) {
-                            throw new Error(context + ": Uri '" + buffer.uri + "' is invalid");
-                        }
                         buffer.loadedObservable = new BABYLON.Observable();
                         buffer.loadedObservable.add(function (buffer) {
                             onSuccess(buffer.loadedData);
                             _this._removePendingData(buffer);
                         });
-                        BABYLON.Tools.LoadFile(this._rootUrl + buffer.uri, function (data) {
-                            _this._tryCatchOnError(function () {
-                                buffer.loadedData = new Uint8Array(data);
-                                buffer.loadedObservable.notifyObservers(buffer);
-                                buffer.loadedObservable = null;
-                            });
-                        }, function (event) {
-                            _this._tryCatchOnError(function () {
-                                _this._onProgress(event);
-                            });
-                        }, this._babylonScene.database, true, function (request) {
-                            _this._tryCatchOnError(function () {
-                                throw new Error(context + ": Failed to load '" + buffer.uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""));
-                            });
+                        this._loadUri(context, buffer.uri, function (data) {
+                            buffer.loadedData = data;
+                            buffer.loadedObservable.notifyObservers(buffer);
+                            buffer.loadedObservable = null;
                         });
                     }
                 }
@@ -1172,8 +1199,9 @@ var BABYLON;
                     if (_this._disposed) {
                         return;
                     }
+                    var data;
                     try {
-                        var data = new Uint8Array(bufferData.buffer, bufferData.byteOffset + (bufferView.byteOffset || 0), bufferView.byteLength);
+                        data = new Uint8Array(bufferData.buffer, bufferData.byteOffset + (bufferView.byteOffset || 0), bufferView.byteLength);
                     }
                     catch (e) {
                         throw new Error(context + ": " + e.message);
@@ -1199,27 +1227,32 @@ var BABYLON;
                         throw new Error(context + ": Invalid type (" + accessor.type + ")");
                     }
                     var data;
-                    switch (accessor.componentType) {
-                        case GLTF2.EComponentType.BYTE:
-                            data = _this._buildArrayBuffer(Float32Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.UNSIGNED_BYTE:
-                            data = _this._buildArrayBuffer(Uint8Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.SHORT:
-                            data = _this._buildArrayBuffer(Int16Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.UNSIGNED_SHORT:
-                            data = _this._buildArrayBuffer(Uint16Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.UNSIGNED_INT:
-                            data = _this._buildArrayBuffer(Uint32Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.FLOAT:
-                            data = _this._buildArrayBuffer(Float32Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        default:
-                            throw new Error(context + ": Invalid component type (" + accessor.componentType + ")");
+                    try {
+                        switch (accessor.componentType) {
+                            case GLTF2.EComponentType.BYTE:
+                                data = _this._buildArrayBuffer(Float32Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.UNSIGNED_BYTE:
+                                data = _this._buildArrayBuffer(Uint8Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.SHORT:
+                                data = _this._buildArrayBuffer(Int16Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.UNSIGNED_SHORT:
+                                data = _this._buildArrayBuffer(Uint16Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.UNSIGNED_INT:
+                                data = _this._buildArrayBuffer(Uint32Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.FLOAT:
+                                data = _this._buildArrayBuffer(Float32Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            default:
+                                throw new Error(context + ": Invalid component type (" + accessor.componentType + ")");
+                        }
+                    }
+                    catch (e) {
+                        throw new Error(context + ": " + e);
                     }
                     onSuccess(data);
                 });
@@ -1236,30 +1269,25 @@ var BABYLON;
                 }
                 return 0;
             };
-            GLTFLoader.prototype._buildArrayBuffer = function (typedArray, context, data, byteOffset, count, numComponents, byteStride) {
-                try {
-                    var byteOffset = data.byteOffset + (byteOffset || 0);
-                    var targetLength = count * numComponents;
-                    if (byteStride == null || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
-                        return new typedArray(data.buffer, byteOffset, targetLength);
-                    }
-                    var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
-                    var sourceBuffer = new typedArray(data.buffer, byteOffset, elementStride * count);
-                    var targetBuffer = new typedArray(targetLength);
-                    var sourceIndex = 0;
-                    var targetIndex = 0;
-                    while (targetIndex < targetLength) {
-                        for (var componentIndex = 0; componentIndex < numComponents; componentIndex++) {
-                            targetBuffer[targetIndex] = sourceBuffer[sourceIndex + componentIndex];
-                            targetIndex++;
-                        }
-                        sourceIndex += elementStride;
+            GLTFLoader.prototype._buildArrayBuffer = function (typedArray, data, byteOffset, count, numComponents, byteStride) {
+                byteOffset = data.byteOffset + (byteOffset || 0);
+                var targetLength = count * numComponents;
+                if (byteStride == null || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
+                    return new typedArray(data.buffer, byteOffset, targetLength);
+                }
+                var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
+                var sourceBuffer = new typedArray(data.buffer, byteOffset, elementStride * count);
+                var targetBuffer = new typedArray(targetLength);
+                var sourceIndex = 0;
+                var targetIndex = 0;
+                while (targetIndex < targetLength) {
+                    for (var componentIndex = 0; componentIndex < numComponents; componentIndex++) {
+                        targetBuffer[targetIndex] = sourceBuffer[sourceIndex + componentIndex];
+                        targetIndex++;
                     }
-                    return targetBuffer;
-                }
-                catch (e) {
-                    throw new Error(context + ": " + e);
+                    sourceIndex += elementStride;
                 }
+                return targetBuffer;
             };
             GLTFLoader.prototype._addPendingData = function (data) {
                 if (!this._renderReady) {
@@ -1278,10 +1306,16 @@ var BABYLON;
             };
             GLTFLoader.prototype._addLoaderPendingData = function (data) {
                 this._loaderPendingCount++;
-                this._loaderTrackers.forEach(function (tracker) { return tracker._addPendingData(data); });
+                for (var _i = 0, _a = this._loaderTrackers; _i < _a.length; _i++) {
+                    var tracker = _a[_i];
+                    tracker._addPendingData(data);
+                }
             };
             GLTFLoader.prototype._removeLoaderPendingData = function (data) {
-                this._loaderTrackers.forEach(function (tracker) { return tracker._removePendingData(data); });
+                for (var _i = 0, _a = this._loaderTrackers; _i < _a.length; _i++) {
+                    var tracker = _a[_i];
+                    tracker._removePendingData(data);
+                }
                 if (--this._loaderPendingCount === 0) {
                     this._onComplete();
                 }
@@ -1463,12 +1497,12 @@ var BABYLON;
                     texture.dataReadyObservable.add(function (texture) {
                         babylonTexture.updateURL(texture.url);
                     });
-                    var image = GLTF2.GLTFUtils.GetArrayItem(this._gltf.images, texture.source);
-                    if (!image) {
+                    var image_1 = GLTF2.GLTFUtils.GetArrayItem(this._gltf.images, texture.source);
+                    if (!image_1) {
                         throw new Error(context + ": Failed to find source " + texture.source);
                     }
-                    this._loadImage("#/images/" + image.index, image, function (data) {
-                        texture.url = URL.createObjectURL(new Blob([data], { type: image.mimeType }));
+                    this._loadImage("#/images/" + image_1.index, image_1, function (data) {
+                        texture.url = URL.createObjectURL(new Blob([data], { type: image_1.mimeType }));
                         texture.dataReadyObservable.notifyObservers(texture);
                     });
                 }
@@ -1482,28 +1516,12 @@ var BABYLON;
                 return babylonTexture;
             };
             GLTFLoader.prototype._loadImage = function (context, image, onSuccess) {
-                var _this = this;
                 if (image.uri) {
-                    if (!GLTF2.GLTFUtils.ValidateUri(image.uri)) {
-                        throw new Error(context + ": Uri '" + image.uri + "' is invalid");
-                    }
                     if (GLTF2.GLTFUtils.IsBase64(image.uri)) {
                         onSuccess(new Uint8Array(GLTF2.GLTFUtils.DecodeBase64(image.uri)));
                     }
                     else {
-                        BABYLON.Tools.LoadFile(this._rootUrl + image.uri, function (data) {
-                            _this._tryCatchOnError(function () {
-                                onSuccess(data);
-                            });
-                        }, function (event) {
-                            _this._tryCatchOnError(function () {
-                                _this._onProgress(event);
-                            });
-                        }, this._babylonScene.database, true, function (request) {
-                            _this._tryCatchOnError(function () {
-                                throw new Error(context + ": Failed to load '" + image.uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""));
-                            });
-                        });
+                        this._loadUri(context, image.uri, onSuccess);
                     }
                 }
                 else {
@@ -1514,6 +1532,28 @@ var BABYLON;
                     this._loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView, onSuccess);
                 }
             };
+            GLTFLoader.prototype._loadUri = function (context, uri, onSuccess) {
+                var _this = this;
+                if (!GLTF2.GLTFUtils.ValidateUri(uri)) {
+                    throw new Error(context + ": Uri '" + uri + "' is invalid");
+                }
+                var request = BABYLON.Tools.LoadFile(this._rootUrl + uri, function (data) {
+                    _this._tryCatchOnError(function () {
+                        onSuccess(new Uint8Array(data));
+                    });
+                }, function (event) {
+                    _this._tryCatchOnError(function () {
+                        _this._onProgress(event);
+                    });
+                }, this._babylonScene.database, true, function (request) {
+                    _this._tryCatchOnError(function () {
+                        throw new Error(context + ": Failed to load '" + uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""));
+                    });
+                });
+                if (request) {
+                    this._requests.push(request);
+                }
+            };
             GLTFLoader.prototype._tryCatchOnError = function (handler) {
                 try {
                     handler();
@@ -1676,8 +1716,8 @@ var BABYLON;
                 if (!extensions) {
                     return false;
                 }
-                for (var i = 0; i < extensions.length; i++) {
-                    var extension = extensions[i];
+                for (var _i = 0, extensions_1 = extensions; _i < extensions_1.length; _i++) {
+                    var extension = extensions_1[_i];
                     if (extension.enabled && action(extension)) {
                         return true;
                     }
@@ -1764,7 +1804,9 @@ var BABYLON;
                             return;
                         }
                         setTimeout(function () {
-                            _this._loadNodeLOD(loader, context, nodes, index - 1, onComplete);
+                            loader._tryCatchOnError(function () {
+                                _this._loadNodeLOD(loader, context, nodes, index - 1, onComplete);
+                            });
                         }, MSFTLOD.MinimalLODDelay);
                     });
                 };
@@ -1793,7 +1835,9 @@ var BABYLON;
                         loader._executeWhenRenderReady(function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
                                 setTimeout(function () {
-                                    _this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
+                                    loader._tryCatchOnError(function () {
+                                        _this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
+                                    });
                                 }, MSFTLOD.MinimalLODDelay);
                             });
                         });

File diff suppressed because it is too large
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 11 - 12
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -9,11 +9,11 @@ declare module BABYLON {
         json: Object;
         bin: ArrayBufferView;
     }
-    interface IGLTFLoader {
+    interface IGLTFLoader extends IDisposable {
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
     }
-    class GLTFFileLoader implements ISceneLoaderPluginAsync {
+    class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
         onParsed: (data: IGLTFLoaderData) => void;
@@ -27,19 +27,15 @@ declare module BABYLON {
          */
         onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
         /**
-         * Raised when the visible components (geometry, materials, textures, etc.) are first ready to be rendered.
-         * For assets with LODs, raised when the first LOD is complete.
-         * For assets without LODs, raised when the model is complete just before onComplete.
-         */
-        onReady: () => void;
-        /**
          * Raised when the asset is completely loaded, just before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete just after onReady.
+         * For assets without LODs, raised when the model is complete just after onSuccess.
          */
         onComplete: () => void;
+        private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         canDirectLoad(data: string): boolean;
@@ -447,6 +443,7 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): boolean;
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         private _loadShadersAsync(gltfRuntime, onload);
@@ -851,9 +848,10 @@ declare module BABYLON.GLTF2 {
 
 
 declare module BABYLON.GLTF2 {
-    class GLTFLoader implements IGLTFLoader, IDisposable {
+    class GLTFLoader implements IGLTFLoader {
         _gltf: IGLTF;
         _babylonScene: Scene;
+        private _disposed;
         private _parent;
         private _rootUrl;
         private _defaultMaterial;
@@ -862,7 +860,7 @@ declare module BABYLON.GLTF2 {
         private _progressCallback;
         private _errorCallback;
         private _renderReady;
-        private _disposed;
+        private _requests;
         private _renderReadyObservable;
         private _renderPendingCount;
         private _loaderPendingCount;
@@ -910,7 +908,7 @@ declare module BABYLON.GLTF2 {
         private _loadBufferViewAsync(context, bufferView, onSuccess);
         private _loadAccessorAsync(context, accessor, onSuccess);
         private _getNumComponentsOfType(type);
-        private _buildArrayBuffer<T>(typedArray, context, data, byteOffset, count, numComponents, byteStride);
+        private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride);
         _addPendingData(data: any): void;
         _removePendingData(data: any): void;
         _addLoaderPendingData(data: any): void;
@@ -924,6 +922,7 @@ declare module BABYLON.GLTF2 {
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
         _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex: number): Texture;
         private _loadImage(context, image, onSuccess);
+        _loadUri(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _tryCatchOnError(handler: () => void): void;
     }
 }

+ 238 - 191
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -21,6 +21,12 @@ var BABYLON;
                 ".glb": { isBinary: true }
             };
         }
+        GLTFFileLoader.prototype.dispose = function () {
+            if (this._loader) {
+                this._loader.dispose();
+                this._loader = null;
+            }
+        };
         GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
             var loaderData = GLTFFileLoader._parse(data, onError);
             if (!loaderData) {
@@ -29,11 +35,11 @@ var BABYLON;
             if (this.onParsed) {
                 this.onParsed(loaderData);
             }
-            var loader = this._getLoader(loaderData, onError);
-            if (!loader) {
+            this._loader = this._getLoader(loaderData, onError);
+            if (!this._loader) {
                 return;
             }
-            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
             var loaderData = GLTFFileLoader._parse(data, onError);
@@ -43,11 +49,11 @@ var BABYLON;
             if (this.onParsed) {
                 this.onParsed(loaderData);
             }
-            var loader = this._getLoader(loaderData, onError);
-            if (!loader) {
+            this._loader = this._getLoader(loaderData, onError);
+            if (!this._loader) {
                 return;
             }
-            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            return this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
@@ -163,18 +169,18 @@ var BABYLON;
             // Look for BIN chunk
             var bin = null;
             while (binaryReader.getPosition() < binaryReader.getLength()) {
-                chunkLength = binaryReader.readUint32();
-                chunkFormat = binaryReader.readUint32();
-                switch (chunkFormat) {
+                var chunkLength_1 = binaryReader.readUint32();
+                var chunkFormat_1 = binaryReader.readUint32();
+                switch (chunkFormat_1) {
                     case ChunkFormat.JSON:
                         onError("Unexpected JSON chunk");
                         return null;
                     case ChunkFormat.BIN:
-                        bin = binaryReader.readUint8Array(chunkLength);
+                        bin = binaryReader.readUint8Array(chunkLength_1);
                         break;
                     default:
                         // ignore unrecognized chunkFormat
-                        binaryReader.skipBytes(chunkLength);
+                        binaryReader.skipBytes(chunkLength_1);
                         break;
                 }
             }
@@ -207,7 +213,7 @@ var BABYLON;
         GLTFFileLoader._decodeBufferToText = function (buffer) {
             var result = "";
             var length = buffer.byteLength;
-            for (var i = 0; i < length; ++i) {
+            for (var i = 0; i < length; i++) {
                 result += String.fromCharCode(buffer[i]);
             }
             return result;
@@ -1597,6 +1603,9 @@ var BABYLON;
                 }
                 GLTFLoader.Extensions[extension.name] = extension;
             };
+            GLTFLoader.prototype.dispose = function () {
+                // do nothing
+            };
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
@@ -2432,8 +2441,9 @@ var BABYLON;
         }());
         var GLTFLoader = /** @class */ (function () {
             function GLTFLoader(parent) {
-                this._renderReady = false;
                 this._disposed = false;
+                this._renderReady = false;
+                this._requests = new Array();
                 this._renderReadyObservable = new BABYLON.Observable();
                 // Count of pending work that needs to complete before the asset is rendered.
                 this._renderPendingCount = 0;
@@ -2456,24 +2466,37 @@ var BABYLON;
                     return;
                 }
                 this._disposed = true;
+                // Abort requests that are not complete
+                for (var _i = 0, _a = this._requests; _i < _a.length; _i++) {
+                    var request = _a[_i];
+                    if (request.readyState !== (XMLHttpRequest.DONE || 4)) {
+                        request.abort();
+                    }
+                }
                 // Revoke object urls created during load
                 if (this._gltf.textures) {
-                    this._gltf.textures.forEach(function (texture) {
+                    for (var _b = 0, _c = this._gltf.textures; _b < _c.length; _b++) {
+                        var texture = _c[_b];
                         if (texture.url) {
                             URL.revokeObjectURL(texture.url);
                         }
-                    });
+                    }
                 }
                 this._gltf = undefined;
                 this._babylonScene = undefined;
+                this._parent = undefined;
                 this._rootUrl = undefined;
                 this._defaultMaterial = undefined;
+                this._rootNode = undefined;
                 this._successCallback = undefined;
+                this._progressCallback = undefined;
                 this._errorCallback = undefined;
                 this._renderReady = false;
-                this._renderReadyObservable.clear();
+                this._requests = undefined;
+                this._renderReadyObservable = undefined;
                 this._renderPendingCount = 0;
                 this._loaderPendingCount = 0;
+                this._loaderTrackers = undefined;
             };
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
@@ -2541,9 +2564,6 @@ var BABYLON;
                 this._startAnimations();
                 this._successCallback();
                 this._renderReadyObservable.notifyObservers(this);
-                if (this._parent.onReady) {
-                    this._parent.onReady();
-                }
             };
             GLTFLoader.prototype._onComplete = function () {
                 if (this._parent.onComplete) {
@@ -2571,11 +2591,12 @@ var BABYLON;
                 var meshes = [this._rootNode.babylonMesh];
                 var nodes = this._gltf.nodes;
                 if (nodes) {
-                    nodes.forEach(function (node) {
+                    for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
+                        var node = nodes_1[_i];
                         if (node.babylonMesh) {
                             meshes.push(node.babylonMesh);
                         }
-                    });
+                    }
                 }
                 return meshes;
             };
@@ -2583,11 +2604,12 @@ var BABYLON;
                 var skeletons = new Array();
                 var skins = this._gltf.skins;
                 if (skins) {
-                    skins.forEach(function (skin) {
+                    for (var _i = 0, skins_1 = skins; _i < skins_1.length; _i++) {
+                        var skin = skins_1[_i];
                         if (skin.babylonSkeleton instanceof BABYLON.Skeleton) {
                             skeletons.push(skin.babylonSkeleton);
                         }
-                    });
+                    }
                 }
                 return skeletons;
             };
@@ -2595,15 +2617,18 @@ var BABYLON;
                 var targets = new Array();
                 var animations = this._gltf.animations;
                 if (animations) {
-                    animations.forEach(function (animation) {
+                    for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
+                        var animation = animations_1[_i];
                         targets.push.apply(targets, animation.targets);
-                    });
+                    }
                 }
                 return targets;
             };
             GLTFLoader.prototype._startAnimations = function () {
-                var _this = this;
-                this._getAnimationTargets().forEach(function (target) { return _this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true); });
+                for (var _i = 0, _a = this._getAnimationTargets(); _i < _a.length; _i++) {
+                    var target = _a[_i];
+                    this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                }
             };
             GLTFLoader.prototype._loadDefaultScene = function (nodeNames) {
                 var scene = GLTF2.GLTFUtils.GetArrayItem(this._gltf.scenes, this._gltf.scene || 0);
@@ -2640,22 +2665,23 @@ var BABYLON;
                     if (!(nodeNames instanceof Array)) {
                         nodeNames = [nodeNames];
                     }
-                    var filteredNodeIndices = new Array();
+                    var filteredNodeIndices_1 = new Array();
                     this._traverseNodes(context, nodeIndices, function (node) {
                         if (nodeNames.indexOf(node.name) !== -1) {
-                            filteredNodeIndices.push(node.index);
+                            filteredNodeIndices_1.push(node.index);
                             return false;
                         }
                         return true;
                     }, this._rootNode);
-                    nodeIndices = filteredNodeIndices;
+                    nodeIndices = filteredNodeIndices_1;
                 }
-                for (var i = 0; i < nodeIndices.length; i++) {
-                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, nodeIndices[i]);
+                for (var _i = 0, nodeIndices_1 = nodeIndices; _i < nodeIndices_1.length; _i++) {
+                    var index = nodeIndices_1[_i];
+                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, index);
                     if (!node) {
-                        throw new Error(context + ": Failed to find node " + nodeIndices[i]);
+                        throw new Error(context + ": Failed to find node " + index);
                     }
-                    this._loadNode("#/nodes/" + nodeIndices[i], node);
+                    this._loadNode("#/nodes/" + index, node);
                 }
                 // Disable the root mesh until the asset is ready to render.
                 this._rootNode.babylonMesh.setEnabled(false);
@@ -2687,25 +2713,26 @@ var BABYLON;
                     // TODO: handle cameras
                 }
                 if (node.children) {
-                    for (var i = 0; i < node.children.length; i++) {
-                        var childNode = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, node.children[i]);
+                    for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
+                        var index = _a[_i];
+                        var childNode = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, index);
                         if (!childNode) {
-                            throw new Error(context + ": Failed to find child node " + node.children[i]);
+                            throw new Error(context + ": Failed to find child node " + index);
                         }
-                        this._loadNode("#/nodes/" + node.children[i], childNode);
+                        this._loadNode("#/nodes/" + index, childNode);
                     }
                 }
             };
             GLTFLoader.prototype._loadMesh = function (context, node, mesh) {
                 var _this = this;
                 node.babylonMesh.name = node.babylonMesh.name || mesh.name;
-                if (!mesh.primitives || mesh.primitives.length === 0) {
+                var primitives = mesh.primitives;
+                if (!primitives || primitives.length === 0) {
                     throw new Error(context + ": Primitives are missing");
                 }
                 this._createMorphTargets(context, node, mesh);
                 this._loadAllVertexDataAsync(context, mesh, function () {
                     _this._loadMorphTargets(context, node, mesh);
-                    var primitives = mesh.primitives;
                     var vertexData = new BABYLON.VertexData();
                     for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
                         var primitive = primitives_1[_i];
@@ -2718,62 +2745,68 @@ var BABYLON;
                     var verticesStart = 0;
                     var indicesStart = 0;
                     for (var index = 0; index < primitives.length; index++) {
-                        var vertexData = primitives[index].vertexData;
-                        var verticesCount = vertexData.positions.length;
-                        var indicesCount = vertexData.indices.length;
+                        var vertexData_1 = primitives[index].vertexData;
+                        var verticesCount = vertexData_1.positions.length;
+                        var indicesCount = vertexData_1.indices.length;
                         BABYLON.SubMesh.AddToMesh(index, verticesStart, verticesCount, indicesStart, indicesCount, node.babylonMesh);
                         verticesStart += verticesCount;
                         indicesStart += indicesCount;
                     }
                     ;
-                    var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, _this._babylonScene);
-                    node.babylonMesh.material = multiMaterial;
-                    var subMaterials = multiMaterial.subMaterials;
-                    for (var index = 0; index < primitives.length; index++) {
-                        var primitive = primitives[index];
-                        if (primitive.material == null) {
-                            subMaterials[index] = _this._getDefaultMaterial();
+                });
+                var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, this._babylonScene);
+                node.babylonMesh.material = multiMaterial;
+                var subMaterials = multiMaterial.subMaterials;
+                var _loop_1 = function (index) {
+                    var primitive = primitives[index];
+                    if (primitive.material == null) {
+                        subMaterials[index] = this_1._getDefaultMaterial();
+                    }
+                    else {
+                        var material_1 = GLTF2.GLTFUtils.GetArrayItem(this_1._gltf.materials, primitive.material);
+                        if (!material_1) {
+                            throw new Error(context + ": Failed to find material " + primitive.material);
                         }
-                        else {
-                            var material = GLTF2.GLTFUtils.GetArrayItem(_this._gltf.materials, primitive.material);
-                            if (!material) {
-                                throw new Error(context + ": Failed to find material " + primitive.material);
+                        this_1._loadMaterial("#/materials/" + material_1.index, material_1, function (babylonMaterial, isNew) {
+                            if (isNew && _this._parent.onMaterialLoaded) {
+                                _this._parent.onMaterialLoaded(babylonMaterial);
                             }
-                            _this._loadMaterial("#/materials/" + material.index, material, function (babylonMaterial, isNew) {
-                                if (isNew && _this._parent.onMaterialLoaded) {
-                                    _this._parent.onMaterialLoaded(babylonMaterial);
-                                }
-                                if (_this._parent.onBeforeMaterialReadyAsync) {
-                                    _this._addLoaderPendingData(material);
-                                    _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, subMaterials[index] != null, function () {
+                            if (_this._parent.onBeforeMaterialReadyAsync) {
+                                _this._addLoaderPendingData(material_1);
+                                _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, subMaterials[index] != null, function () {
+                                    _this._tryCatchOnError(function () {
                                         subMaterials[index] = babylonMaterial;
-                                        _this._removeLoaderPendingData(material);
+                                        _this._removeLoaderPendingData(material_1);
                                     });
-                                }
-                                else {
-                                    subMaterials[index] = babylonMaterial;
-                                }
-                            });
-                        }
+                                });
+                            }
+                            else {
+                                subMaterials[index] = babylonMaterial;
+                            }
+                        });
                     }
-                    ;
-                });
+                };
+                var this_1 = this;
+                for (var index = 0; index < primitives.length; index++) {
+                    _loop_1(index);
+                }
+                ;
             };
             GLTFLoader.prototype._loadAllVertexDataAsync = function (context, mesh, onSuccess) {
                 var primitives = mesh.primitives;
                 var numRemainingPrimitives = primitives.length;
-                var _loop_1 = function () {
+                var _loop_2 = function (index) {
                     var primitive = primitives[index];
-                    this_1._loadVertexDataAsync(context + "/primitive/" + index, mesh, primitive, function (vertexData) {
+                    this_2._loadVertexDataAsync(context + "/primitive/" + index, mesh, primitive, function (vertexData) {
                         primitive.vertexData = vertexData;
                         if (--numRemainingPrimitives === 0) {
                             onSuccess();
                         }
                     });
                 };
-                var this_1 = this;
+                var this_2 = this;
                 for (var index = 0; index < primitives.length; index++) {
-                    _loop_1();
+                    _loop_2(index);
                 }
             };
             GLTFLoader.prototype._loadVertexDataAsync = function (context, mesh, primitive, onSuccess) {
@@ -2788,12 +2821,12 @@ var BABYLON;
                 }
                 var vertexData = new BABYLON.VertexData();
                 var numRemainingAttributes = Object.keys(attributes).length;
-                var _loop_2 = function (attribute) {
-                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_2._gltf.accessors, attributes[attribute]);
+                var _loop_3 = function (attribute) {
+                    var accessor = GLTF2.GLTFUtils.GetArrayItem(this_3._gltf.accessors, attributes[attribute]);
                     if (!accessor) {
                         throw new Error(context + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
                     }
-                    this_2._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
+                    this_3._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
                         switch (attribute) {
                             case "NORMAL":
                                 vertexData.normals = data;
@@ -2826,7 +2859,9 @@ var BABYLON;
                         if (--numRemainingAttributes === 0) {
                             if (primitive.indices == null) {
                                 vertexData.indices = new Uint32Array(vertexData.positions.length / 3);
-                                vertexData.indices.forEach(function (v, i) { return vertexData.indices[i] = i; });
+                                for (var i = 0; i < vertexData.indices.length; i++) {
+                                    vertexData.indices[i] = i;
+                                }
                                 onSuccess(vertexData);
                             }
                             else {
@@ -2842,9 +2877,9 @@ var BABYLON;
                         }
                     });
                 };
-                var this_2 = this, accessor;
+                var this_3 = this;
                 for (var attribute in attributes) {
-                    _loop_2(attribute);
+                    _loop_3(attribute);
                 }
             };
             GLTFLoader.prototype._createMorphTargets = function (context, node, mesh) {
@@ -2877,7 +2912,7 @@ var BABYLON;
                         var vertexData = new BABYLON.VertexData();
                         for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
                             var primitive = _a[_i];
-                            vertexData.merge(primitive.targetsVertexData[index]);
+                            vertexData.merge(primitive.targetsVertexData[index], { tangentLength: 3 });
                         }
                         var target = morphTargetManager.getTarget(index);
                         target.setNormals(vertexData.normals);
@@ -2888,33 +2923,36 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadAllMorphTargetVertexDataAsync = function (context, node, mesh, onSuccess) {
                 var numRemainingTargets = mesh.primitives.length * node.babylonMesh.morphTargetManager.numTargets;
-                for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
-                    var primitive = _a[_i];
+                var _loop_4 = function (primitive) {
                     var targets = primitive.targets;
                     primitive.targetsVertexData = new Array(targets.length);
-                    var _loop_3 = function (index) {
-                        this_3._loadMorphTargetVertexDataAsync(context + "/targets/" + index, primitive.vertexData, targets[index], function (vertexData) {
+                    var _loop_5 = function (index) {
+                        this_4._loadMorphTargetVertexDataAsync(context + "/targets/" + index, primitive.vertexData, targets[index], function (vertexData) {
                             primitive.targetsVertexData[index] = vertexData;
                             if (--numRemainingTargets === 0) {
                                 onSuccess();
                             }
                         });
                     };
-                    var this_3 = this;
                     for (var index = 0; index < targets.length; index++) {
-                        _loop_3(index);
+                        _loop_5(index);
                     }
+                };
+                var this_4 = this;
+                for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
+                    var primitive = _a[_i];
+                    _loop_4(primitive);
                 }
             };
             GLTFLoader.prototype._loadMorphTargetVertexDataAsync = function (context, vertexData, attributes, onSuccess) {
                 var targetVertexData = new BABYLON.VertexData();
                 var numRemainingAttributes = Object.keys(attributes).length;
-                var _loop_4 = function (attribute) {
-                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_4._gltf.accessors, attributes[attribute]);
+                var _loop_6 = function (attribute) {
+                    var accessor = GLTF2.GLTFUtils.GetArrayItem(this_5._gltf.accessors, attributes[attribute]);
                     if (!accessor) {
                         throw new Error(context + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
                     }
-                    this_4._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
+                    this_5._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
                         // glTF stores morph target information as deltas while babylon.js expects the final data.
                         // As a result we have to add the original data to the delta to calculate the final data.
                         var values = data;
@@ -2952,9 +2990,9 @@ var BABYLON;
                         }
                     });
                 };
-                var this_4 = this, accessor;
+                var this_5 = this;
                 for (var attribute in attributes) {
-                    _loop_4(attribute);
+                    _loop_6(attribute);
                 }
             };
             GLTFLoader.prototype._loadTransform = function (node) {
@@ -2962,8 +3000,8 @@ var BABYLON;
                 var rotation = BABYLON.Quaternion.Identity();
                 var scaling = BABYLON.Vector3.One();
                 if (node.matrix) {
-                    var mat = BABYLON.Matrix.FromArray(node.matrix);
-                    mat.decompose(scaling, rotation, position);
+                    var matrix = BABYLON.Matrix.FromArray(node.matrix);
+                    matrix.decompose(scaling, rotation, position);
                 }
                 else {
                     if (node.translation)
@@ -3005,10 +3043,11 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadBones = function (context, skin, inverseBindMatrixData) {
                 var babylonBones = {};
-                for (var i = 0; i < skin.joints.length; i++) {
-                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, skin.joints[i]);
+                for (var _i = 0, _a = skin.joints; _i < _a.length; _i++) {
+                    var index = _a[_i];
+                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, index);
                     if (!node) {
-                        throw new Error(context + ": Failed to find joint " + skin.joints[i]);
+                        throw new Error(context + ": Failed to find joint " + index);
                     }
                     this._loadBone(node, skin, inverseBindMatrixData, babylonBones);
                 }
@@ -3040,10 +3079,11 @@ var BABYLON;
             };
             GLTFLoader.prototype._traverseNodes = function (context, indices, action, parentNode) {
                 if (parentNode === void 0) { parentNode = null; }
-                for (var i = 0; i < indices.length; i++) {
-                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, indices[i]);
+                for (var _i = 0, indices_1 = indices; _i < indices_1.length; _i++) {
+                    var index = indices_1[_i];
+                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, index);
                     if (!node) {
-                        throw new Error(context + ": Failed to find node " + indices[i]);
+                        throw new Error(context + ": Failed to find node " + index);
                     }
                     this._traverseNode(context, node, action, parentNode);
                 }
@@ -3176,7 +3216,7 @@ var BABYLON;
                     animation.targets = animation.targets || [];
                     if (targetPath === "influence") {
                         var morphTargetManager = targetNode.babylonMesh.morphTargetManager;
-                        for (var targetIndex = 0; targetIndex < morphTargetManager.numTargets; targetIndex++) {
+                        var _loop_7 = function (targetIndex) {
                             var morphTarget = morphTargetManager.getTarget(targetIndex);
                             var animationName = (animation.name || "anim" + animation.index) + "_" + targetIndex;
                             var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
@@ -3188,14 +3228,17 @@ var BABYLON;
                             }); }));
                             morphTarget.animations.push(babylonAnimation);
                             animation.targets.push(morphTarget);
+                        };
+                        for (var targetIndex = 0; targetIndex < morphTargetManager.numTargets; targetIndex++) {
+                            _loop_7(targetIndex);
                         }
                     }
                     else {
                         var animationName = animation.name || "anim" + animation.index;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
-                        for (var i = 0; i < targetNode.babylonAnimationTargets.length; i++) {
-                            var target = targetNode.babylonAnimationTargets[i];
+                        for (var _i = 0, _a = targetNode.babylonAnimationTargets; _i < _a.length; _i++) {
+                            var target = _a[_i];
                             target.animations.push(babylonAnimation.clone());
                             animation.targets.push(target);
                         }
@@ -3242,28 +3285,15 @@ var BABYLON;
                         this._removePendingData(buffer);
                     }
                     else {
-                        if (!GLTF2.GLTFUtils.ValidateUri(buffer.uri)) {
-                            throw new Error(context + ": Uri '" + buffer.uri + "' is invalid");
-                        }
                         buffer.loadedObservable = new BABYLON.Observable();
                         buffer.loadedObservable.add(function (buffer) {
                             onSuccess(buffer.loadedData);
                             _this._removePendingData(buffer);
                         });
-                        BABYLON.Tools.LoadFile(this._rootUrl + buffer.uri, function (data) {
-                            _this._tryCatchOnError(function () {
-                                buffer.loadedData = new Uint8Array(data);
-                                buffer.loadedObservable.notifyObservers(buffer);
-                                buffer.loadedObservable = null;
-                            });
-                        }, function (event) {
-                            _this._tryCatchOnError(function () {
-                                _this._onProgress(event);
-                            });
-                        }, this._babylonScene.database, true, function (request) {
-                            _this._tryCatchOnError(function () {
-                                throw new Error(context + ": Failed to load '" + buffer.uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""));
-                            });
+                        this._loadUri(context, buffer.uri, function (data) {
+                            buffer.loadedData = data;
+                            buffer.loadedObservable.notifyObservers(buffer);
+                            buffer.loadedObservable = null;
                         });
                     }
                 }
@@ -3278,8 +3308,9 @@ var BABYLON;
                     if (_this._disposed) {
                         return;
                     }
+                    var data;
                     try {
-                        var data = new Uint8Array(bufferData.buffer, bufferData.byteOffset + (bufferView.byteOffset || 0), bufferView.byteLength);
+                        data = new Uint8Array(bufferData.buffer, bufferData.byteOffset + (bufferView.byteOffset || 0), bufferView.byteLength);
                     }
                     catch (e) {
                         throw new Error(context + ": " + e.message);
@@ -3305,27 +3336,32 @@ var BABYLON;
                         throw new Error(context + ": Invalid type (" + accessor.type + ")");
                     }
                     var data;
-                    switch (accessor.componentType) {
-                        case GLTF2.EComponentType.BYTE:
-                            data = _this._buildArrayBuffer(Float32Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.UNSIGNED_BYTE:
-                            data = _this._buildArrayBuffer(Uint8Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.SHORT:
-                            data = _this._buildArrayBuffer(Int16Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.UNSIGNED_SHORT:
-                            data = _this._buildArrayBuffer(Uint16Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.UNSIGNED_INT:
-                            data = _this._buildArrayBuffer(Uint32Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.FLOAT:
-                            data = _this._buildArrayBuffer(Float32Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        default:
-                            throw new Error(context + ": Invalid component type (" + accessor.componentType + ")");
+                    try {
+                        switch (accessor.componentType) {
+                            case GLTF2.EComponentType.BYTE:
+                                data = _this._buildArrayBuffer(Float32Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.UNSIGNED_BYTE:
+                                data = _this._buildArrayBuffer(Uint8Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.SHORT:
+                                data = _this._buildArrayBuffer(Int16Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.UNSIGNED_SHORT:
+                                data = _this._buildArrayBuffer(Uint16Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.UNSIGNED_INT:
+                                data = _this._buildArrayBuffer(Uint32Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.FLOAT:
+                                data = _this._buildArrayBuffer(Float32Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            default:
+                                throw new Error(context + ": Invalid component type (" + accessor.componentType + ")");
+                        }
+                    }
+                    catch (e) {
+                        throw new Error(context + ": " + e);
                     }
                     onSuccess(data);
                 });
@@ -3342,30 +3378,25 @@ var BABYLON;
                 }
                 return 0;
             };
-            GLTFLoader.prototype._buildArrayBuffer = function (typedArray, context, data, byteOffset, count, numComponents, byteStride) {
-                try {
-                    var byteOffset = data.byteOffset + (byteOffset || 0);
-                    var targetLength = count * numComponents;
-                    if (byteStride == null || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
-                        return new typedArray(data.buffer, byteOffset, targetLength);
-                    }
-                    var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
-                    var sourceBuffer = new typedArray(data.buffer, byteOffset, elementStride * count);
-                    var targetBuffer = new typedArray(targetLength);
-                    var sourceIndex = 0;
-                    var targetIndex = 0;
-                    while (targetIndex < targetLength) {
-                        for (var componentIndex = 0; componentIndex < numComponents; componentIndex++) {
-                            targetBuffer[targetIndex] = sourceBuffer[sourceIndex + componentIndex];
-                            targetIndex++;
-                        }
-                        sourceIndex += elementStride;
-                    }
-                    return targetBuffer;
+            GLTFLoader.prototype._buildArrayBuffer = function (typedArray, data, byteOffset, count, numComponents, byteStride) {
+                byteOffset = data.byteOffset + (byteOffset || 0);
+                var targetLength = count * numComponents;
+                if (byteStride == null || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
+                    return new typedArray(data.buffer, byteOffset, targetLength);
                 }
-                catch (e) {
-                    throw new Error(context + ": " + e);
+                var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
+                var sourceBuffer = new typedArray(data.buffer, byteOffset, elementStride * count);
+                var targetBuffer = new typedArray(targetLength);
+                var sourceIndex = 0;
+                var targetIndex = 0;
+                while (targetIndex < targetLength) {
+                    for (var componentIndex = 0; componentIndex < numComponents; componentIndex++) {
+                        targetBuffer[targetIndex] = sourceBuffer[sourceIndex + componentIndex];
+                        targetIndex++;
+                    }
+                    sourceIndex += elementStride;
                 }
+                return targetBuffer;
             };
             GLTFLoader.prototype._addPendingData = function (data) {
                 if (!this._renderReady) {
@@ -3384,10 +3415,16 @@ var BABYLON;
             };
             GLTFLoader.prototype._addLoaderPendingData = function (data) {
                 this._loaderPendingCount++;
-                this._loaderTrackers.forEach(function (tracker) { return tracker._addPendingData(data); });
+                for (var _i = 0, _a = this._loaderTrackers; _i < _a.length; _i++) {
+                    var tracker = _a[_i];
+                    tracker._addPendingData(data);
+                }
             };
             GLTFLoader.prototype._removeLoaderPendingData = function (data) {
-                this._loaderTrackers.forEach(function (tracker) { return tracker._removePendingData(data); });
+                for (var _i = 0, _a = this._loaderTrackers; _i < _a.length; _i++) {
+                    var tracker = _a[_i];
+                    tracker._removePendingData(data);
+                }
                 if (--this._loaderPendingCount === 0) {
                     this._onComplete();
                 }
@@ -3569,12 +3606,12 @@ var BABYLON;
                     texture.dataReadyObservable.add(function (texture) {
                         babylonTexture.updateURL(texture.url);
                     });
-                    var image = GLTF2.GLTFUtils.GetArrayItem(this._gltf.images, texture.source);
-                    if (!image) {
+                    var image_1 = GLTF2.GLTFUtils.GetArrayItem(this._gltf.images, texture.source);
+                    if (!image_1) {
                         throw new Error(context + ": Failed to find source " + texture.source);
                     }
-                    this._loadImage("#/images/" + image.index, image, function (data) {
-                        texture.url = URL.createObjectURL(new Blob([data], { type: image.mimeType }));
+                    this._loadImage("#/images/" + image_1.index, image_1, function (data) {
+                        texture.url = URL.createObjectURL(new Blob([data], { type: image_1.mimeType }));
                         texture.dataReadyObservable.notifyObservers(texture);
                     });
                 }
@@ -3588,28 +3625,12 @@ var BABYLON;
                 return babylonTexture;
             };
             GLTFLoader.prototype._loadImage = function (context, image, onSuccess) {
-                var _this = this;
                 if (image.uri) {
-                    if (!GLTF2.GLTFUtils.ValidateUri(image.uri)) {
-                        throw new Error(context + ": Uri '" + image.uri + "' is invalid");
-                    }
                     if (GLTF2.GLTFUtils.IsBase64(image.uri)) {
                         onSuccess(new Uint8Array(GLTF2.GLTFUtils.DecodeBase64(image.uri)));
                     }
                     else {
-                        BABYLON.Tools.LoadFile(this._rootUrl + image.uri, function (data) {
-                            _this._tryCatchOnError(function () {
-                                onSuccess(data);
-                            });
-                        }, function (event) {
-                            _this._tryCatchOnError(function () {
-                                _this._onProgress(event);
-                            });
-                        }, this._babylonScene.database, true, function (request) {
-                            _this._tryCatchOnError(function () {
-                                throw new Error(context + ": Failed to load '" + image.uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""));
-                            });
-                        });
+                        this._loadUri(context, image.uri, onSuccess);
                     }
                 }
                 else {
@@ -3620,6 +3641,28 @@ var BABYLON;
                     this._loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView, onSuccess);
                 }
             };
+            GLTFLoader.prototype._loadUri = function (context, uri, onSuccess) {
+                var _this = this;
+                if (!GLTF2.GLTFUtils.ValidateUri(uri)) {
+                    throw new Error(context + ": Uri '" + uri + "' is invalid");
+                }
+                var request = BABYLON.Tools.LoadFile(this._rootUrl + uri, function (data) {
+                    _this._tryCatchOnError(function () {
+                        onSuccess(new Uint8Array(data));
+                    });
+                }, function (event) {
+                    _this._tryCatchOnError(function () {
+                        _this._onProgress(event);
+                    });
+                }, this._babylonScene.database, true, function (request) {
+                    _this._tryCatchOnError(function () {
+                        throw new Error(context + ": Failed to load '" + uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""));
+                    });
+                });
+                if (request) {
+                    this._requests.push(request);
+                }
+            };
             GLTFLoader.prototype._tryCatchOnError = function (handler) {
                 try {
                     handler();
@@ -3782,8 +3825,8 @@ var BABYLON;
                 if (!extensions) {
                     return false;
                 }
-                for (var i = 0; i < extensions.length; i++) {
-                    var extension = extensions[i];
+                for (var _i = 0, extensions_1 = extensions; _i < extensions_1.length; _i++) {
+                    var extension = extensions_1[_i];
                     if (extension.enabled && action(extension)) {
                         return true;
                     }
@@ -3870,7 +3913,9 @@ var BABYLON;
                             return;
                         }
                         setTimeout(function () {
-                            _this._loadNodeLOD(loader, context, nodes, index - 1, onComplete);
+                            loader._tryCatchOnError(function () {
+                                _this._loadNodeLOD(loader, context, nodes, index - 1, onComplete);
+                            });
                         }, MSFTLOD.MinimalLODDelay);
                     });
                 };
@@ -3899,7 +3944,9 @@ var BABYLON;
                         loader._executeWhenRenderReady(function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
                                 setTimeout(function () {
-                                    _this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
+                                    loader._tryCatchOnError(function () {
+                                        _this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
+                                    });
                                 }, MSFTLOD.MinimalLODDelay);
                             });
                         });

File diff suppressed because it is too large
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 238 - 191
dist/preview release/loaders/babylonjs.loaders.js

@@ -992,6 +992,12 @@ var BABYLON;
                 ".glb": { isBinary: true }
             };
         }
+        GLTFFileLoader.prototype.dispose = function () {
+            if (this._loader) {
+                this._loader.dispose();
+                this._loader = null;
+            }
+        };
         GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
             var loaderData = GLTFFileLoader._parse(data, onError);
             if (!loaderData) {
@@ -1000,11 +1006,11 @@ var BABYLON;
             if (this.onParsed) {
                 this.onParsed(loaderData);
             }
-            var loader = this._getLoader(loaderData, onError);
-            if (!loader) {
+            this._loader = this._getLoader(loaderData, onError);
+            if (!this._loader) {
                 return;
             }
-            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
             var loaderData = GLTFFileLoader._parse(data, onError);
@@ -1014,11 +1020,11 @@ var BABYLON;
             if (this.onParsed) {
                 this.onParsed(loaderData);
             }
-            var loader = this._getLoader(loaderData, onError);
-            if (!loader) {
+            this._loader = this._getLoader(loaderData, onError);
+            if (!this._loader) {
                 return;
             }
-            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            return this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
@@ -1134,18 +1140,18 @@ var BABYLON;
             // Look for BIN chunk
             var bin = null;
             while (binaryReader.getPosition() < binaryReader.getLength()) {
-                chunkLength = binaryReader.readUint32();
-                chunkFormat = binaryReader.readUint32();
-                switch (chunkFormat) {
+                var chunkLength_1 = binaryReader.readUint32();
+                var chunkFormat_1 = binaryReader.readUint32();
+                switch (chunkFormat_1) {
                     case ChunkFormat.JSON:
                         onError("Unexpected JSON chunk");
                         return null;
                     case ChunkFormat.BIN:
-                        bin = binaryReader.readUint8Array(chunkLength);
+                        bin = binaryReader.readUint8Array(chunkLength_1);
                         break;
                     default:
                         // ignore unrecognized chunkFormat
-                        binaryReader.skipBytes(chunkLength);
+                        binaryReader.skipBytes(chunkLength_1);
                         break;
                 }
             }
@@ -1178,7 +1184,7 @@ var BABYLON;
         GLTFFileLoader._decodeBufferToText = function (buffer) {
             var result = "";
             var length = buffer.byteLength;
-            for (var i = 0; i < length; ++i) {
+            for (var i = 0; i < length; i++) {
                 result += String.fromCharCode(buffer[i]);
             }
             return result;
@@ -2568,6 +2574,9 @@ var BABYLON;
                 }
                 GLTFLoader.Extensions[extension.name] = extension;
             };
+            GLTFLoader.prototype.dispose = function () {
+                // do nothing
+            };
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
@@ -3385,8 +3394,9 @@ var BABYLON;
         }());
         var GLTFLoader = /** @class */ (function () {
             function GLTFLoader(parent) {
-                this._renderReady = false;
                 this._disposed = false;
+                this._renderReady = false;
+                this._requests = new Array();
                 this._renderReadyObservable = new BABYLON.Observable();
                 // Count of pending work that needs to complete before the asset is rendered.
                 this._renderPendingCount = 0;
@@ -3409,24 +3419,37 @@ var BABYLON;
                     return;
                 }
                 this._disposed = true;
+                // Abort requests that are not complete
+                for (var _i = 0, _a = this._requests; _i < _a.length; _i++) {
+                    var request = _a[_i];
+                    if (request.readyState !== (XMLHttpRequest.DONE || 4)) {
+                        request.abort();
+                    }
+                }
                 // Revoke object urls created during load
                 if (this._gltf.textures) {
-                    this._gltf.textures.forEach(function (texture) {
+                    for (var _b = 0, _c = this._gltf.textures; _b < _c.length; _b++) {
+                        var texture = _c[_b];
                         if (texture.url) {
                             URL.revokeObjectURL(texture.url);
                         }
-                    });
+                    }
                 }
                 this._gltf = undefined;
                 this._babylonScene = undefined;
+                this._parent = undefined;
                 this._rootUrl = undefined;
                 this._defaultMaterial = undefined;
+                this._rootNode = undefined;
                 this._successCallback = undefined;
+                this._progressCallback = undefined;
                 this._errorCallback = undefined;
                 this._renderReady = false;
-                this._renderReadyObservable.clear();
+                this._requests = undefined;
+                this._renderReadyObservable = undefined;
                 this._renderPendingCount = 0;
                 this._loaderPendingCount = 0;
+                this._loaderTrackers = undefined;
             };
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
@@ -3494,9 +3517,6 @@ var BABYLON;
                 this._startAnimations();
                 this._successCallback();
                 this._renderReadyObservable.notifyObservers(this);
-                if (this._parent.onReady) {
-                    this._parent.onReady();
-                }
             };
             GLTFLoader.prototype._onComplete = function () {
                 if (this._parent.onComplete) {
@@ -3524,11 +3544,12 @@ var BABYLON;
                 var meshes = [this._rootNode.babylonMesh];
                 var nodes = this._gltf.nodes;
                 if (nodes) {
-                    nodes.forEach(function (node) {
+                    for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
+                        var node = nodes_1[_i];
                         if (node.babylonMesh) {
                             meshes.push(node.babylonMesh);
                         }
-                    });
+                    }
                 }
                 return meshes;
             };
@@ -3536,11 +3557,12 @@ var BABYLON;
                 var skeletons = new Array();
                 var skins = this._gltf.skins;
                 if (skins) {
-                    skins.forEach(function (skin) {
+                    for (var _i = 0, skins_1 = skins; _i < skins_1.length; _i++) {
+                        var skin = skins_1[_i];
                         if (skin.babylonSkeleton instanceof BABYLON.Skeleton) {
                             skeletons.push(skin.babylonSkeleton);
                         }
-                    });
+                    }
                 }
                 return skeletons;
             };
@@ -3548,15 +3570,18 @@ var BABYLON;
                 var targets = new Array();
                 var animations = this._gltf.animations;
                 if (animations) {
-                    animations.forEach(function (animation) {
+                    for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
+                        var animation = animations_1[_i];
                         targets.push.apply(targets, animation.targets);
-                    });
+                    }
                 }
                 return targets;
             };
             GLTFLoader.prototype._startAnimations = function () {
-                var _this = this;
-                this._getAnimationTargets().forEach(function (target) { return _this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true); });
+                for (var _i = 0, _a = this._getAnimationTargets(); _i < _a.length; _i++) {
+                    var target = _a[_i];
+                    this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                }
             };
             GLTFLoader.prototype._loadDefaultScene = function (nodeNames) {
                 var scene = GLTF2.GLTFUtils.GetArrayItem(this._gltf.scenes, this._gltf.scene || 0);
@@ -3593,22 +3618,23 @@ var BABYLON;
                     if (!(nodeNames instanceof Array)) {
                         nodeNames = [nodeNames];
                     }
-                    var filteredNodeIndices = new Array();
+                    var filteredNodeIndices_1 = new Array();
                     this._traverseNodes(context, nodeIndices, function (node) {
                         if (nodeNames.indexOf(node.name) !== -1) {
-                            filteredNodeIndices.push(node.index);
+                            filteredNodeIndices_1.push(node.index);
                             return false;
                         }
                         return true;
                     }, this._rootNode);
-                    nodeIndices = filteredNodeIndices;
+                    nodeIndices = filteredNodeIndices_1;
                 }
-                for (var i = 0; i < nodeIndices.length; i++) {
-                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, nodeIndices[i]);
+                for (var _i = 0, nodeIndices_1 = nodeIndices; _i < nodeIndices_1.length; _i++) {
+                    var index = nodeIndices_1[_i];
+                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, index);
                     if (!node) {
-                        throw new Error(context + ": Failed to find node " + nodeIndices[i]);
+                        throw new Error(context + ": Failed to find node " + index);
                     }
-                    this._loadNode("#/nodes/" + nodeIndices[i], node);
+                    this._loadNode("#/nodes/" + index, node);
                 }
                 // Disable the root mesh until the asset is ready to render.
                 this._rootNode.babylonMesh.setEnabled(false);
@@ -3640,25 +3666,26 @@ var BABYLON;
                     // TODO: handle cameras
                 }
                 if (node.children) {
-                    for (var i = 0; i < node.children.length; i++) {
-                        var childNode = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, node.children[i]);
+                    for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
+                        var index = _a[_i];
+                        var childNode = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, index);
                         if (!childNode) {
-                            throw new Error(context + ": Failed to find child node " + node.children[i]);
+                            throw new Error(context + ": Failed to find child node " + index);
                         }
-                        this._loadNode("#/nodes/" + node.children[i], childNode);
+                        this._loadNode("#/nodes/" + index, childNode);
                     }
                 }
             };
             GLTFLoader.prototype._loadMesh = function (context, node, mesh) {
                 var _this = this;
                 node.babylonMesh.name = node.babylonMesh.name || mesh.name;
-                if (!mesh.primitives || mesh.primitives.length === 0) {
+                var primitives = mesh.primitives;
+                if (!primitives || primitives.length === 0) {
                     throw new Error(context + ": Primitives are missing");
                 }
                 this._createMorphTargets(context, node, mesh);
                 this._loadAllVertexDataAsync(context, mesh, function () {
                     _this._loadMorphTargets(context, node, mesh);
-                    var primitives = mesh.primitives;
                     var vertexData = new BABYLON.VertexData();
                     for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
                         var primitive = primitives_1[_i];
@@ -3671,62 +3698,68 @@ var BABYLON;
                     var verticesStart = 0;
                     var indicesStart = 0;
                     for (var index = 0; index < primitives.length; index++) {
-                        var vertexData = primitives[index].vertexData;
-                        var verticesCount = vertexData.positions.length;
-                        var indicesCount = vertexData.indices.length;
+                        var vertexData_1 = primitives[index].vertexData;
+                        var verticesCount = vertexData_1.positions.length;
+                        var indicesCount = vertexData_1.indices.length;
                         BABYLON.SubMesh.AddToMesh(index, verticesStart, verticesCount, indicesStart, indicesCount, node.babylonMesh);
                         verticesStart += verticesCount;
                         indicesStart += indicesCount;
                     }
                     ;
-                    var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, _this._babylonScene);
-                    node.babylonMesh.material = multiMaterial;
-                    var subMaterials = multiMaterial.subMaterials;
-                    for (var index = 0; index < primitives.length; index++) {
-                        var primitive = primitives[index];
-                        if (primitive.material == null) {
-                            subMaterials[index] = _this._getDefaultMaterial();
+                });
+                var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, this._babylonScene);
+                node.babylonMesh.material = multiMaterial;
+                var subMaterials = multiMaterial.subMaterials;
+                var _loop_1 = function (index) {
+                    var primitive = primitives[index];
+                    if (primitive.material == null) {
+                        subMaterials[index] = this_1._getDefaultMaterial();
+                    }
+                    else {
+                        var material_1 = GLTF2.GLTFUtils.GetArrayItem(this_1._gltf.materials, primitive.material);
+                        if (!material_1) {
+                            throw new Error(context + ": Failed to find material " + primitive.material);
                         }
-                        else {
-                            var material = GLTF2.GLTFUtils.GetArrayItem(_this._gltf.materials, primitive.material);
-                            if (!material) {
-                                throw new Error(context + ": Failed to find material " + primitive.material);
+                        this_1._loadMaterial("#/materials/" + material_1.index, material_1, function (babylonMaterial, isNew) {
+                            if (isNew && _this._parent.onMaterialLoaded) {
+                                _this._parent.onMaterialLoaded(babylonMaterial);
                             }
-                            _this._loadMaterial("#/materials/" + material.index, material, function (babylonMaterial, isNew) {
-                                if (isNew && _this._parent.onMaterialLoaded) {
-                                    _this._parent.onMaterialLoaded(babylonMaterial);
-                                }
-                                if (_this._parent.onBeforeMaterialReadyAsync) {
-                                    _this._addLoaderPendingData(material);
-                                    _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, subMaterials[index] != null, function () {
+                            if (_this._parent.onBeforeMaterialReadyAsync) {
+                                _this._addLoaderPendingData(material_1);
+                                _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, node.babylonMesh, subMaterials[index] != null, function () {
+                                    _this._tryCatchOnError(function () {
                                         subMaterials[index] = babylonMaterial;
-                                        _this._removeLoaderPendingData(material);
+                                        _this._removeLoaderPendingData(material_1);
                                     });
-                                }
-                                else {
-                                    subMaterials[index] = babylonMaterial;
-                                }
-                            });
-                        }
+                                });
+                            }
+                            else {
+                                subMaterials[index] = babylonMaterial;
+                            }
+                        });
                     }
-                    ;
-                });
+                };
+                var this_1 = this;
+                for (var index = 0; index < primitives.length; index++) {
+                    _loop_1(index);
+                }
+                ;
             };
             GLTFLoader.prototype._loadAllVertexDataAsync = function (context, mesh, onSuccess) {
                 var primitives = mesh.primitives;
                 var numRemainingPrimitives = primitives.length;
-                var _loop_1 = function () {
+                var _loop_2 = function (index) {
                     var primitive = primitives[index];
-                    this_1._loadVertexDataAsync(context + "/primitive/" + index, mesh, primitive, function (vertexData) {
+                    this_2._loadVertexDataAsync(context + "/primitive/" + index, mesh, primitive, function (vertexData) {
                         primitive.vertexData = vertexData;
                         if (--numRemainingPrimitives === 0) {
                             onSuccess();
                         }
                     });
                 };
-                var this_1 = this;
+                var this_2 = this;
                 for (var index = 0; index < primitives.length; index++) {
-                    _loop_1();
+                    _loop_2(index);
                 }
             };
             GLTFLoader.prototype._loadVertexDataAsync = function (context, mesh, primitive, onSuccess) {
@@ -3741,12 +3774,12 @@ var BABYLON;
                 }
                 var vertexData = new BABYLON.VertexData();
                 var numRemainingAttributes = Object.keys(attributes).length;
-                var _loop_2 = function (attribute) {
-                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_2._gltf.accessors, attributes[attribute]);
+                var _loop_3 = function (attribute) {
+                    var accessor = GLTF2.GLTFUtils.GetArrayItem(this_3._gltf.accessors, attributes[attribute]);
                     if (!accessor) {
                         throw new Error(context + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
                     }
-                    this_2._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
+                    this_3._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
                         switch (attribute) {
                             case "NORMAL":
                                 vertexData.normals = data;
@@ -3779,7 +3812,9 @@ var BABYLON;
                         if (--numRemainingAttributes === 0) {
                             if (primitive.indices == null) {
                                 vertexData.indices = new Uint32Array(vertexData.positions.length / 3);
-                                vertexData.indices.forEach(function (v, i) { return vertexData.indices[i] = i; });
+                                for (var i = 0; i < vertexData.indices.length; i++) {
+                                    vertexData.indices[i] = i;
+                                }
                                 onSuccess(vertexData);
                             }
                             else {
@@ -3795,9 +3830,9 @@ var BABYLON;
                         }
                     });
                 };
-                var this_2 = this, accessor;
+                var this_3 = this;
                 for (var attribute in attributes) {
-                    _loop_2(attribute);
+                    _loop_3(attribute);
                 }
             };
             GLTFLoader.prototype._createMorphTargets = function (context, node, mesh) {
@@ -3830,7 +3865,7 @@ var BABYLON;
                         var vertexData = new BABYLON.VertexData();
                         for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
                             var primitive = _a[_i];
-                            vertexData.merge(primitive.targetsVertexData[index]);
+                            vertexData.merge(primitive.targetsVertexData[index], { tangentLength: 3 });
                         }
                         var target = morphTargetManager.getTarget(index);
                         target.setNormals(vertexData.normals);
@@ -3841,33 +3876,36 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadAllMorphTargetVertexDataAsync = function (context, node, mesh, onSuccess) {
                 var numRemainingTargets = mesh.primitives.length * node.babylonMesh.morphTargetManager.numTargets;
-                for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
-                    var primitive = _a[_i];
+                var _loop_4 = function (primitive) {
                     var targets = primitive.targets;
                     primitive.targetsVertexData = new Array(targets.length);
-                    var _loop_3 = function (index) {
-                        this_3._loadMorphTargetVertexDataAsync(context + "/targets/" + index, primitive.vertexData, targets[index], function (vertexData) {
+                    var _loop_5 = function (index) {
+                        this_4._loadMorphTargetVertexDataAsync(context + "/targets/" + index, primitive.vertexData, targets[index], function (vertexData) {
                             primitive.targetsVertexData[index] = vertexData;
                             if (--numRemainingTargets === 0) {
                                 onSuccess();
                             }
                         });
                     };
-                    var this_3 = this;
                     for (var index = 0; index < targets.length; index++) {
-                        _loop_3(index);
+                        _loop_5(index);
                     }
+                };
+                var this_4 = this;
+                for (var _i = 0, _a = mesh.primitives; _i < _a.length; _i++) {
+                    var primitive = _a[_i];
+                    _loop_4(primitive);
                 }
             };
             GLTFLoader.prototype._loadMorphTargetVertexDataAsync = function (context, vertexData, attributes, onSuccess) {
                 var targetVertexData = new BABYLON.VertexData();
                 var numRemainingAttributes = Object.keys(attributes).length;
-                var _loop_4 = function (attribute) {
-                    accessor = GLTF2.GLTFUtils.GetArrayItem(this_4._gltf.accessors, attributes[attribute]);
+                var _loop_6 = function (attribute) {
+                    var accessor = GLTF2.GLTFUtils.GetArrayItem(this_5._gltf.accessors, attributes[attribute]);
                     if (!accessor) {
                         throw new Error(context + ": Failed to find attribute '" + attribute + "' accessor " + attributes[attribute]);
                     }
-                    this_4._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
+                    this_5._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
                         // glTF stores morph target information as deltas while babylon.js expects the final data.
                         // As a result we have to add the original data to the delta to calculate the final data.
                         var values = data;
@@ -3905,9 +3943,9 @@ var BABYLON;
                         }
                     });
                 };
-                var this_4 = this, accessor;
+                var this_5 = this;
                 for (var attribute in attributes) {
-                    _loop_4(attribute);
+                    _loop_6(attribute);
                 }
             };
             GLTFLoader.prototype._loadTransform = function (node) {
@@ -3915,8 +3953,8 @@ var BABYLON;
                 var rotation = BABYLON.Quaternion.Identity();
                 var scaling = BABYLON.Vector3.One();
                 if (node.matrix) {
-                    var mat = BABYLON.Matrix.FromArray(node.matrix);
-                    mat.decompose(scaling, rotation, position);
+                    var matrix = BABYLON.Matrix.FromArray(node.matrix);
+                    matrix.decompose(scaling, rotation, position);
                 }
                 else {
                     if (node.translation)
@@ -3958,10 +3996,11 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadBones = function (context, skin, inverseBindMatrixData) {
                 var babylonBones = {};
-                for (var i = 0; i < skin.joints.length; i++) {
-                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, skin.joints[i]);
+                for (var _i = 0, _a = skin.joints; _i < _a.length; _i++) {
+                    var index = _a[_i];
+                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, index);
                     if (!node) {
-                        throw new Error(context + ": Failed to find joint " + skin.joints[i]);
+                        throw new Error(context + ": Failed to find joint " + index);
                     }
                     this._loadBone(node, skin, inverseBindMatrixData, babylonBones);
                 }
@@ -3993,10 +4032,11 @@ var BABYLON;
             };
             GLTFLoader.prototype._traverseNodes = function (context, indices, action, parentNode) {
                 if (parentNode === void 0) { parentNode = null; }
-                for (var i = 0; i < indices.length; i++) {
-                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, indices[i]);
+                for (var _i = 0, indices_1 = indices; _i < indices_1.length; _i++) {
+                    var index = indices_1[_i];
+                    var node = GLTF2.GLTFUtils.GetArrayItem(this._gltf.nodes, index);
                     if (!node) {
-                        throw new Error(context + ": Failed to find node " + indices[i]);
+                        throw new Error(context + ": Failed to find node " + index);
                     }
                     this._traverseNode(context, node, action, parentNode);
                 }
@@ -4129,7 +4169,7 @@ var BABYLON;
                     animation.targets = animation.targets || [];
                     if (targetPath === "influence") {
                         var morphTargetManager = targetNode.babylonMesh.morphTargetManager;
-                        for (var targetIndex = 0; targetIndex < morphTargetManager.numTargets; targetIndex++) {
+                        var _loop_7 = function (targetIndex) {
                             var morphTarget = morphTargetManager.getTarget(targetIndex);
                             var animationName = (animation.name || "anim" + animation.index) + "_" + targetIndex;
                             var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
@@ -4141,14 +4181,17 @@ var BABYLON;
                             }); }));
                             morphTarget.animations.push(babylonAnimation);
                             animation.targets.push(morphTarget);
+                        };
+                        for (var targetIndex = 0; targetIndex < morphTargetManager.numTargets; targetIndex++) {
+                            _loop_7(targetIndex);
                         }
                     }
                     else {
                         var animationName = animation.name || "anim" + animation.index;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
-                        for (var i = 0; i < targetNode.babylonAnimationTargets.length; i++) {
-                            var target = targetNode.babylonAnimationTargets[i];
+                        for (var _i = 0, _a = targetNode.babylonAnimationTargets; _i < _a.length; _i++) {
+                            var target = _a[_i];
                             target.animations.push(babylonAnimation.clone());
                             animation.targets.push(target);
                         }
@@ -4195,28 +4238,15 @@ var BABYLON;
                         this._removePendingData(buffer);
                     }
                     else {
-                        if (!GLTF2.GLTFUtils.ValidateUri(buffer.uri)) {
-                            throw new Error(context + ": Uri '" + buffer.uri + "' is invalid");
-                        }
                         buffer.loadedObservable = new BABYLON.Observable();
                         buffer.loadedObservable.add(function (buffer) {
                             onSuccess(buffer.loadedData);
                             _this._removePendingData(buffer);
                         });
-                        BABYLON.Tools.LoadFile(this._rootUrl + buffer.uri, function (data) {
-                            _this._tryCatchOnError(function () {
-                                buffer.loadedData = new Uint8Array(data);
-                                buffer.loadedObservable.notifyObservers(buffer);
-                                buffer.loadedObservable = null;
-                            });
-                        }, function (event) {
-                            _this._tryCatchOnError(function () {
-                                _this._onProgress(event);
-                            });
-                        }, this._babylonScene.database, true, function (request) {
-                            _this._tryCatchOnError(function () {
-                                throw new Error(context + ": Failed to load '" + buffer.uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""));
-                            });
+                        this._loadUri(context, buffer.uri, function (data) {
+                            buffer.loadedData = data;
+                            buffer.loadedObservable.notifyObservers(buffer);
+                            buffer.loadedObservable = null;
                         });
                     }
                 }
@@ -4231,8 +4261,9 @@ var BABYLON;
                     if (_this._disposed) {
                         return;
                     }
+                    var data;
                     try {
-                        var data = new Uint8Array(bufferData.buffer, bufferData.byteOffset + (bufferView.byteOffset || 0), bufferView.byteLength);
+                        data = new Uint8Array(bufferData.buffer, bufferData.byteOffset + (bufferView.byteOffset || 0), bufferView.byteLength);
                     }
                     catch (e) {
                         throw new Error(context + ": " + e.message);
@@ -4258,27 +4289,32 @@ var BABYLON;
                         throw new Error(context + ": Invalid type (" + accessor.type + ")");
                     }
                     var data;
-                    switch (accessor.componentType) {
-                        case GLTF2.EComponentType.BYTE:
-                            data = _this._buildArrayBuffer(Float32Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.UNSIGNED_BYTE:
-                            data = _this._buildArrayBuffer(Uint8Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.SHORT:
-                            data = _this._buildArrayBuffer(Int16Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.UNSIGNED_SHORT:
-                            data = _this._buildArrayBuffer(Uint16Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.UNSIGNED_INT:
-                            data = _this._buildArrayBuffer(Uint32Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        case GLTF2.EComponentType.FLOAT:
-                            data = _this._buildArrayBuffer(Float32Array, context, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
-                            break;
-                        default:
-                            throw new Error(context + ": Invalid component type (" + accessor.componentType + ")");
+                    try {
+                        switch (accessor.componentType) {
+                            case GLTF2.EComponentType.BYTE:
+                                data = _this._buildArrayBuffer(Float32Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.UNSIGNED_BYTE:
+                                data = _this._buildArrayBuffer(Uint8Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.SHORT:
+                                data = _this._buildArrayBuffer(Int16Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.UNSIGNED_SHORT:
+                                data = _this._buildArrayBuffer(Uint16Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.UNSIGNED_INT:
+                                data = _this._buildArrayBuffer(Uint32Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            case GLTF2.EComponentType.FLOAT:
+                                data = _this._buildArrayBuffer(Float32Array, bufferViewData, accessor.byteOffset, accessor.count, numComponents, bufferView.byteStride);
+                                break;
+                            default:
+                                throw new Error(context + ": Invalid component type (" + accessor.componentType + ")");
+                        }
+                    }
+                    catch (e) {
+                        throw new Error(context + ": " + e);
                     }
                     onSuccess(data);
                 });
@@ -4295,30 +4331,25 @@ var BABYLON;
                 }
                 return 0;
             };
-            GLTFLoader.prototype._buildArrayBuffer = function (typedArray, context, data, byteOffset, count, numComponents, byteStride) {
-                try {
-                    var byteOffset = data.byteOffset + (byteOffset || 0);
-                    var targetLength = count * numComponents;
-                    if (byteStride == null || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
-                        return new typedArray(data.buffer, byteOffset, targetLength);
-                    }
-                    var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
-                    var sourceBuffer = new typedArray(data.buffer, byteOffset, elementStride * count);
-                    var targetBuffer = new typedArray(targetLength);
-                    var sourceIndex = 0;
-                    var targetIndex = 0;
-                    while (targetIndex < targetLength) {
-                        for (var componentIndex = 0; componentIndex < numComponents; componentIndex++) {
-                            targetBuffer[targetIndex] = sourceBuffer[sourceIndex + componentIndex];
-                            targetIndex++;
-                        }
-                        sourceIndex += elementStride;
-                    }
-                    return targetBuffer;
+            GLTFLoader.prototype._buildArrayBuffer = function (typedArray, data, byteOffset, count, numComponents, byteStride) {
+                byteOffset = data.byteOffset + (byteOffset || 0);
+                var targetLength = count * numComponents;
+                if (byteStride == null || byteStride === numComponents * typedArray.BYTES_PER_ELEMENT) {
+                    return new typedArray(data.buffer, byteOffset, targetLength);
                 }
-                catch (e) {
-                    throw new Error(context + ": " + e);
+                var elementStride = byteStride / typedArray.BYTES_PER_ELEMENT;
+                var sourceBuffer = new typedArray(data.buffer, byteOffset, elementStride * count);
+                var targetBuffer = new typedArray(targetLength);
+                var sourceIndex = 0;
+                var targetIndex = 0;
+                while (targetIndex < targetLength) {
+                    for (var componentIndex = 0; componentIndex < numComponents; componentIndex++) {
+                        targetBuffer[targetIndex] = sourceBuffer[sourceIndex + componentIndex];
+                        targetIndex++;
+                    }
+                    sourceIndex += elementStride;
                 }
+                return targetBuffer;
             };
             GLTFLoader.prototype._addPendingData = function (data) {
                 if (!this._renderReady) {
@@ -4337,10 +4368,16 @@ var BABYLON;
             };
             GLTFLoader.prototype._addLoaderPendingData = function (data) {
                 this._loaderPendingCount++;
-                this._loaderTrackers.forEach(function (tracker) { return tracker._addPendingData(data); });
+                for (var _i = 0, _a = this._loaderTrackers; _i < _a.length; _i++) {
+                    var tracker = _a[_i];
+                    tracker._addPendingData(data);
+                }
             };
             GLTFLoader.prototype._removeLoaderPendingData = function (data) {
-                this._loaderTrackers.forEach(function (tracker) { return tracker._removePendingData(data); });
+                for (var _i = 0, _a = this._loaderTrackers; _i < _a.length; _i++) {
+                    var tracker = _a[_i];
+                    tracker._removePendingData(data);
+                }
                 if (--this._loaderPendingCount === 0) {
                     this._onComplete();
                 }
@@ -4522,12 +4559,12 @@ var BABYLON;
                     texture.dataReadyObservable.add(function (texture) {
                         babylonTexture.updateURL(texture.url);
                     });
-                    var image = GLTF2.GLTFUtils.GetArrayItem(this._gltf.images, texture.source);
-                    if (!image) {
+                    var image_1 = GLTF2.GLTFUtils.GetArrayItem(this._gltf.images, texture.source);
+                    if (!image_1) {
                         throw new Error(context + ": Failed to find source " + texture.source);
                     }
-                    this._loadImage("#/images/" + image.index, image, function (data) {
-                        texture.url = URL.createObjectURL(new Blob([data], { type: image.mimeType }));
+                    this._loadImage("#/images/" + image_1.index, image_1, function (data) {
+                        texture.url = URL.createObjectURL(new Blob([data], { type: image_1.mimeType }));
                         texture.dataReadyObservable.notifyObservers(texture);
                     });
                 }
@@ -4541,28 +4578,12 @@ var BABYLON;
                 return babylonTexture;
             };
             GLTFLoader.prototype._loadImage = function (context, image, onSuccess) {
-                var _this = this;
                 if (image.uri) {
-                    if (!GLTF2.GLTFUtils.ValidateUri(image.uri)) {
-                        throw new Error(context + ": Uri '" + image.uri + "' is invalid");
-                    }
                     if (GLTF2.GLTFUtils.IsBase64(image.uri)) {
                         onSuccess(new Uint8Array(GLTF2.GLTFUtils.DecodeBase64(image.uri)));
                     }
                     else {
-                        BABYLON.Tools.LoadFile(this._rootUrl + image.uri, function (data) {
-                            _this._tryCatchOnError(function () {
-                                onSuccess(data);
-                            });
-                        }, function (event) {
-                            _this._tryCatchOnError(function () {
-                                _this._onProgress(event);
-                            });
-                        }, this._babylonScene.database, true, function (request) {
-                            _this._tryCatchOnError(function () {
-                                throw new Error(context + ": Failed to load '" + image.uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""));
-                            });
-                        });
+                        this._loadUri(context, image.uri, onSuccess);
                     }
                 }
                 else {
@@ -4573,6 +4594,28 @@ var BABYLON;
                     this._loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView, onSuccess);
                 }
             };
+            GLTFLoader.prototype._loadUri = function (context, uri, onSuccess) {
+                var _this = this;
+                if (!GLTF2.GLTFUtils.ValidateUri(uri)) {
+                    throw new Error(context + ": Uri '" + uri + "' is invalid");
+                }
+                var request = BABYLON.Tools.LoadFile(this._rootUrl + uri, function (data) {
+                    _this._tryCatchOnError(function () {
+                        onSuccess(new Uint8Array(data));
+                    });
+                }, function (event) {
+                    _this._tryCatchOnError(function () {
+                        _this._onProgress(event);
+                    });
+                }, this._babylonScene.database, true, function (request) {
+                    _this._tryCatchOnError(function () {
+                        throw new Error(context + ": Failed to load '" + uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""));
+                    });
+                });
+                if (request) {
+                    this._requests.push(request);
+                }
+            };
             GLTFLoader.prototype._tryCatchOnError = function (handler) {
                 try {
                     handler();
@@ -4735,8 +4778,8 @@ var BABYLON;
                 if (!extensions) {
                     return false;
                 }
-                for (var i = 0; i < extensions.length; i++) {
-                    var extension = extensions[i];
+                for (var _i = 0, extensions_1 = extensions; _i < extensions_1.length; _i++) {
+                    var extension = extensions_1[_i];
                     if (extension.enabled && action(extension)) {
                         return true;
                     }
@@ -4814,7 +4857,9 @@ var BABYLON;
                             return;
                         }
                         setTimeout(function () {
-                            _this._loadNodeLOD(loader, context, nodes, index - 1, onComplete);
+                            loader._tryCatchOnError(function () {
+                                _this._loadNodeLOD(loader, context, nodes, index - 1, onComplete);
+                            });
                         }, MSFTLOD.MinimalLODDelay);
                     });
                 };
@@ -4843,7 +4888,9 @@ var BABYLON;
                         loader._executeWhenRenderReady(function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
                                 setTimeout(function () {
-                                    _this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
+                                    loader._tryCatchOnError(function () {
+                                        _this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
+                                    });
                                 }, MSFTLOD.MinimalLODDelay);
                             });
                         });

File diff suppressed because it is too large
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


+ 11 - 12
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -107,11 +107,11 @@ declare module BABYLON {
         json: Object;
         bin: ArrayBufferView;
     }
-    interface IGLTFLoader {
+    interface IGLTFLoader extends IDisposable {
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
     }
-    class GLTFFileLoader implements ISceneLoaderPluginAsync {
+    class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
         onParsed: (data: IGLTFLoaderData) => void;
@@ -125,19 +125,15 @@ declare module BABYLON {
          */
         onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
         /**
-         * Raised when the visible components (geometry, materials, textures, etc.) are first ready to be rendered.
-         * For assets with LODs, raised when the first LOD is complete.
-         * For assets without LODs, raised when the model is complete just before onComplete.
-         */
-        onReady: () => void;
-        /**
          * Raised when the asset is completely loaded, just before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete just after onReady.
+         * For assets without LODs, raised when the model is complete just after onSuccess.
          */
         onComplete: () => void;
+        private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         canDirectLoad(data: string): boolean;
@@ -545,6 +541,7 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
+        dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): boolean;
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         private _loadShadersAsync(gltfRuntime, onload);
@@ -949,9 +946,10 @@ declare module BABYLON.GLTF2 {
 
 
 declare module BABYLON.GLTF2 {
-    class GLTFLoader implements IGLTFLoader, IDisposable {
+    class GLTFLoader implements IGLTFLoader {
         _gltf: IGLTF;
         _babylonScene: Scene;
+        private _disposed;
         private _parent;
         private _rootUrl;
         private _defaultMaterial;
@@ -960,7 +958,7 @@ declare module BABYLON.GLTF2 {
         private _progressCallback;
         private _errorCallback;
         private _renderReady;
-        private _disposed;
+        private _requests;
         private _renderReadyObservable;
         private _renderPendingCount;
         private _loaderPendingCount;
@@ -1008,7 +1006,7 @@ declare module BABYLON.GLTF2 {
         private _loadBufferViewAsync(context, bufferView, onSuccess);
         private _loadAccessorAsync(context, accessor, onSuccess);
         private _getNumComponentsOfType(type);
-        private _buildArrayBuffer<T>(typedArray, context, data, byteOffset, count, numComponents, byteStride);
+        private _buildArrayBuffer<T>(typedArray, data, byteOffset, count, numComponents, byteStride);
         _addPendingData(data: any): void;
         _removePendingData(data: any): void;
         _addLoaderPendingData(data: any): void;
@@ -1022,6 +1020,7 @@ declare module BABYLON.GLTF2 {
         _loadMaterialAlphaProperties(context: string, material: IGLTFMaterial, colorFactor: number[]): void;
         _loadTexture(context: string, texture: IGLTFTexture, coordinatesIndex: number): Texture;
         private _loadImage(context, image, onSuccess);
+        _loadUri(context: string, uri: string, onSuccess: (data: ArrayBufferView) => void): void;
         _tryCatchOnError(handler: () => void): void;
     }
 }

+ 1 - 1
dist/preview release/loaders/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "3.1.0-alpha3.4",
+    "version": "3.1.0-alpha3.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/loaders/readme.md

@@ -36,7 +36,7 @@ Afterwards it can be imported to the project using:
 
 ```
 import * as BABYLON from 'babylonjs';
-import from 'babylonjs-loaders';
+import 'babylonjs-loaders';
 ```
 
 This will extend Babylon's namespace with the loaders available.

+ 1 - 0
dist/preview release/materialsLibrary/babylon.customMaterial.d.ts

@@ -68,6 +68,7 @@ declare module BABYLON {
         CONTRAST: boolean;
         COLORCURVES: boolean;
         COLORGRADING: boolean;
+        COLORGRADING3D: boolean;
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DBGRMAP: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;

+ 1 - 0
dist/preview release/materialsLibrary/babylon.customMaterial.js

@@ -89,6 +89,7 @@ var BABYLON;
             _this.CONTRAST = false;
             _this.COLORCURVES = false;
             _this.COLORGRADING = false;
+            _this.COLORGRADING3D = false;
             _this.SAMPLER3DGREENDEPTH = false;
             _this.SAMPLER3DBGRMAP = false;
             _this.IMAGEPROCESSINGPOSTPROCESS = false;

File diff suppressed because it is too large
+ 2 - 2
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


+ 1 - 0
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -4018,6 +4018,7 @@ var BABYLON;
             _this.CONTRAST = false;
             _this.COLORCURVES = false;
             _this.COLORGRADING = false;
+            _this.COLORGRADING3D = false;
             _this.SAMPLER3DGREENDEPTH = false;
             _this.SAMPLER3DBGRMAP = false;
             _this.IMAGEPROCESSINGPOSTPROCESS = false;

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.min.js


+ 1 - 0
dist/preview release/materialsLibrary/babylonjs.materials.module.d.ts

@@ -571,6 +571,7 @@ declare module BABYLON {
         CONTRAST: boolean;
         COLORCURVES: boolean;
         COLORGRADING: boolean;
+        COLORGRADING3D: boolean;
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DBGRMAP: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;

+ 1 - 1
dist/preview release/materialsLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.1.0-alpha3.4",
+    "version": "3.1.0-alpha3.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/materialsLibrary/readme.md

@@ -36,7 +36,7 @@ Afterwards it can be imported to the project using:
 
 ```
 import * as BABYLON from 'babylonjs';
-import from 'babylonjs-materials';
+import 'babylonjs-materials';
 ```
 
 This will extend Babylon's namespace with the materials available:

+ 1 - 1
dist/preview release/postProcessesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.1.0-alpha3.4",
+    "version": "3.1.0-alpha3.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/postProcessesLibrary/readme.md

@@ -36,7 +36,7 @@ Afterwards it can be imported to the project using:
 
 ```
 import * as BABYLON from 'babylonjs';
-import from 'babylonjs-post-process';
+import 'babylonjs-post-process';
 ```
 
 This will extend Babylon's namespace with the post processes available:

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.1.0-alpha3.4",
+    "version": "3.1.0-alpha3.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/readme.md

@@ -36,7 +36,7 @@ Afterwards it can be imported to the project using:
 
 ```
 import * as BABYLON from 'babylonjs';
-import from 'babylonjs-procedural-textures';
+import 'babylonjs-procedural-textures';
 ```
 
 This will extend Babylon's namespace with the procedural textures available:

+ 4 - 2
dist/preview release/what's new.md

@@ -16,10 +16,11 @@
 - Added support for `material.separateCullingPass`. [Doc here](http://doc.babylonjs.com/tutorials/transparency_and_how_meshes_are_rendered#things-to-do-and-not-to-do) ([sebavan](https://github.com/sebavan))
 - Added support for Windows Motion Controllers ([Lewis Weaver](https://github.com/leweaver))
 - Added support for Particle animation in ParticleSystem. [Doc here](http://doc.babylonjs.com/tutorials/particles#particle-animation) ([Ibraheem Osama](https://github.com/IbraheemOsama))
-- More robust TypeScript code with *noImplicitAny*, *noImplicitThis* and *noImplicitReturns* compiler options ([deltakosh](https://github.com/deltakosh))
-- Introduced `NullEngine` which can be used to use Babylon.js in headless mode. [Doc here](http://doc.babylonjs.com/generals/nullengine) ([deltakosh](https://github.com/deltakosh)) 
+- More robust TypeScript code with *strictNullChecks*, *noImplicitAny*, *noImplicitThis* and *noImplicitReturns* compiler options ([deltakosh](https://github.com/deltakosh))
+- Introduced `NullEngine` which can be used to use Babylon.js in headless mode. [Doc here](http://doc.babylonjs.com/generals/nullengine) ([deltakosh](https://github.com/deltakosh))
 
 ## Updates
+- Support for non uniform scaling. Normals are now correctly computed ([deltakosh](https://github.com/deltakosh))
 - Added `MultiObserver`. [Doc here](http://doc.babylonjs.com/overviews/observables#multiobserver) ([deltakosh](https://github.com/deltakosh))
 - Added `shadowGenerator.addShadowCaster` and `shadowGenerator.removeShadowCaster` helper functions ([deltakosh](https://github.com/deltakosh))
 - Several inspector improvements ([temechon](https://github.com/temechon))
@@ -43,3 +44,4 @@
 
 ## Breaking changes
 - `Gamepads` was removed in favor of `scene.gamepadManager`
+- `DynamicFloatArray`, `MapTexture` and `RectPakingMap` were removed because there were not used anymore

+ 0 - 3
inspector/src/properties.ts

@@ -75,9 +75,6 @@ module INSPECTOR {
             ],
             format: (tex: BABYLON.Texture) => { return tex.name }
         },
-        'MapTexture': {
-            type: BABYLON.MapTexture
-        },
         'RenderTargetTexture': {
             type: BABYLON.RenderTargetTexture
         },

+ 1 - 8
inspector/src/tabs/TextureTab.ts

@@ -85,14 +85,7 @@ module INSPECTOR {
                 imgs.push(Helpers.CreateElement('img', 'texture-image', this._imagePanel) as HTMLImageElement);
             }
             
-            if (texture instanceof BABYLON.MapTexture) {
-                // instance of Map texture
-                texture.bindTextureForPosSize(new BABYLON.Vector2(0, 0), new BABYLON.Size(texture.getSize().width, texture.getSize().height), false);
-                BABYLON.Tools.DumpFramebuffer(texture.getSize().width, texture.getSize().height, this._inspector.scene.getEngine(), (data) => img.src = data);
-                texture.unbindTexture();
-
-            }
-            else if (texture instanceof BABYLON.RenderTargetTexture) {
+            if (texture instanceof BABYLON.RenderTargetTexture) {
                 // RenderTarget textures
                 let scene = this._inspector.scene;
                 let engine = scene.getEngine();

+ 4 - 0
loaders/src/glTF/1.0/babylon.glTFLoader.ts

@@ -1512,6 +1512,10 @@ module BABYLON.GLTF1 {
             GLTFLoader.Extensions[extension.name] = extension;
         }
 
+        public dispose(): void {
+            // do nothing
+        }
+
         public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): boolean {
             scene.useRightHandedSystem = true;
 

+ 3 - 3
loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts

@@ -24,14 +24,14 @@ module BABYLON.GLTF2.Extensions {
         }
 
         private _loadSpecularGlossinessProperties(loader: GLTFLoader, context: string, material: IGLTFMaterial, properties: IKHRMaterialsPbrSpecularGlossiness): void {
-            var babylonMaterial = material.babylonMaterial as PBRMaterial;
+            const babylonMaterial = material.babylonMaterial as PBRMaterial;
 
             babylonMaterial.albedoColor = properties.diffuseFactor ? Color3.FromArray(properties.diffuseFactor) : new Color3(1, 1, 1);
             babylonMaterial.reflectivityColor = properties.specularFactor ? Color3.FromArray(properties.specularFactor) : new Color3(1, 1, 1);
             babylonMaterial.microSurface = properties.glossinessFactor == null ? 1 : properties.glossinessFactor;
 
             if (properties.diffuseTexture) {
-                var texture = GLTFUtils.GetArrayItem(loader._gltf.textures, properties.diffuseTexture.index);
+                const texture = GLTFUtils.GetArrayItem(loader._gltf.textures, properties.diffuseTexture.index);
                 if (!texture) {
                     throw new Error(context + ": Failed to find diffuse texture " + properties.diffuseTexture.index);
                 }
@@ -40,7 +40,7 @@ module BABYLON.GLTF2.Extensions {
             }
 
             if (properties.specularGlossinessTexture) {
-                var texture = GLTFUtils.GetArrayItem(loader._gltf.textures, properties.specularGlossinessTexture.index);
+                const texture = GLTFUtils.GetArrayItem(loader._gltf.textures, properties.specularGlossinessTexture.index);
                 if (!texture) {
                     throw new Error(context + ": Failed to find diffuse texture " + properties.specularGlossinessTexture.index);
                 }

+ 11 - 7
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -18,8 +18,8 @@ module BABYLON.GLTF2.Extensions {
 
         protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean {
             return this._loadExtension<IMSFTLOD>(node, (extension, onComplete) => {
-                for (var i = extension.ids.length - 1; i >= 0; i--) {
-                    var lodNode = GLTFUtils.GetArrayItem(loader._gltf.nodes, extension.ids[i]);
+                for (let i = extension.ids.length - 1; i >= 0; i--) {
+                    const lodNode = GLTFUtils.GetArrayItem(loader._gltf.nodes, extension.ids[i]);
                     if (!lodNode) {
                         throw new Error(context + ": Failed to find node " + extension.ids[i]);
                     }
@@ -34,7 +34,7 @@ module BABYLON.GLTF2.Extensions {
 
         protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean {
             return this._loadExtension<IMSFTLOD>(node, (extension, onComplete) => {
-                var nodes = [node.index, ...extension.ids].map(index => loader._gltf.nodes[index]);
+                const nodes = [node.index, ...extension.ids].map(index => loader._gltf.nodes[index]);
 
                 loader._addLoaderPendingData(node);
                 this._loadNodeLOD(loader, context, nodes, nodes.length - 1, () => {
@@ -49,7 +49,7 @@ module BABYLON.GLTF2.Extensions {
                 loader._loadNode(context, nodes[index]);
             }, () => {
                 if (index !== nodes.length - 1) {
-                    var previousNode = nodes[index + 1];
+                    const previousNode = nodes[index + 1];
                     previousNode.babylonMesh.setEnabled(false);
                 }
 
@@ -59,14 +59,16 @@ module BABYLON.GLTF2.Extensions {
                 }
 
                 setTimeout(() => {
-                    this._loadNodeLOD(loader, context, nodes, index - 1, onComplete);
+                    loader._tryCatchOnError(() => {
+                        this._loadNodeLOD(loader, context, nodes, index - 1, onComplete);
+                    });
                 }, MSFTLOD.MinimalLODDelay);
             });
         }
 
         protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean {
             return this._loadExtension<IMSFTLOD>(material, (extension, onComplete) => {
-                var materials = [material.index, ...extension.ids].map(index => loader._gltf.materials[index]);
+                const materials = [material.index, ...extension.ids].map(index => loader._gltf.materials[index]);
 
                 loader._addLoaderPendingData(material);
                 this._loadMaterialLOD(loader, context, materials, materials.length - 1, assign, () => {
@@ -91,7 +93,9 @@ module BABYLON.GLTF2.Extensions {
                 loader._executeWhenRenderReady(() => {
                     BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), () => {
                         setTimeout(() => {
-                            this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
+                            loader._tryCatchOnError(() => {
+                                this._loadMaterialLOD(loader, context, materials, index - 1, assign, onComplete);
+                            });
                         }, MSFTLOD.MinimalLODDelay);
                     });
                 });

File diff suppressed because it is too large
+ 284 - 268
loaders/src/glTF/2.0/babylon.glTFLoader.ts


+ 3 - 4
loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts

@@ -17,7 +17,7 @@ module BABYLON.GLTF2 {
                 return false;
             }
 
-            var extension = property.extensions[this.name] as T;
+            const extension = property.extensions[this.name] as T;
             if (!extension) {
                 return false;
             }
@@ -52,13 +52,12 @@ module BABYLON.GLTF2 {
         }
 
         private static _ApplyExtensions(action: (extension: GLTFLoaderExtension) => boolean) {
-            var extensions = GLTFLoaderExtension._Extensions;
+            const extensions = GLTFLoaderExtension._Extensions;
             if (!extensions) {
                 return false;
             }
 
-            for (var i = 0; i < extensions.length; i++) {
-                var extension = extensions[i];
+            for (const extension of extensions) {
                 if (extension.enabled && action(extension)) {
                     return true;
                 }

+ 5 - 5
loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts

@@ -18,11 +18,11 @@ module BABYLON.GLTF2 {
         * @param uri: the uri to decode
         */
         public static DecodeBase64(uri: string): ArrayBuffer {
-            var decodedString = atob(uri.split(",")[1]);
-            var bufferLength = decodedString.length;
-            var bufferView = new Uint8Array(new ArrayBuffer(bufferLength));
+            const decodedString = atob(uri.split(",")[1]);
+            const bufferLength = decodedString.length;
+            const bufferView = new Uint8Array(new ArrayBuffer(bufferLength));
 
-            for (var i = 0; i < bufferLength; i++) {
+            for (let i = 0; i < bufferLength; i++) {
                 bufferView[i] = decodedString.charCodeAt(i);
             }
 
@@ -35,7 +35,7 @@ module BABYLON.GLTF2 {
 
         public static AssignIndices(array: Array<{index?: number}>): void {
             if (array) {
-                for (var index = 0; index < array.length; index++) {
+                for (let index = 0; index < array.length; index++) {
                     array[index].index = index;
                 }
             }

+ 47 - 45
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -18,12 +18,12 @@ module BABYLON {
         bin: ArrayBufferView;
     }
 
-    export interface IGLTFLoader {
+    export interface IGLTFLoader extends IDisposable {
         importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
     }
 
-    export class GLTFFileLoader implements ISceneLoaderPluginAsync {
+    export class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync {
         public static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         public static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
 
@@ -45,19 +45,14 @@ module BABYLON {
         public onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
 
         /**
-         * Raised when the visible components (geometry, materials, textures, etc.) are first ready to be rendered.
-         * For assets with LODs, raised when the first LOD is complete.
-         * For assets without LODs, raised when the model is complete just before onComplete.
-         */
-        public onReady: () => void;
-
-        /**
          * Raised when the asset is completely loaded, just before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
-         * For assets without LODs, raised when the model is complete just after onReady.
+         * For assets without LODs, raised when the model is complete just after onSuccess.
          */
         public onComplete: () => void;
 
+        private _loader: IGLTFLoader;
+
         public name = "gltf";
 
         public extensions: ISceneLoaderPluginExtensions = {
@@ -65,8 +60,15 @@ module BABYLON {
             ".glb": { isBinary: true }
         };
 
+        public dispose(): void {
+            if (this._loader) {
+                this._loader.dispose();
+                this._loader = null;
+            }
+        }
+
         public importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void {
-            var loaderData = GLTFFileLoader._parse(data, onError);
+            const loaderData = GLTFFileLoader._parse(data, onError);
             if (!loaderData) {
                 return;
             }
@@ -75,16 +77,16 @@ module BABYLON {
                 this.onParsed(loaderData);
             }
 
-            var loader = this._getLoader(loaderData, onError);
-            if (!loader) {
+            this._loader = this._getLoader(loaderData, onError);
+            if (!this._loader) {
                 return;
             }
 
-            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         }
 
         public loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void {
-            var loaderData = GLTFFileLoader._parse(data, onError);
+            const loaderData = GLTFFileLoader._parse(data, onError);
             if (!loaderData) {
                 return;
             }
@@ -93,12 +95,12 @@ module BABYLON {
                 this.onParsed(loaderData);
             }
 
-            var loader = this._getLoader(loaderData, onError);
-            if (!loader) {
+            this._loader = this._getLoader(loaderData, onError);
+            if (!this._loader) {
                 return;
             }
 
-            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            return this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         }
 
         public canDirectLoad(data: string): boolean {
@@ -125,16 +127,16 @@ module BABYLON {
         private _getLoader(loaderData: IGLTFLoaderData, onError: (message: string) => void): IGLTFLoader {
             const loaderVersion = { major: 2, minor: 0 };
 
-            var asset = (<any>loaderData.json).asset || {};
+            const asset = (<any>loaderData.json).asset || {};
 
-            var version = GLTFFileLoader._parseVersion(asset.version);
+            const version = GLTFFileLoader._parseVersion(asset.version);
             if (!version) {
                 onError("Invalid version: " + asset.version);
                 return null;
             }
 
             if (asset.minVersion !== undefined) {
-                var minVersion = GLTFFileLoader._parseVersion(asset.minVersion);
+                const minVersion = GLTFFileLoader._parseVersion(asset.minVersion);
                 if (!minVersion) {
                     onError("Invalid minimum version: " + asset.minVersion);
                     return null;
@@ -146,12 +148,12 @@ module BABYLON {
                 }
             }
 
-            var createLoaders: { [key: number]: (parent: GLTFFileLoader) => IGLTFLoader } = {
+            const createLoaders: { [key: number]: (parent: GLTFFileLoader) => IGLTFLoader } = {
                 1: GLTFFileLoader.CreateGLTFLoaderV1,
                 2: GLTFFileLoader.CreateGLTFLoaderV2
             };
 
-            var createLoader = createLoaders[version.major];
+            const createLoader = createLoaders[version.major];
             if (!createLoader) {
                 onError("Unsupported version: " + asset.version);
                 return null;
@@ -165,15 +167,15 @@ module BABYLON {
                 Magic: 0x46546C67
             };
 
-            var binaryReader = new BinaryReader(data);
+            const binaryReader = new BinaryReader(data);
 
-            var magic = binaryReader.readUint32();
+            const magic = binaryReader.readUint32();
             if (magic !== Binary.Magic) {
                 onError("Unexpected magic: " + magic);
                 return null;
             }
 
-            var version = binaryReader.readUint32();
+            const version = binaryReader.readUint32();
             switch (version) {
                 case 1: return GLTFFileLoader._parseV1(binaryReader, onError);
                 case 2: return GLTFFileLoader._parseV2(binaryReader, onError);
@@ -188,16 +190,16 @@ module BABYLON {
                 JSON: 0
             };
 
-            var length = binaryReader.readUint32();
+            const length = binaryReader.readUint32();
             if (length != binaryReader.getLength()) {
                 onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
                 return null;
             }
 
-            var contentLength = binaryReader.readUint32();
-            var contentFormat = binaryReader.readUint32();
+            const contentLength = binaryReader.readUint32();
+            const contentFormat = binaryReader.readUint32();
 
-            var content: Object;
+            let content: Object;
             switch (contentFormat) {
                 case ContentFormat.JSON:
                     content = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(contentLength)));
@@ -207,8 +209,8 @@ module BABYLON {
                     return null;
             }
 
-            var bytesRemaining = binaryReader.getLength() - binaryReader.getPosition();
-            var body = binaryReader.readUint8Array(bytesRemaining);
+            const bytesRemaining = binaryReader.getLength() - binaryReader.getPosition();
+            const body = binaryReader.readUint8Array(bytesRemaining);
 
             return {
                 json: content,
@@ -222,26 +224,26 @@ module BABYLON {
                 BIN: 0x004E4942
             };
 
-            var length = binaryReader.readUint32();
+            const length = binaryReader.readUint32();
             if (length !== binaryReader.getLength()) {
                 onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
                 return null;
             }
 
             // JSON chunk
-            var chunkLength = binaryReader.readUint32();
-            var chunkFormat = binaryReader.readUint32();
+            const chunkLength = binaryReader.readUint32();
+            const chunkFormat = binaryReader.readUint32();
             if (chunkFormat !== ChunkFormat.JSON) {
                 onError("First chunk format is not JSON");
                 return null;
             }
-            var json = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(chunkLength)));
+            const json = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(chunkLength)));
 
             // Look for BIN chunk
-            var bin: Uint8Array = null;
+            let bin: Uint8Array = null;
             while (binaryReader.getPosition() < binaryReader.getLength()) {
-                chunkLength = binaryReader.readUint32();
-                chunkFormat = binaryReader.readUint32();
+                const chunkLength = binaryReader.readUint32();
+                const chunkFormat = binaryReader.readUint32();
                 switch (chunkFormat) {
                     case ChunkFormat.JSON:
                         onError("Unexpected JSON chunk");
@@ -263,7 +265,7 @@ module BABYLON {
         }
 
         private static _parseVersion(version: string): { major: number, minor: number } {
-            var match = (version + "").match(/^(\d+)\.(\d+)$/);
+            const match = (version + "").match(/^(\d+)\.(\d+)$/);
             if (!match) {
                 return null;
             }
@@ -283,10 +285,10 @@ module BABYLON {
         }
 
         private static _decodeBufferToText(buffer: Uint8Array): string {
-            var result = "";
-            var length = buffer.byteLength;
+            let result = "";
+            const length = buffer.byteLength;
 
-            for (var i = 0; i < length; ++i) {
+            for (let i = 0; i < length; i++) {
                 result += String.fromCharCode(buffer[i]);
             }
 
@@ -314,13 +316,13 @@ module BABYLON {
         }
 
         public readUint32(): number {
-            var value = this._dataView.getUint32(this._byteOffset, true);
+            const value = this._dataView.getUint32(this._byteOffset, true);
             this._byteOffset += 4;
             return value;
         }
 
         public readUint8Array(length: number): Uint8Array {
-            var value = new Uint8Array(this._arrayBuffer, this._byteOffset, length);
+            const value = new Uint8Array(this._arrayBuffer, this._byteOffset, length);
             this._byteOffset += length;
             return value;
         }

+ 2 - 2
localDev/index.html

@@ -65,8 +65,8 @@
 			.require(indexjs)
 			.load(function() {
 				if (BABYLON.Engine.isSupported()) {
-					engine = new BABYLON.Engine(canvas, true, { stencil: true });					
-					BABYLONDEVTOOLS.Loader.debugShortcut(engine);			
+					engine = new BABYLON.Engine(canvas, true, { stencil: true, disableWebGL2Support: false });
+					BABYLONDEVTOOLS.Loader.debugShortcut(engine);
 
 					// call the scene creation from the js.
 					var scene = createScene();

+ 1 - 0
materialsLibrary/src/custom/babylon.customMaterial.ts

@@ -72,6 +72,7 @@ module BABYLON {
         public CONTRAST = false;
         public COLORCURVES = false;
         public COLORGRADING = false;
+        public COLORGRADING3D = false;
         public SAMPLER3DGREENDEPTH = false;
         public SAMPLER3DBGRMAP = false;
         public IMAGEPROCESSINGPOSTPROCESS = false;

+ 1 - 1
package.json

@@ -8,7 +8,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "3.1.0-alpha3.5",
+    "version": "3.1.0-alpha3.6",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 3 - 3
src/Actions/babylon.action.ts

@@ -5,7 +5,7 @@
 
         private _nextActiveAction: Action;
         private _child: Action;
-        private _condition: Condition;
+        private _condition?: Condition;
         private _triggerParameter: any;
 
         public onBeforeExecuteObservable = new Observable<Action>();
@@ -31,7 +31,7 @@
             return this._triggerParameter;
         }
 
-        public _executeCurrent(evt: ActionEvent): void {
+        public _executeCurrent(evt?: ActionEvent): void {
             if (this._nextActiveAction._condition) {
                 var condition = this._nextActiveAction._condition;
                 var currentRenderId = this._actionManager.getScene().getRenderId();
@@ -59,7 +59,7 @@
             this.skipToNextActiveAction();
         }
 
-        public execute(evt: ActionEvent): void {
+        public execute(evt?: ActionEvent): void {
 
         }
 

+ 22 - 20
src/Actions/babylon.actionManager.ts

@@ -11,7 +11,7 @@
          * @param meshUnderPointer The mesh that is currently pointed at (can be null)
          * @param sourceEvent the original (browser) event that triggered the ActionEvent
          */
-        constructor(public source: any, public pointerX: number, public pointerY: number, public meshUnderPointer: AbstractMesh, public sourceEvent?: any, public additionalData?: any) {
+        constructor(public source: any, public pointerX: number, public pointerY: number, public meshUnderPointer: Nullable<AbstractMesh>, public sourceEvent?: any, public additionalData?: any) {
 
         }
 
@@ -295,7 +295,7 @@
          * @param {BABYLON.Action} action - the action to be registered
          * @return {BABYLON.Action} the action amended (prepared) after registration
          */
-        public registerAction(action: Action): Action {
+        public registerAction(action: Action): Nullable<Action> {
             if (action.trigger === ActionManager.OnEveryFrameTrigger) {
                 if (this.getScene().actionManager !== this) {
                     Tools.Warn("OnEveryFrameTrigger can only be used with scene.actionManager");
@@ -323,27 +323,29 @@
          * @param {number} trigger - the trigger to process
          * @param evt {BABYLON.ActionEvent} the event details to be processed
          */
-        public processTrigger(trigger: number, evt: ActionEvent): void {
+        public processTrigger(trigger: number, evt?: ActionEvent): void {
             for (var index = 0; index < this.actions.length; index++) {
                 var action = this.actions[index];
 
                 if (action.trigger === trigger) {
-                    if (trigger === ActionManager.OnKeyUpTrigger
-                        || trigger === ActionManager.OnKeyDownTrigger) {
-                        var parameter = action.getTriggerParameter();
+                    if (evt) {
+                        if (trigger === ActionManager.OnKeyUpTrigger
+                            || trigger === ActionManager.OnKeyDownTrigger) {
+                            var parameter = action.getTriggerParameter();
 
-                        if (parameter && parameter !== evt.sourceEvent.keyCode) {
-                            if (!parameter.toLowerCase) {
-                                continue;
-                            }
-                            var lowerCase = parameter.toLowerCase();
-
-                            if (lowerCase !== evt.sourceEvent.key) {
-                                var unicode = evt.sourceEvent.charCode ? evt.sourceEvent.charCode : evt.sourceEvent.keyCode;
-                                var actualkey = String.fromCharCode(unicode).toLowerCase();
-                                if (actualkey !== lowerCase) {
+                            if (parameter && parameter !== evt.sourceEvent.keyCode) {
+                                if (!parameter.toLowerCase) {
                                     continue;
                                 }
+                                var lowerCase = parameter.toLowerCase();
+
+                                if (lowerCase !== evt.sourceEvent.key) {
+                                    var unicode = evt.sourceEvent.charCode ? evt.sourceEvent.charCode : evt.sourceEvent.keyCode;
+                                    var actualkey = String.fromCharCode(unicode).toLowerCase();
+                                    if (actualkey !== lowerCase) {
+                                        continue;
+                                    }
+                                }
                             }
                         }
                     }
@@ -413,7 +415,7 @@
             return root;
         }
 
-        public static Parse(parsedActions: any, object: AbstractMesh, scene: Scene) {
+        public static Parse(parsedActions: any, object: Nullable<AbstractMesh>, scene: Scene) {
             var actionManager = new BABYLON.ActionManager(scene);
             if (object === null)
                 scene.actionManager = actionManager;
@@ -427,7 +429,7 @@
                 return newInstance;
             };
 
-            var parseParameter = (name: string, value: string, target: any, propertyPath: string): any => {
+            var parseParameter = (name: string, value: string, target: any, propertyPath: Nullable<string>): any => {
                 if (propertyPath === null) {
                     // String, boolean or float
                     var floatValue = parseFloat(value);
@@ -474,13 +476,13 @@
             };
 
             // traverse graph per trigger
-            var traverse = (parsedAction: any, trigger: any, condition: Condition, action: Action, combineArray: Array<Action> = null) => {
+            var traverse = (parsedAction: any, trigger: any, condition: Nullable<Condition>, action: Nullable<Action>, combineArray: Nullable<Array<Action>> = null) => {
                 if (parsedAction.detached)
                     return;
 
                 var parameters = new Array<any>();
                 var target: any = null;
-                var propertyPath: string = null;
+                var propertyPath: Nullable<string> = null;
                 var combine = parsedAction.combine && parsedAction.combine.length > 0;
 
                 // Parameters

+ 8 - 5
src/Animations/babylon.animatable.ts

@@ -1,7 +1,7 @@
 module BABYLON {
     export class Animatable {
-        private _localDelayOffset: number = null;
-        private _pausedDelay: number = null;
+        private _localDelayOffset: Nullable<number> = null;
+        private _pausedDelay: Nullable<number> = null;
         private _runtimeAnimations = new Array<RuntimeAnimation>();
         private _paused = false;
         private _scene: Scene;
@@ -22,7 +22,7 @@
             this._speedRatio = value;
         }
 
-        constructor(scene: Scene, public target: any, public fromFrame: number = 0, public toFrame: number = 100, public loopAnimation: boolean = false, speedRatio: number = 1.0, public onAnimationEnd?: () => void, animations?: any) {
+        constructor(scene: Scene, public target: any, public fromFrame: number = 0, public toFrame: number = 100, public loopAnimation: boolean = false, speedRatio: number = 1.0, public onAnimationEnd?: Nullable<() => void>, animations?: any) {
             if (animations) {
                 this.appendAnimations(target, animations);
             }
@@ -45,7 +45,7 @@
             }
         }
 
-        public getAnimationByTargetProperty(property: string): Animation {
+        public getAnimationByTargetProperty(property: string): Nullable<Animation> {
             var runtimeAnimations = this._runtimeAnimations;
 
             for (var index = 0; index < runtimeAnimations.length; index++) {
@@ -57,7 +57,7 @@
             return null;
         }
 
-        public getRuntimeAnimationByTargetProperty(property: string): RuntimeAnimation {
+        public getRuntimeAnimationByTargetProperty(property: string): Nullable<RuntimeAnimation> {
             var runtimeAnimations = this._runtimeAnimations;
 
             for (var index = 0; index < runtimeAnimations.length; index++) {
@@ -105,6 +105,9 @@
                 var currentFrame = runtimeAnimations[0].currentFrame;
                 var adjustTime = frame - currentFrame;
                 var delay = adjustTime * 1000 / fps;
+                if (this._localDelayOffset === null) {
+                    this._localDelayOffset = 0;
+                }
                 this._localDelayOffset -= delay;
             }
 

+ 41 - 20
src/Animations/babylon.animation.ts

@@ -96,10 +96,10 @@
 
         public blendingSpeed = 0.01;
 
-        private _ranges: { [name: string]: AnimationRange; } = {};
+        private _ranges: { [name: string]: Nullable<AnimationRange> } = {};
 
         static _PrepareAnimation(name: string, targetProperty: string, framePerSecond: number, totalFrame: number,
-            from: any, to: any, loopMode?: number, easingFunction?: EasingFunction): Animation {
+            from: any, to: any, loopMode?: number, easingFunction?: EasingFunction): Nullable<Animation> {
             var dataType = undefined;
 
             if (!isNaN(parseFloat(from)) && isFinite(from)) {
@@ -153,19 +153,27 @@
 
         public static CreateAndStartAnimation(name: string, node: Node, targetProperty: string,
             framePerSecond: number, totalFrame: number,
-            from: any, to: any, loopMode?: number, easingFunction?: EasingFunction, onAnimationEnd?: () => void) {
+            from: any, to: any, loopMode?: number, easingFunction?: EasingFunction, onAnimationEnd?: () => void): Nullable<Animatable> {
 
             var animation = Animation._PrepareAnimation(name, targetProperty, framePerSecond, totalFrame, from, to, loopMode, easingFunction);
 
+            if (!animation) {
+                return null;
+            }
+
             return node.getScene().beginDirectAnimation(node, [animation], 0, totalFrame, (animation.loopMode === 1), 1.0, onAnimationEnd);
         }
 
         public static CreateMergeAndStartAnimation(name: string, node: Node, targetProperty: string,
             framePerSecond: number, totalFrame: number,
-            from: any, to: any, loopMode?: number, easingFunction?: EasingFunction, onAnimationEnd?: () => void) {
+            from: any, to: any, loopMode?: number, easingFunction?: EasingFunction, onAnimationEnd?: () => void): Nullable<Animatable> {
 
             var animation = Animation._PrepareAnimation(name, targetProperty, framePerSecond, totalFrame, from, to, loopMode, easingFunction);
 
+            if (!animation) {
+                return null;
+            }
+
             node.animations.push(animation);
 
             return node.getScene().beginAnimation(node, 0, totalFrame, (animation.loopMode === 1), 1.0, onAnimationEnd);
@@ -182,7 +190,7 @@
 		 * @param duration The duration of the animation, in milliseconds
 		 * @param onAnimationEnd Call back trigger at the end of the animation.
 		 */
-		public static TransitionTo(property: string, targetValue: any, host: any, scene: Scene, frameRate: number, transition: Animation, duration: number,	onAnimationEnd: () => void = null): Animatable {
+		public static TransitionTo(property: string, targetValue: any, host: any, scene: Scene, frameRate: number, transition: Animation, duration: number,	onAnimationEnd: Nullable<() => void> = null): Nullable<Animatable> {
 
 			if (duration <= 0) {
 				host[property] = targetValue;
@@ -293,23 +301,27 @@
         }
 
         public deleteRange(name: string, deleteFrames = true): void {
-            if (this._ranges[name]) {
-                if (deleteFrames) {
-                    var from = this._ranges[name].from;
-                    var to = this._ranges[name].to;
- 
-                    // this loop MUST go high to low for multiple splices to work
-                    for (var key = this._keys.length - 1; key >= 0; key--) {
-                        if (this._keys[key].frame >= from && this._keys[key].frame <= to) {
-                            this._keys.splice(key, 1);
-                        }
+            let range = this._ranges[name];
+            if (!range) {
+                return;
+
+            }
+            if (deleteFrames) {
+                var from = range.from;
+                var to = range.to;
+
+                // this loop MUST go high to low for multiple splices to work
+                for (var key = this._keys.length - 1; key >= 0; key--) {
+                    if (this._keys[key].frame >= from && this._keys[key].frame <= to) {
+                        this._keys.splice(key, 1);
                     }
                 }
-                this._ranges[name] = undefined; // said much faster than 'delete this._range[name]' 
             }
+            this._ranges[name] = null; // said much faster than 'delete this._range[name]' 
+        
         }
 
-        public getRange(name: string): AnimationRange {
+        public getRange(name: string): Nullable<AnimationRange> {
             return this._ranges[name];
         }
 
@@ -394,7 +406,11 @@
             if (this._ranges) {
                 clone._ranges = {};
                 for (var name in this._ranges) {
-                    clone._ranges[name] = this._ranges[name].clone();
+                    let range = this._ranges[name];
+                    if (!range) {
+                        continue;
+                    }
+                    clone._ranges[name] = range.clone();
                 }
             }
 
@@ -442,10 +458,15 @@
 
             serializationObject.ranges = [];
             for (var name in this._ranges) {
+                let source  =this._ranges[name];
+
+                if (!source) {
+                    continue;
+                }
                 var range: any = {};
                 range.name = name;
-                range.from = this._ranges[name].from;
-                range.to = this._ranges[name].to;
+                range.from = source.from;
+                range.to = source.to;
                 serializationObject.ranges.push(range);
             }
 

+ 1 - 1
src/Animations/babylon.runtimeAnimation.ts

@@ -50,7 +50,7 @@
             return value;
         }      
         
-        private _interpolate(currentFrame: number, repeatCount: number, loopMode: number, offsetValue?: any, highLimitValue?: any) {
+        private _interpolate(currentFrame: number, repeatCount: number, loopMode?: number, offsetValue?: any, highLimitValue?: any) {
             if (loopMode === Animation.ANIMATIONLOOPMODE_CONSTANT && repeatCount > 0) {
                 return highLimitValue.clone ? highLimitValue.clone() : highLimitValue;
             }

+ 0 - 0
src/Audio/babylon.analyser.ts


Some files were not shown because too many files changed in this diff